linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] [RFC/RFT] Implement sparse keymap library
@ 2009-12-02  9:24 Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 1/8] Input: add generic support for sparse keymaps Dmitry Torokhov
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Hi,

It seems that almost everty platform driver out there copied the keymap
implementation from wistron button driver... That's a lot of duplicated code
and I think it is high time we split it into a library module that can be
shared between all these drivers.

The code is only compile-tested since I don't have boxes that would run these
drivers.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/8] Input: add generic support for sparse keymaps
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 2/8] Input: wistron_btns - switch to using sparse keymap library Dmitry Torokhov
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

More and more devices choose to reimplement support for sparse keymaps
first introduced by wistron driver. Move it into a library module so it
can be easily used by interested parties.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 Documentation/DocBook/device-drivers.tmpl |    3 
 drivers/input/Kconfig                     |   28 +++-
 drivers/input/Makefile                    |    1 
 drivers/input/input-polldev.c             |   14 ++
 drivers/input/sparse-keymap.c             |  186 +++++++++++++++++++++++++++++
 include/linux/input/sparse-keymap.h       |   52 ++++++++
 6 files changed, 272 insertions(+), 12 deletions(-)
 create mode 100644 drivers/input/sparse-keymap.c
 create mode 100644 include/linux/input/sparse-keymap.h

diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index e994d1d..0d6c9ee 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -306,6 +306,9 @@ X!Idrivers/video/console/fonts.c
      <sect1><title>Matrix keyboars/keypads</title>
 !Iinclude/linux/input/matrix_keypad.h
      </sect1>
+     <sect1><title>Sparse keymap support</title>
+!Iinclude/linux/input/sparse-keymap.h
+!Edrivers/input/sparse-keymap.c
   </chapter>
 
   <chapter id="spi">
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index cd50c00..50af91e 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -8,7 +8,7 @@ menu "Input device support"
 config INPUT
 	tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
 	default y
-	---help---
+	help
 	  Say Y here if you have any input device (mouse, keyboard, tablet,
 	  joystick, steering wheel ...) connected to your system and want
 	  it to be available to applications. This includes standard PS/2
@@ -27,8 +27,7 @@ if INPUT
 
 config INPUT_FF_MEMLESS
 	tristate "Support for memoryless force-feedback devices"
-	default n
-	---help---
+	help
 	  Say Y here if you have memoryless force-feedback input device
 	  such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
 	  Power 2, or similar. You will also need to enable hardware-specific
@@ -52,12 +51,25 @@ config INPUT_POLLDEV
 	  To compile this driver as a module, choose M here: the
 	  module will be called input-polldev.
 
+config INPUT_SPARSEKMAP
+	tristate "Sparse keymap support library"
+	help
+	  Say Y here if you are using a driver for an input
+	  device that uses sparse keymap. This option is only
+	  useful for out-of-tree drivers since in-tree drivers
+	  select it automatically.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sparse-keymap.
+
 comment "Userland interfaces"
 
 config INPUT_MOUSEDEV
 	tristate "Mouse interface" if EMBEDDED
 	default y
-	---help---
+	help
 	  Say Y here if you want your mouse to be accessible as char devices
 	  13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
 	  emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
@@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX
 	bool "Provide legacy /dev/psaux device"
 	default y
 	depends on INPUT_MOUSEDEV
-	---help---
+	help
 	  Say Y here if you want your mouse also be accessible as char device
 	  10:1 - /dev/psaux. The data available through /dev/psaux is exactly
 	  the same as the data from /dev/input/mice.
@@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y
 
 config INPUT_JOYDEV
 	tristate "Joystick interface"
-	---help---
+	help
 	  Say Y here if you want your joystick or gamepad to be
 	  accessible as char device 13:0+ - /dev/input/jsX device.
 
@@ -125,7 +137,7 @@ config INPUT_EVDEV
 
 config INPUT_EVBUG
 	tristate "Event debugging"
-	---help---
+	help
 	  Say Y here if you have a problem with the input subsystem and
 	  want all events (keypresses, mouse movements), to be output to
 	  the system log. While this is useful for debugging, it's also
@@ -140,7 +152,7 @@ config INPUT_EVBUG
 config INPUT_APMPOWER
 	tristate "Input Power Event -> APM Bridge" if EMBEDDED
 	depends on INPUT && APM_EMULATION
-	---help---
+	help
 	  Say Y here if you want suspend key events to trigger a user
 	  requested suspend through APM. This is useful on embedded
 	  systems where such behaviour is desired without userspace
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 4c9c745..7ad212d 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -9,6 +9,7 @@ input-core-objs := input.o input-compat.o ff-core.o
 
 obj-$(CONFIG_INPUT_FF_MEMLESS)	+= ff-memless.o
 obj-$(CONFIG_INPUT_POLLDEV)	+= input-polldev.o
+obj-$(CONFIG_INPUT_SPARSEKMAP)	+= sparse-keymap.o
 
 obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 6a2eb39..aa6713b 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device);
  * @dev: device to free
  *
  * The function frees memory allocated for polling device and drops
- * reference to the associated input device (if present).
+ * reference to the associated input device.
  */
 void input_free_polled_device(struct input_polled_dev *dev)
 {
@@ -258,6 +258,15 @@ int input_register_polled_device(struct input_polled_dev *dev)
 		return error;
 	}
 
+	/*
+	 * Take extra reference to the underlying input device so
+	 * that it survives call to input_unregister_polled_device()
+	 * and is deleted only after input_free_polled_device()
+	 * has been invoked. This is needed to ease task of freeing
+	 * sparse keymaps.
+	 */
+	input_get_device(input);
+
 	return 0;
 }
 EXPORT_SYMBOL(input_register_polled_device);
@@ -269,8 +278,6 @@ EXPORT_SYMBOL(input_register_polled_device);
  * The function unregisters previously registered polled input
  * device from input layer. Polling is stopped and device is
  * ready to be freed with call to input_free_polled_device().
- * Callers should not attempt to access dev->input pointer
- * after calling this function.
  */
 void input_unregister_polled_device(struct input_polled_dev *dev)
 {
@@ -278,7 +285,6 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
 			   &input_polldev_attribute_group);
 
 	input_unregister_device(dev->input);
-	dev->input = NULL;
 }
 EXPORT_SYMBOL(input_unregister_polled_device);
 
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
new file mode 100644
index 0000000..cb769f6
--- /dev/null
+++ b/drivers/input/sparse-keymap.c
@@ -0,0 +1,186 @@
+/*
+ * Generic support for sparse keymaps
+ *
+ * Copyright (c) 2009 Dmitry Torokhov
+ *
+ * Derived from wistron button driver:
+ * 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("Generic support for sparse keymaps");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
+
+/**
+ * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
+ * @dev: Input device using sparse keymap
+ * @code: Scan code
+ *
+ * This function is used to perform &struct key_entry lookup in an
+ * input device using sparse keymap.
+ */
+struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
+						    unsigned int code)
+{
+	struct key_entry *key;
+
+	for (key = dev->keycode; key->type != KE_END; key++)
+		if (code == key->code)
+			return key;
+
+	return NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
+
+/**
+ * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
+ * @dev: Input device using sparse keymap
+ * @keycode: Key code
+ *
+ * This function is used to perform &struct key_entry lookup in an
+ * input device using sparse keymap.
+ */
+struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
+						   unsigned int keycode)
+{
+	struct key_entry *key;
+
+	for (key = dev->keycode; key->type != KE_END; key++)
+		if (key->type == KE_KEY && keycode == key->keycode)
+			return key;
+
+	return NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
+
+static int sparse_keymap_getkeycode(struct input_dev *dev,
+				    int scancode, int *keycode)
+{
+	const struct key_entry *key =
+			sparse_keymap_entry_from_scancode(dev, scancode);
+
+	if (key && key->type == KE_KEY) {
+		*keycode = key->keycode;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int sparse_keymap_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 = sparse_keymap_entry_from_scancode(dev, scancode);
+	if (key && key->type == KE_KEY) {
+		old_keycode = key->keycode;
+		key->keycode = keycode;
+		set_bit(keycode, dev->keybit);
+		if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
+			clear_bit(old_keycode, dev->keybit);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(sparse_keymap_setkeycode);
+
+/**
+ * sparse_keymap_setup - set up sparse keymap for an input device
+ * @dev: Input device
+ * @keymap: Keymap in form of array of &key_entry structures ending
+ *	with %KE_END type entry
+ * @setup: Function that can be used to adjust keymap entries
+ *	depending on device's deeds, may be %NULL
+ *
+ * The function calculates size and allocates copy of the original
+ * keymap after which sets up input device event bits appropriately.
+ * Before detsroying input device allocated keymap should be freed
+ * with a call to sparse_keymap_free().
+ */
+int sparse_keymap_setup(struct input_dev *dev,
+			const struct key_entry *keymap,
+			int (*setup)(struct input_dev *, struct key_entry *))
+{
+	size_t map_size = 1; /* to account for the last KE_END entry */
+	const struct key_entry *e;
+	struct key_entry *map, *entry;
+	int i;
+	int error;
+
+	for (e = keymap; e->type != KE_END; e++)
+		map_size++;
+
+	map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	memcpy(map, keymap, map_size * sizeof (struct key_entry));
+
+	for (i = 0; i < map_size; i++) {
+		entry = &map[i];
+
+		if (setup) {
+			error = setup(dev, entry);
+			if (error)
+				goto err_out;
+		}
+
+		switch (entry->type) {
+		case KE_KEY:
+			__set_bit(EV_KEY, dev->evbit);
+			__set_bit(entry->keycode, dev->keybit);
+			break;
+
+		case KE_SW:
+			__set_bit(EV_SW, dev->evbit);
+			__set_bit(entry->sw.code, dev->swbit);
+			break;
+		}
+	}
+
+	dev->keycode = map;
+	dev->keycodemax = map_size;
+	dev->getkeycode = sparse_keymap_getkeycode;
+	dev->setkeycode = sparse_keymap_setkeycode;
+
+	return 0;
+
+ err_out:
+	kfree(keymap);
+	return error;
+
+}
+EXPORT_SYMBOL(sparse_keymap_setup);
+
+/**
+ * sparse_keymap_free - free memory allocated for sparse keymap
+ * @dev: Input device using sparse keymap
+ *
+ * This function is used to free memory allocated by sparse keymap
+ * in an input device that was set up by sparse_keymap_setup().
+ */
+void sparse_keymap_free(struct input_dev *dev)
+{
+	kfree(dev->keycode);
+	dev->keycode = NULL;
+	dev->keycodemax = 0;
+	dev->getkeycode = NULL;
+	dev->setkeycode = NULL;
+}
+EXPORT_SYMBOL(sparse_keymap_free);
diff --git a/include/linux/input/sparse-keymap.h b/include/linux/input/sparse-keymap.h
new file mode 100644
index 0000000..fae67b1
--- /dev/null
+++ b/include/linux/input/sparse-keymap.h
@@ -0,0 +1,52 @@
+#ifndef _SPARSE_KEYMAP_H
+#define _SPARSE_KEYMAP_H
+
+/*
+ * Copyright (c) 2009 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#define KE_END		0	/* Indicates end of keymap */
+#define KE_KEY		1	/* Ordinary key/button */
+#define KE_SW		2	/* Switch */
+#define KE_LAST		KE_SW
+
+/**
+ * struct key_entry - keymap entry for use in sparse keymap
+ * @type: Type of the key entry (KE_KEY, KE_SW, KE_END); drivers are
+ *	allowed to extend the list with their own private definitions.
+ * @code: Device-specific data identifying the button/switch
+ * @keycode: KEY_* code assigned to a key/button
+ * @sw.code: SW_* code assigned to a switch
+ * @sw.value: Value that should be sent in an input even when switch
+ *	is toggled.
+ *
+ * This structure defines an entry in a sparse keymap used by some
+ * input devices for which traditional table-based approach is not
+ * suitable.
+ */
+struct key_entry {
+	int type;		/* See KE_* above */
+	u32 code;
+	union {
+		u16 keycode;		/* For KE_KEY */
+		struct {		/* For KE_SW */
+			u8 code;
+			u8 value;
+		} sw;
+	};
+};
+
+struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
+						    unsigned int code);
+struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
+						   unsigned int code);
+int sparse_keymap_setup(struct input_dev *dev,
+			const struct key_entry *keymap,
+			int (*setup)(struct input_dev *, struct key_entry *));
+void sparse_keymap_free(struct input_dev *dev);
+
+#endif /* _SPARSE_KEYMAP_H */


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/8] Input: wistron_btns - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 1/8] Input: add generic support for sparse keymaps Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 3/8] Input: dell-wmi " Dmitry Torokhov
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

The keymap manipulation code was split into a library module,
so let's make us of it.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/input/misc/Kconfig        |    1 
 drivers/input/misc/wistron_btns.c |  150 ++++++++++---------------------------
 2 files changed, 42 insertions(+), 109 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a9bb254..d25ecbb 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -80,6 +80,7 @@ config INPUT_WISTRON_BTNS
 	tristate "x86 Wistron laptop button interface"
 	depends on X86 && !X86_64
 	select INPUT_POLLDEV
+	select INPUT_SPARSEKMAP
 	select NEW_LEDS
 	select LEDS_CLASS
 	select CHECK_SIGNATURE
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 00eb9d6..6a36ffa 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -21,6 +21,7 @@
 #include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/input-polldev.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -224,19 +225,8 @@ static void bios_set_state(u8 subsys, int enable)
 
 /* Hardware database */
 
-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_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
+#define KE_WIFI		(KE_LAST + 1)
+#define KE_BLUETOOTH	(KE_LAST + 2)
 
 #define FE_MAIL_LED 0x01
 #define FE_WIFI_LED 0x02
@@ -1128,31 +1118,10 @@ static inline void wistron_led_resume(void)
 		led_classdev_resume(&wistron_wifi_led);
 }
 
-static struct key_entry *wistron_get_entry_by_scancode(int code)
-{
-	struct key_entry *key;
-
-	for (key = keymap; key->type != KE_END; key++)
-		if (code == key->code)
-			return key;
-
-	return NULL;
-}
-
-static struct key_entry *wistron_get_entry_by_keycode(int keycode)
-{
-	struct key_entry *key;
-
-	for (key = keymap; key->type != KE_END; key++)
-		if (key->type == KE_KEY && keycode == key->keycode)
-			return key;
-
-	return NULL;
-}
-
 static void handle_key(u8 code)
 {
-	const struct key_entry *key = wistron_get_entry_by_scancode(code);
+	const struct key_entry *key =
+		sparse_keymap_entry_from_scancode(wistron_idev->input, code);
 
 	if (key) {
 		switch (key->type) {
@@ -1220,42 +1189,39 @@ static void wistron_poll(struct input_polled_dev *dev)
 		dev->poll_interval = POLL_INTERVAL_DEFAULT;
 }
 
-static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int __devinit wistron_setup_keymap(struct input_dev *dev,
+					  struct key_entry *entry)
 {
-	const struct key_entry *key = wistron_get_entry_by_scancode(scancode);
-
-	if (key && key->type == KE_KEY) {
-		*keycode = key->keycode;
-		return 0;
-	}
+	switch (entry->type) {
 
-	return -EINVAL;
-}
+	/* if wifi or bluetooth are not available, create normal keys */
+	case KE_WIFI:
+		if (!have_wifi) {
+			entry->type = KE_KEY;
+			entry->keycode = KEY_WLAN;
+		}
+		break;
 
-static int wistron_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 = wistron_get_entry_by_scancode(scancode);
-	if (key && key->type == KE_KEY) {
-		old_keycode = key->keycode;
-		key->keycode = keycode;
-		set_bit(keycode, dev->keybit);
-		if (!wistron_get_entry_by_keycode(old_keycode))
-			clear_bit(old_keycode, dev->keybit);
-		return 0;
+	case KE_BLUETOOTH:
+		if (!have_bluetooth) {
+			entry->type = KE_KEY;
+			entry->keycode = KEY_BLUETOOTH;
+		}
+		break;
+
+	case KE_END:
+		if (entry->code & FE_UNTESTED)
+			printk(KERN_WARNING "Untested laptop multimedia keys, "
+				"please report success or failure to "
+				"eric.piel@tremplin-utc.net\n");
+		break;
 	}
 
-	return -EINVAL;
+	return 0;
 }
 
 static int __devinit setup_input_dev(void)
 {
-	struct key_entry *key;
 	struct input_dev *input_dev;
 	int error;
 
@@ -1273,56 +1239,21 @@ static int __devinit setup_input_dev(void)
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->dev.parent = &wistron_device->dev;
 
-	input_dev->getkeycode = wistron_getkeycode;
-	input_dev->setkeycode = wistron_setkeycode;
-
-	for (key = keymap; key->type != KE_END; key++) {
-		switch (key->type) {
-			case KE_KEY:
-				set_bit(EV_KEY, input_dev->evbit);
-				set_bit(key->keycode, input_dev->keybit);
-				break;
-
-			case KE_SW:
-				set_bit(EV_SW, input_dev->evbit);
-				set_bit(key->sw.code, input_dev->swbit);
-				break;
-
-			/* if wifi or bluetooth are not available, create normal keys */
-			case KE_WIFI:
-				if (!have_wifi) {
-					key->type = KE_KEY;
-					key->keycode = KEY_WLAN;
-					key--;
-				}
-				break;
-
-			case KE_BLUETOOTH:
-				if (!have_bluetooth) {
-					key->type = KE_KEY;
-					key->keycode = KEY_BLUETOOTH;
-					key--;
-				}
-				break;
-
-			default:
-				break;
-		}
-	}
-
-	/* reads information flags on KE_END */
-	if (key->code & FE_UNTESTED)
-		printk(KERN_WARNING "Untested laptop multimedia keys, "
-			"please report success or failure to eric.piel"
-			"@tremplin-utc.net\n");
+	error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap);
+	if (error)
+		goto err_free_dev;
 
 	error = input_register_polled_device(wistron_idev);
-	if (error) {
-		input_free_polled_device(wistron_idev);
-		return error;
-	}
+	if (error)
+		goto err_free_keymap;
 
 	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(input_dev);
+ err_free_dev:
+	input_free_polled_device(wistron_idev);
+	return error;
 }
 
 /* Driver core */
@@ -1371,6 +1302,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
 {
 	wistron_led_remove();
 	input_unregister_polled_device(wistron_idev);
+	sparse_keymap_free(wistron_idev->input);
 	input_free_polled_device(wistron_idev);
 	bios_detach();
 


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/8] Input: dell-wmi - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 1/8] Input: add generic support for sparse keymaps Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 2/8] Input: wistron_btns - switch to using sparse keymap library Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 4/8] Input: hp-wmi " Dmitry Torokhov
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig    |    1 
 drivers/platform/x86/dell-wmi.c |  186 +++++++++++++--------------------------
 2 files changed, 61 insertions(+), 126 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 55ca39d..1f10bf4 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -88,6 +88,7 @@ config DELL_WMI
 	tristate "Dell WMI extras"
 	depends on ACPI_WMI
 	depends on INPUT
+	select INPUT_SPARSEKMAP
 	---help---
 	  Say Y here if you want to support WMI-based hotkeys on Dell laptops.
 
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 0f900cc..5f4a0e6 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/acpi.h>
 #include <linux/string.h>
@@ -40,13 +41,7 @@ MODULE_LICENSE("GPL");
 
 MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
 
-struct key_entry {
-	char type;		/* See KE_* below */
-	u16 code;
-	u16 keycode;
-};
-
-enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
+#define KE_IGNORE	(KE_LAST + 1)
 
 /*
  * Certain keys are flagged as KE_IGNORE. All of these are either
@@ -54,105 +49,50 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
  * via the keyboard controller so should not be sent again.
  */
 
-static struct key_entry dell_wmi_keymap[] = {
-	{KE_KEY, 0xe045, KEY_PROG1},
-	{KE_KEY, 0xe009, KEY_EJECTCD},
+static const struct key_entry dell_wmi_keymap[] = {
+	{KE_KEY, 0xe045, {KEY_PROG1}},
+	{KE_KEY, 0xe009, {KEY_EJECTCD}},
 
 	/* These also contain the brightness level at offset 6 */
-	{KE_KEY, 0xe006, KEY_BRIGHTNESSUP},
-	{KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN},
+	{KE_KEY, 0xe006, {KEY_BRIGHTNESSUP}},
+	{KE_KEY, 0xe005, {KEY_BRIGHTNESSDOWN}},
 
 	/* Battery health status button */
-	{KE_KEY, 0xe007, KEY_BATTERY},
+	{KE_KEY, 0xe007, {KEY_BATTERY}},
 
 	/* This is actually for all radios. Although physically a
 	 * switch, the notification does not provide an indication of
 	 * state and so it should be reported as a key */
-	{KE_KEY, 0xe008, KEY_WLAN},
+	{KE_KEY, 0xe008, {KEY_WLAN}},
 
 	/* The next device is at offset 6, the active devices are at
 	   offset 8 and the attached devices at offset 10 */
-	{KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE},
+	{KE_KEY, 0xe00b, {KEY_DISPLAYTOGGLE}},
 
-	{KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
+	{KE_IGNORE, 0xe00c, {KEY_KBDILLUMTOGGLE}},
 
 	/* BIOS error detected */
-	{KE_IGNORE, 0xe00d, KEY_RESERVED},
+	{KE_IGNORE, 0xe00d, {KEY_RESERVED}},
 
 	/* Wifi Catcher */
-	{KE_KEY, 0xe011, KEY_PROG2},
+	{KE_KEY, 0xe011, {KEY_PROG2}},
 
 	/* Ambient light sensor toggle */
-	{KE_IGNORE, 0xe013, KEY_RESERVED},
-
-	{KE_IGNORE, 0xe020, KEY_MUTE},
-	{KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN},
-	{KE_IGNORE, 0xe030, KEY_VOLUMEUP},
-	{KE_IGNORE, 0xe033, KEY_KBDILLUMUP},
-	{KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN},
-	{KE_IGNORE, 0xe03a, KEY_CAPSLOCK},
-	{KE_IGNORE, 0xe045, KEY_NUMLOCK},
-	{KE_IGNORE, 0xe046, KEY_SCROLLLOCK},
+	{KE_IGNORE, 0xe013, {KEY_RESERVED}},
+
+	{KE_IGNORE, 0xe020, {KEY_MUTE}},
+	{KE_IGNORE, 0xe02e, {KEY_VOLUMEDOWN}},
+	{KE_IGNORE, 0xe030, {KEY_VOLUMEUP}},
+	{KE_IGNORE, 0xe033, {KEY_KBDILLUMUP}},
+	{KE_IGNORE, 0xe034, {KEY_KBDILLUMDOWN}},
+	{KE_IGNORE, 0xe03a, {KEY_CAPSLOCK}},
+	{KE_IGNORE, 0xe045, {KEY_NUMLOCK}},
+	{KE_IGNORE, 0xe046, {KEY_SCROLLLOCK}},
 	{KE_END, 0}
 };
 
 static struct input_dev *dell_wmi_input_dev;
 
-static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
-{
-	struct key_entry *key;
-
-	for (key = dell_wmi_keymap; key->type != KE_END; key++)
-		if (code == key->code)
-			return key;
-
-	return NULL;
-}
-
-static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
-{
-	struct key_entry *key;
-
-	for (key = dell_wmi_keymap; key->type != KE_END; key++)
-		if (key->type == KE_KEY && keycode == key->keycode)
-			return key;
-
-	return NULL;
-}
-
-static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
-			       int *keycode)
-{
-	struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
-
-	if (key && key->type == KE_KEY) {
-		*keycode = key->keycode;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static int dell_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 = dell_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 (!dell_wmi_get_entry_by_keycode(old_keycode))
-			clear_bit(old_keycode, dev->keybit);
-		return 0;
-	}
-	return -EINVAL;
-}
-
 static void dell_wmi_notify(u32 value, void *context)
 {
 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -170,7 +110,8 @@ static void dell_wmi_notify(u32 value, void *context)
 		 *  additional information, so mask them off for the
 		 *  scancode lookup
 		 */
-		key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF);
+		key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
+							buffer[1] & 0xFFFF);
 		if (key) {
 			input_report_key(dell_wmi_input_dev, key->keycode, 1);
 			input_sync(dell_wmi_input_dev);
@@ -184,41 +125,37 @@ static void dell_wmi_notify(u32 value, void *context)
 
 static int __init dell_wmi_input_setup(void)
 {
-	struct key_entry *key;
 	int err;
 
 	dell_wmi_input_dev = input_allocate_device();
-
 	if (!dell_wmi_input_dev)
 		return -ENOMEM;
 
 	dell_wmi_input_dev->name = "Dell WMI hotkeys";
 	dell_wmi_input_dev->phys = "wmi/input0";
 	dell_wmi_input_dev->id.bustype = BUS_HOST;
-	dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode;
-	dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode;
-
-	for (key = dell_wmi_keymap; key->type != KE_END; key++) {
-		switch (key->type) {
-		case KE_KEY:
-			set_bit(EV_KEY, dell_wmi_input_dev->evbit);
-			set_bit(key->keycode, dell_wmi_input_dev->keybit);
-			break;
-		case KE_SW:
-			set_bit(EV_SW, dell_wmi_input_dev->evbit);
-			set_bit(key->keycode, dell_wmi_input_dev->swbit);
-			break;
-		}
-	}
 
-	err = input_register_device(dell_wmi_input_dev);
+	err = sparse_keymap_setup(dell_wmi_input_dev, dell_wmi_keymap, NULL);
+	if (err)
+		goto err_free_dev;
 
-	if (err) {
-		input_free_device(dell_wmi_input_dev);
-		return err;
-	}
+	err = input_register_device(dell_wmi_input_dev);
+	if (err)
+		goto err_free_keymap;
 
 	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(dell_wmi_input_dev);
+ err_free_dev:
+	input_free_device(dell_wmi_input_dev);
+	return err;
+}
+
+static void dell_wmi_input_destroy(void)
+{
+	sparse_keymap_free(dell_wmi_input_dev);
+	input_unregister_device(dell_wmi_input_dev);
 }
 
 static int __init dell_wmi_init(void)
@@ -226,33 +163,30 @@ static int __init dell_wmi_init(void)
 	int err;
 
 	if (wmi_has_guid(DELL_EVENT_GUID)) {
-		err = dell_wmi_input_setup();
-
-		if (err)
-			return err;
+		printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
+		return -ENODEV;
+	}
 
-		err = wmi_install_notify_handler(DELL_EVENT_GUID,
-						 dell_wmi_notify, NULL);
-		if (err) {
-			input_unregister_device(dell_wmi_input_dev);
-			printk(KERN_ERR "dell-wmi: Unable to register"
-			       " notify handler - %d\n", err);
-			return err;
-		}
+	err = dell_wmi_input_setup();
+	if (err)
+		return err;
 
-	} else
-		printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
+	err = wmi_install_notify_handler(DELL_EVENT_GUID,
+					 dell_wmi_notify, NULL);
+	if (err) {
+		dell_wmi_input_destroy();
+		printk(KERN_ERR "dell-wmi: Unable to register"
+		       " notify handler - %d\n", err);
+		return err;
+	}
 
 	return 0;
 }
+module_init(dell_wmi_init);
 
 static void __exit dell_wmi_exit(void)
 {
-	if (wmi_has_guid(DELL_EVENT_GUID)) {
-		wmi_remove_notify_handler(DELL_EVENT_GUID);
-		input_unregister_device(dell_wmi_input_dev);
-	}
+	wmi_remove_notify_handler(DELL_EVENT_GUID);
+	dell_wmi_input_destroy();
 }
-
-module_init(dell_wmi_init);
 module_exit(dell_wmi_exit);


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/8] Input: hp-wmi - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
                   ` (2 preceding siblings ...)
  2009-12-02  9:24 ` [PATCH 3/8] Input: dell-wmi " Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-03  9:58   ` Anisse Astier
  2009-12-02  9:24 ` [PATCH 5/8] Input: eeepc-laptop " Dmitry Torokhov
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig  |    1 
 drivers/platform/x86/hp-wmi.c |  142 ++++++++++++-----------------------------
 2 files changed, 44 insertions(+), 99 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 1f10bf4..18b66fd 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -137,6 +137,7 @@ config HP_WMI
 	depends on ACPI_WMI
 	depends on INPUT
 	depends on RFKILL || RFKILL = n
+	select INPUT_SPARSEKMAP
 	help
 	 Say Y here if you want to support WMI-based hotkeys on HP laptops and
 	 to read data from WMI such as docking or ambient light sensor state.
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c284217..8868610 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
@@ -69,21 +70,13 @@ struct bios_return {
 	u32 value;
 };
 
-struct key_entry {
-	char type;		/* See KE_* below */
-	u16 code;
-	u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry hp_wmi_keymap[] = {
-	{KE_KEY, 0x02, KEY_BRIGHTNESSUP},
-	{KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
-	{KE_KEY, 0x20e6, KEY_PROG1},
-	{KE_KEY, 0x2142, KEY_MEDIA},
-	{KE_KEY, 0x213b, KEY_INFO},
-	{KE_KEY, 0x231b, KEY_HELP},
+static const struct key_entry hp_wmi_keymap[] = {
+	{KE_KEY, 0x02, {KEY_BRIGHTNESSUP}},
+	{KE_KEY, 0x03, {KEY_BRIGHTNESSDOWN}},
+	{KE_KEY, 0x20e6, {KEY_PROG1}},
+	{KE_KEY, 0x2142, {KEY_MEDIA}},
+	{KE_KEY, 0x213b, {KEY_INFO}},
+	{KE_KEY, 0x231b, {KEY_HELP}},
 	{KE_END, 0}
 };
 
@@ -274,61 +267,6 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
 
-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;
-}
-
 static void hp_wmi_notify(u32 value, void *context)
 {
 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -344,7 +282,8 @@ static void hp_wmi_notify(u32 value, void *context)
 		if (eventcode == 0x4)
 			eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
 							 0);
-		key = hp_wmi_get_entry_by_scancode(eventcode);
+		key = sparse_keymap_entry_from_scancode(hp_wmi_input_dev,
+							eventcode);
 		if (key) {
 			switch (key->type) {
 			case KE_KEY:
@@ -381,7 +320,6 @@ static void hp_wmi_notify(u32 value, void *context)
 
 static int __init hp_wmi_input_setup(void)
 {
-	struct key_entry *key;
 	int err;
 
 	hp_wmi_input_dev = input_allocate_device();
@@ -389,21 +327,14 @@ static int __init hp_wmi_input_setup(void)
 	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++) {
-		switch (key->type) {
-		case KE_KEY:
-			set_bit(EV_KEY, hp_wmi_input_dev->evbit);
-			set_bit(key->keycode, hp_wmi_input_dev->keybit);
-			break;
-		}
-	}
 
-	set_bit(EV_SW, hp_wmi_input_dev->evbit);
-	set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
-	set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+	__set_bit(EV_SW, hp_wmi_input_dev->evbit);
+	__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+	__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+	err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
+	if (err)
+		goto err_free_dev;
 
 	/* Set initial hardware state */
 	input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -411,14 +342,29 @@ static int __init hp_wmi_input_setup(void)
 			    hp_wmi_tablet_state());
 	input_sync(hp_wmi_input_dev);
 
-	err = input_register_device(hp_wmi_input_dev);
+	err = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
+	if (err)
+		goto err_free_keymap;
 
-	if (err) {
-		input_free_device(hp_wmi_input_dev);
-		return err;
-	}
+	err = input_register_device(hp_wmi_input_dev);
+	if (err)
+		goto err_uninstall_notifier;
 
 	return 0;
+
+ err_uninstall_notifier:
+	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ err_free_keymap:
+	sparse_keymap_free(hp_wmi_input_dev);
+ err_free_dev:
+	input_free_device(hp_wmi_input_dev);
+	return err;
+}
+
+static void __exit hp_wmi_input_destroy(void)
+{
+	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+	input_unregister_device(hp_wmi_input_dev);
 }
 
 static void cleanup_sysfs(struct platform_device *device)
@@ -541,10 +487,9 @@ static int __init hp_wmi_init(void)
 	int err;
 
 	if (wmi_has_guid(HPWMI_EVENT_GUID)) {
-		err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
-						 hp_wmi_notify, NULL);
-		if (!err)
-			hp_wmi_input_setup();
+		err = hp_wmi_input_setup();
+		if (err)
+			return err;
 	}
 
 	if (wmi_has_guid(HPWMI_BIOS_GUID)) {
@@ -564,10 +509,9 @@ static int __init hp_wmi_init(void)
 
 static void __exit hp_wmi_exit(void)
 {
-	if (wmi_has_guid(HPWMI_EVENT_GUID)) {
-		wmi_remove_notify_handler(HPWMI_EVENT_GUID);
-		input_unregister_device(hp_wmi_input_dev);
-	}
+	if (wmi_has_guid(HPWMI_EVENT_GUID))
+		hp_wmi_input_destroy();
+
 	if (hp_wmi_platform_dev) {
 		platform_device_del(hp_wmi_platform_dev);
 		platform_driver_unregister(&hp_wmi_driver);


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/8] Input: eeepc-laptop - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
                   ` (3 preceding siblings ...)
  2009-12-02  9:24 ` [PATCH 4/8] Input: hp-wmi " Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 6/8] Input: asus-laptop " Dmitry Torokhov
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig        |    1 
 drivers/platform/x86/eeepc-laptop.c |  153 +++++++++++------------------------
 2 files changed, 49 insertions(+), 105 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 18b66fd..ae9c976 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -336,6 +336,7 @@ config EEEPC_LAPTOP
 	depends on HOTPLUG_PCI
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
+	select INPUT_SPARSEKMAP
 	---help---
 	  This driver supports the Fn-Fx keys on Eee PC laptops.
 
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 4226e53..009c70b 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -31,6 +31,7 @@
 #include <acpi/acpi_bus.h>
 #include <linux/uaccess.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 #include <linux/rfkill.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
@@ -169,31 +170,23 @@ static struct platform_driver platform_driver = {
 
 static struct platform_device *platform_device;
 
-struct key_entry {
-	char type;
-	u8 code;
-	u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry eeepc_keymap[] = {
+static const struct key_entry eeepc_keymap[] = {
 	/* Sleep already handled via generic ACPI code */
-	{KE_KEY, 0x10, KEY_WLAN },
-	{KE_KEY, 0x11, KEY_WLAN },
-	{KE_KEY, 0x12, KEY_PROG1 },
-	{KE_KEY, 0x13, KEY_MUTE },
-	{KE_KEY, 0x14, KEY_VOLUMEDOWN },
-	{KE_KEY, 0x15, KEY_VOLUMEUP },
-	{KE_KEY, 0x1a, KEY_COFFEE },
-	{KE_KEY, 0x1b, KEY_ZOOM },
-	{KE_KEY, 0x1c, KEY_PROG2 },
-	{KE_KEY, 0x1d, KEY_PROG3 },
-	{KE_KEY, NOTIFY_BRN_MIN,     KEY_BRIGHTNESSDOWN },
-	{KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP },
-	{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
-	{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
-	{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x10, { KEY_WLAN } },
+	{KE_KEY, 0x11, { KEY_WLAN } },
+	{KE_KEY, 0x12, { KEY_PROG1 } },
+	{KE_KEY, 0x13, { KEY_MUTE } },
+	{KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
+	{KE_KEY, 0x15, { KEY_VOLUMEUP } },
+	{KE_KEY, 0x1a, { KEY_COFFEE } },
+	{KE_KEY, 0x1b, { KEY_ZOOM } },
+	{KE_KEY, 0x1c, { KEY_PROG2 } },
+	{KE_KEY, 0x1d, { KEY_PROG3 } },
+	{KE_KEY, NOTIFY_BRN_MIN,     { KEY_BRIGHTNESSDOWN } },
+	{KE_KEY, NOTIFY_BRN_MIN + 2, { KEY_BRIGHTNESSUP } },
+	{KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
+	{KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
+	{KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
 	{KE_END, 0},
 };
 
@@ -509,61 +502,6 @@ static struct attribute_group platform_attribute_group = {
 /*
  * Hotkey functions
  */
-static struct key_entry *eepc_get_entry_by_scancode(int code)
-{
-	struct key_entry *key;
-
-	for (key = eeepc_keymap; key->type != KE_END; key++)
-		if (code == key->code)
-			return key;
-
-	return NULL;
-}
-
-static struct key_entry *eepc_get_entry_by_keycode(int code)
-{
-	struct key_entry *key;
-
-	for (key = eeepc_keymap; key->type != KE_END; key++)
-		if (code == key->keycode && key->type == KE_KEY)
-			return key;
-
-	return NULL;
-}
-
-static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
-{
-	struct key_entry *key = eepc_get_entry_by_scancode(scancode);
-
-	if (key && key->type == KE_KEY) {
-		*keycode = key->keycode;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static int eeepc_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 = eepc_get_entry_by_scancode(scancode);
-	if (key && key->type == KE_KEY) {
-		old_keycode = key->keycode;
-		key->keycode = keycode;
-		set_bit(keycode, dev->keybit);
-		if (!eepc_get_entry_by_keycode(old_keycode))
-			clear_bit(old_keycode, dev->keybit);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
 static void cmsg_quirk(int cm, const char *name)
 {
 	int dummy;
@@ -698,7 +636,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
 
 static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
 {
-	static struct key_entry *key;
+	struct key_entry *key;
 	u16 count;
 	int brn = -ENODEV;
 
@@ -729,7 +667,7 @@ static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
 			else
 				event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
 		}
-		key = eepc_get_entry_by_scancode(event);
+		key = sparse_keymap_entry_from_scancode(ehotk->inputdev, event);
 		if (key) {
 			switch (key->type) {
 			case KE_KEY:
@@ -1017,8 +955,10 @@ static void eeepc_rfkill_exit(void)
 
 static void eeepc_input_exit(void)
 {
-	if (ehotk->inputdev)
+	if (ehotk->inputdev) {
+		sparse_keymap_free(ehotk->inputdev);
 		input_unregister_device(ehotk->inputdev);
+	}
 }
 
 static void eeepc_hwmon_exit(void)
@@ -1158,36 +1098,39 @@ static int eeepc_hwmon_init(struct device *dev)
 
 static int eeepc_input_init(struct device *dev)
 {
-	const struct key_entry *key;
-	int result;
+	struct input_dev *input;
+	int error;
 
-	ehotk->inputdev = input_allocate_device();
-	if (!ehotk->inputdev) {
+	input = input_allocate_device();
+	if (!input) {
 		pr_info("Unable to allocate input device\n");
 		return -ENOMEM;
 	}
-	ehotk->inputdev->name = "Asus EeePC extra buttons";
-	ehotk->inputdev->dev.parent = dev;
-	ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
-	ehotk->inputdev->id.bustype = BUS_HOST;
-	ehotk->inputdev->getkeycode = eeepc_getkeycode;
-	ehotk->inputdev->setkeycode = eeepc_setkeycode;
-
-	for (key = eeepc_keymap; key->type != KE_END; key++) {
-		switch (key->type) {
-		case KE_KEY:
-			set_bit(EV_KEY, ehotk->inputdev->evbit);
-			set_bit(key->keycode, ehotk->inputdev->keybit);
-			break;
-		}
+	input->name = "Asus EeePC extra buttons";
+	input->dev.parent = dev;
+	input->phys = EEEPC_HOTK_FILE "/input0";
+	input->id.bustype = BUS_HOST;
+
+	error = sparse_keymap_setup(input, eeepc_keymap, NULL);
+	if (error) {
+		pr_err("Unable to setup input device keymap\n");
+		goto err_free_dev;
 	}
-	result = input_register_device(ehotk->inputdev);
-	if (result) {
-		pr_info("Unable to register input device\n");
-		input_free_device(ehotk->inputdev);
-		return result;
+
+	error = input_register_device(input);
+	if (error) {
+		pr_err("Unable to register input device\n");
+		goto err_free_keymap;
 	}
+
+	ehotk->inputdev = input;
 	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(input);
+ err_free_dev:
+	input_free_device(input);
+	return error;
 }
 
 static int __devinit eeepc_hotk_add(struct acpi_device *device)


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/8] Input: asus-laptop - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
                   ` (4 preceding siblings ...)
  2009-12-02  9:24 ` [PATCH 5/8] Input: eeepc-laptop " Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 7/8] Input: topstar-laptop " Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 8/8] Input: panasonic-laptop " Dmitry Torokhov
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig       |    1 
 drivers/platform/x86/asus-laptop.c |  181 +++++++++++++-----------------------
 2 files changed, 64 insertions(+), 118 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ae9c976..e555d39 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -59,6 +59,7 @@ config ASUS_LAPTOP
 	select NEW_LEDS
 	select BACKLIGHT_CLASS_DEVICE
 	depends on INPUT
+	select INPUT_SPARSEKMAP
 	---help---
 	  This is the new Linux driver for Asus laptops. It may also support some
 	  MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b39d2bb..c04332e 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -49,6 +49,7 @@
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 #define ASUS_LAPTOP_VERSION "0.42"
 
@@ -284,41 +285,33 @@ ASUS_LED(pled, "phone", 1);
 ASUS_LED(gled, "gaming", 1);
 ASUS_LED(kled, "kbd_backlight", 3);
 
-struct key_entry {
-	char type;
-	u8 code;
-	u16 keycode;
-};
-
-enum { KE_KEY, KE_END };
-
-static struct key_entry asus_keymap[] = {
-	{KE_KEY, 0x30, KEY_VOLUMEUP},
-	{KE_KEY, 0x31, KEY_VOLUMEDOWN},
-	{KE_KEY, 0x32, KEY_MUTE},
-	{KE_KEY, 0x33, KEY_SWITCHVIDEOMODE},
-	{KE_KEY, 0x34, KEY_SWITCHVIDEOMODE},
-	{KE_KEY, 0x40, KEY_PREVIOUSSONG},
-	{KE_KEY, 0x41, KEY_NEXTSONG},
-	{KE_KEY, 0x43, KEY_STOPCD},
-	{KE_KEY, 0x45, KEY_PLAYPAUSE},
-	{KE_KEY, 0x4c, KEY_MEDIA},
-	{KE_KEY, 0x50, KEY_EMAIL},
-	{KE_KEY, 0x51, KEY_WWW},
-	{KE_KEY, 0x55, KEY_CALC},
-	{KE_KEY, 0x5C, KEY_SCREENLOCK},  /* Screenlock */
-	{KE_KEY, 0x5D, KEY_WLAN},
-	{KE_KEY, 0x5E, KEY_WLAN},
-	{KE_KEY, 0x5F, KEY_WLAN},
-	{KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
-	{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
-	{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
-	{KE_KEY, 0x82, KEY_CAMERA},
-	{KE_KEY, 0x8A, KEY_PROG1},
-	{KE_KEY, 0x95, KEY_MEDIA},
-	{KE_KEY, 0x99, KEY_PHONE},
-	{KE_KEY, 0xc4, KEY_KBDILLUMUP},
-	{KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
+static const struct key_entry asus_keymap[] = {
+	{KE_KEY, 0x30, {KEY_VOLUMEUP}},
+	{KE_KEY, 0x31, {KEY_VOLUMEDOWN}},
+	{KE_KEY, 0x32, {KEY_MUTE}},
+	{KE_KEY, 0x33, {KEY_SWITCHVIDEOMODE}},
+	{KE_KEY, 0x34, {KEY_SWITCHVIDEOMODE}},
+	{KE_KEY, 0x40, {KEY_PREVIOUSSONG}},
+	{KE_KEY, 0x41, {KEY_NEXTSONG}},
+	{KE_KEY, 0x43, {KEY_STOPCD}},
+	{KE_KEY, 0x45, {KEY_PLAYPAUSE}},
+	{KE_KEY, 0x4c, {KEY_MEDIA}},
+	{KE_KEY, 0x50, {KEY_EMAIL}},
+	{KE_KEY, 0x51, {KEY_WWW}},
+	{KE_KEY, 0x55, {KEY_CALC}},
+	{KE_KEY, 0x5C, {KEY_SCREENLOCK}},  /* Screenlock */
+	{KE_KEY, 0x5D, {KEY_WLAN}},
+	{KE_KEY, 0x5E, {KEY_WLAN}},
+	{KE_KEY, 0x5F, {KEY_WLAN}},
+	{KE_KEY, 0x60, {KEY_SWITCHVIDEOMODE}},
+	{KE_KEY, 0x61, {KEY_SWITCHVIDEOMODE}},
+	{KE_KEY, 0x6B, {BTN_TOUCH}}, /* Lock Mouse */
+	{KE_KEY, 0x82, {KEY_CAMERA}},
+	{KE_KEY, 0x8A, {KEY_PROG1}},
+	{KE_KEY, 0x95, {KEY_MEDIA}},
+	{KE_KEY, 0x99, {KEY_PHONE}},
+	{KE_KEY, 0xc4, {KEY_KBDILLUMUP}},
+	{KE_KEY, 0xc5, {KEY_KBDILLUMDOWN}},
 	{KE_END, 0},
 };
 
@@ -866,61 +859,6 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
 /*
  * Hotkey functions
  */
-static struct key_entry *asus_get_entry_by_scancode(int code)
-{
-	struct key_entry *key;
-
-	for (key = asus_keymap; key->type != KE_END; key++)
-		if (code == key->code)
-			return key;
-
-	return NULL;
-}
-
-static struct key_entry *asus_get_entry_by_keycode(int code)
-{
-	struct key_entry *key;
-
-	for (key = asus_keymap; key->type != KE_END; key++)
-		if (code == key->keycode && key->type == KE_KEY)
-			return key;
-
-	return NULL;
-}
-
-static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
-{
-	struct key_entry *key = asus_get_entry_by_scancode(scancode);
-
-	if (key && key->type == KE_KEY) {
-		*keycode = key->keycode;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static int asus_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 = asus_get_entry_by_scancode(scancode);
-	if (key && key->type == KE_KEY) {
-		old_keycode = key->keycode;
-		key->keycode = keycode;
-		set_bit(keycode, dev->keybit);
-		if (!asus_get_entry_by_keycode(old_keycode))
-			clear_bit(old_keycode, dev->keybit);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
 static void asus_hotk_notify(struct acpi_device *device, u32 event)
 {
 	static struct key_entry *key;
@@ -949,9 +887,9 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event)
 					count);
 
 	if (hotk->inputdev) {
-		key = asus_get_entry_by_scancode(event);
+		key = sparse_keymap_entry_from_scancode(hotk->inputdev, event);
 		if (!key)
-			return ;
+			return;
 
 		switch (key->type) {
 		case KE_KEY:
@@ -1009,7 +947,7 @@ static struct platform_driver asuspf_driver = {
 	.driver = {
 		   .name = ASUS_HOTK_FILE,
 		   .owner = THIS_MODULE,
-		   }
+	},
 };
 
 static struct platform_device *asuspf_device;
@@ -1184,36 +1122,41 @@ static int asus_hotk_get_info(void)
 	return AE_OK;
 }
 
-static int asus_input_init(void)
+static int __init asus_input_init(void)
 {
-	const struct key_entry *key;
-	int result;
+	struct input_dev *inputdev;
+	int error;
 
-	hotk->inputdev = input_allocate_device();
-	if (!hotk->inputdev) {
-		pr_info("Unable to allocate input device\n");
-		return 0;
+	inputdev = input_allocate_device();
+	if (!inputdev) {
+		pr_err("Unable to allocate input device\n");
+		return -ENOMEM;
 	}
-	hotk->inputdev->name = "Asus Laptop extra buttons";
-	hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
-	hotk->inputdev->id.bustype = BUS_HOST;
-	hotk->inputdev->getkeycode = asus_getkeycode;
-	hotk->inputdev->setkeycode = asus_setkeycode;
 
-	for (key = asus_keymap; key->type != KE_END; key++) {
-		switch (key->type) {
-		case KE_KEY:
-			set_bit(EV_KEY, hotk->inputdev->evbit);
-			set_bit(key->keycode, hotk->inputdev->keybit);
-			break;
-		}
+	inputdev->name = "Asus Laptop extra buttons";
+	inputdev->phys = ASUS_HOTK_FILE "/input0";
+	inputdev->id.bustype = BUS_HOST;
+
+	error = sparse_keymap_setup(inputdev, asus_keymap, NULL);
+	if (error) {
+		pr_err("Unable to setup input device keymap\n");
+		goto err_free_dev;
 	}
-	result = input_register_device(hotk->inputdev);
-	if (result) {
-		pr_info("Unable to register input device\n");
-		input_free_device(hotk->inputdev);
+
+	error = input_register_device(inputdev);
+	if (error) {
+		pr_err("Unable to register input device\n");
+		goto err_free_keymap;
 	}
-	return result;
+
+	hotk->inputdev = inputdev;
+	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(inputdev);
+ err_free_dev:
+	input_free_device(inputdev);
+	return error;
 }
 
 static int asus_hotk_check(void)
@@ -1338,8 +1281,10 @@ static void asus_led_exit(void)
 
 static void asus_input_exit(void)
 {
-	if (hotk->inputdev)
+	if (hotk->inputdev) {
+		sparse_keymap_free(hotk->inputdev);
 		input_unregister_device(hotk->inputdev);
+	}
 }
 
 static void __exit asus_laptop_exit(void)


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/8] Input: topstar-laptop - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
                   ` (5 preceding siblings ...)
  2009-12-02  9:24 ` [PATCH 6/8] Input: asus-laptop " Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  2009-12-02  9:24 ` [PATCH 8/8] Input: panasonic-laptop " Dmitry Torokhov
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig          |    1 
 drivers/platform/x86/topstar-laptop.c |  146 ++++++++++++---------------------
 2 files changed, 52 insertions(+), 95 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index e555d39..00e94b0 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -405,6 +405,7 @@ config TOPSTAR_LAPTOP
 	tristate "Topstar Laptop Extras"
 	depends on ACPI
 	depends on INPUT
+	select INPUT_SPARSEKMAP
 	---help---
 	  This driver adds support for hotkeys found on Topstar laptops.
 
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index 02f3d4e..7ca08db 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 #define ACPI_TOPSTAR_CLASS "topstar"
 
@@ -25,52 +26,25 @@ struct topstar_hkey {
 	struct input_dev *inputdev;
 };
 
-struct tps_key_entry {
-	u8 code;
-	u16 keycode;
+static const struct key_entry topstar_keymap[] = {
+	{ KE_KEY, 0x80, { KEY_BRIGHTNESSUP } },
+	{ KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } },
+	{ KE_KEY, 0x83, { KEY_VOLUMEUP } },
+	{ KE_KEY, 0x84, { KEY_VOLUMEDOWN } },
+	{ KE_KEY, 0x85, { KEY_MUTE } },
+	{ KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } },
+	{ KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */
+	{ KE_KEY, 0x88, { KEY_WLAN } },
+	{ KE_KEY, 0x8a, { KEY_WWW } },
+	{ KE_KEY, 0x8b, { KEY_MAIL } },
+	{ KE_KEY, 0x8c, { KEY_MEDIA } },
+	{ KE_KEY, 0x96, { KEY_F14 } }, /* G key? */
+	{ KE_END, 0 }
 };
 
-static struct tps_key_entry topstar_keymap[] = {
-	{ 0x80, KEY_BRIGHTNESSUP },
-	{ 0x81, KEY_BRIGHTNESSDOWN },
-	{ 0x83, KEY_VOLUMEUP },
-	{ 0x84, KEY_VOLUMEDOWN },
-	{ 0x85, KEY_MUTE },
-	{ 0x86, KEY_SWITCHVIDEOMODE },
-	{ 0x87, KEY_F13 }, /* touchpad enable/disable key */
-	{ 0x88, KEY_WLAN },
-	{ 0x8a, KEY_WWW },
-	{ 0x8b, KEY_MAIL },
-	{ 0x8c, KEY_MEDIA },
-	{ 0x96, KEY_F14 }, /* G key? */
-	{ }
-};
-
-static struct tps_key_entry *tps_get_key_by_scancode(int code)
-{
-	struct tps_key_entry *key;
-
-	for (key = topstar_keymap; key->code; key++)
-		if (code == key->code)
-			return key;
-
-	return NULL;
-}
-
-static struct tps_key_entry *tps_get_key_by_keycode(int code)
-{
-	struct tps_key_entry *key;
-
-	for (key = topstar_keymap; key->code; key++)
-		if (code == key->keycode)
-			return key;
-
-	return NULL;
-}
-
 static void acpi_topstar_notify(struct acpi_device *device, u32 event)
 {
-	struct tps_key_entry *key;
+	struct key_entry *key;
 	static bool dup_evnt[2];
 	bool *dup;
 	struct topstar_hkey *hkey = acpi_driver_data(device);
@@ -92,13 +66,16 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event)
 	if (event == 0x97)
 		event = 0x96;
 
-	key = tps_get_key_by_scancode(event);
+	key = sparse_keymap_entry_from_scancode(hkey->inputdev, event);
 	if (key) {
-		input_report_key(hkey->inputdev, key->keycode, 1);
-		input_sync(hkey->inputdev);
-		input_report_key(hkey->inputdev, key->keycode, 0);
-		input_sync(hkey->inputdev);
-		return;
+		switch (key->type) {
+		case KE_KEY:
+			input_report_key(hkey->inputdev, key->keycode, 1);
+			input_sync(hkey->inputdev);
+			input_report_key(hkey->inputdev, key->keycode, 0);
+			input_sync(hkey->inputdev);
+			return;
+		}
 	}
 
 	/* Known non hotkey events don't handled or that we don't care yet */
@@ -126,63 +103,41 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
 	return 0;
 }
 
-static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
-{
-	struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
-
-	if (!key)
-		return -EINVAL;
-
-	*keycode = key->keycode;
-	return 0;
-}
-
-static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode)
-{
-	struct tps_key_entry *key;
-	int old_keycode;
-
-	if (keycode < 0 || keycode > KEY_MAX)
-		return -EINVAL;
-
-	key = tps_get_key_by_scancode(scancode);
-
-	if (!key)
-		return -EINVAL;
-
-	old_keycode = key->keycode;
-	key->keycode = keycode;
-	set_bit(keycode, dev->keybit);
-	if (!tps_get_key_by_keycode(old_keycode))
-		clear_bit(old_keycode, dev->keybit);
-	return 0;
-}
-
 static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
 {
-	struct tps_key_entry *key;
+	struct input_dev *input;
+	int error;
 
-	hkey->inputdev = input_allocate_device();
-	if (!hkey->inputdev) {
+	input = input_allocate_device();
+	if (!input) {
 		pr_err("Unable to allocate input device\n");
-		return -ENODEV;
+		return -ENOMEM;
 	}
-	hkey->inputdev->name = "Topstar Laptop extra buttons";
-	hkey->inputdev->phys = "topstar/input0";
-	hkey->inputdev->id.bustype = BUS_HOST;
-	hkey->inputdev->getkeycode = topstar_getkeycode;
-	hkey->inputdev->setkeycode = topstar_setkeycode;
-	for (key = topstar_keymap; key->code; key++) {
-		set_bit(EV_KEY, hkey->inputdev->evbit);
-		set_bit(key->keycode, hkey->inputdev->keybit);
+
+	input->name = "Topstar Laptop extra buttons";
+	input->phys = "topstar/input0";
+	input->id.bustype = BUS_HOST;
+
+	error = sparse_keymap_setup(input, topstar_keymap, NULL);
+	if (error) {
+		pr_err("Unable to setup input device keymap\n");
+		goto err_free_dev;
 	}
-	if (input_register_device(hkey->inputdev)) {
+
+	error = input_register_device(input);
+	if (error) {
 		pr_err("Unable to register input device\n");
-		input_free_device(hkey->inputdev);
-		return -ENODEV;
+		goto err_free_keymap;
 	}
 
+	hkey->inputdev = input;
 	return 0;
+
+ err_free_keymap:
+	sparse_keymap_free(input);
+ err_free_dev:
+	input_free_device(input);
+	return error;
 }
 
 static int acpi_topstar_add(struct acpi_device *device)
@@ -216,6 +171,7 @@ static int acpi_topstar_remove(struct acpi_device *device, int type)
 
 	acpi_topstar_fncx_switch(device, false);
 
+	sparse_keymap_free(tps_hkey->inputdev);
 	input_unregister_device(tps_hkey->inputdev);
 	kfree(tps_hkey);
 


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 8/8] Input: panasonic-laptop - switch to using sparse keymap library
  2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
                   ` (6 preceding siblings ...)
  2009-12-02  9:24 ` [PATCH 7/8] Input: topstar-laptop " Dmitry Torokhov
@ 2009-12-02  9:24 ` Dmitry Torokhov
  7 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-02  9:24 UTC (permalink / raw)
  To: linux-input
  Cc: linux-acpi, Len Brown, Herton Ronaldo Krzesinski, Harald Welte,
	Corentin Chary, Carlos Corbacho, Wu Zhangjin

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/platform/x86/Kconfig            |    1 
 drivers/platform/x86/panasonic-laptop.c |  172 ++++++++++++-------------------
 2 files changed, 66 insertions(+), 107 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 00e94b0..1b27e4d 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -168,6 +168,7 @@ config PANASONIC_LAPTOP
 	tristate "Panasonic Laptop Extras"
 	depends on INPUT && ACPI
 	depends on BACKLIGHT_CLASS_DEVICE
+	select INPUT_SPARSEKMAP
 	---help---
 	  This driver adds support for access to backlight control and hotkeys
 	  on Panasonic Let's Note laptops.
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index fe7cf01..d24b824 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -127,6 +127,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
 
 
 #ifndef ACPI_HOTKEY_COMPONENT
@@ -199,30 +200,29 @@ static struct acpi_driver acpi_pcc_driver = {
 			},
 };
 
-#define KEYMAP_SIZE		11
-static const int initial_keymap[KEYMAP_SIZE] = {
-	/*  0 */ KEY_RESERVED,
-	/*  1 */ KEY_BRIGHTNESSDOWN,
-	/*  2 */ KEY_BRIGHTNESSUP,
-	/*  3 */ KEY_DISPLAYTOGGLE,
-	/*  4 */ KEY_MUTE,
-	/*  5 */ KEY_VOLUMEDOWN,
-	/*  6 */ KEY_VOLUMEUP,
-	/*  7 */ KEY_SLEEP,
-	/*  8 */ KEY_PROG1, /* Change CPU boost */
-	/*  9 */ KEY_BATTERY,
-	/* 10 */ KEY_SUSPEND,
+static const struct key_entry panasonic_keymap[] = {
+	{ KE_KEY, 0, { KEY_RESERVED } },
+	{ KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
+	{ KE_KEY, 2, { KEY_BRIGHTNESSUP } },
+	{ KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
+	{ KE_KEY, 4, { KEY_MUTE } },
+	{ KE_KEY, 5, { KEY_VOLUMEDOWN } },
+	{ KE_KEY, 6, { KEY_VOLUMEUP } },
+	{ KE_KEY, 7, { KEY_SLEEP } },
+	{ KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
+	{ KE_KEY, 9, { KEY_BATTERY } },
+	{ KE_KEY, 10, { KEY_SUSPEND } },
+	{ KE_END, 0 }
 };
 
 struct pcc_acpi {
 	acpi_handle		handle;
 	unsigned long		num_sifr;
 	int			sticky_mode;
-	u32 			*sinf;
+	u32			*sinf;
 	struct acpi_device	*device;
 	struct input_dev	*input_dev;
 	struct backlight_device	*backlight;
-	int			keymap[KEYMAP_SIZE];
 };
 
 struct pcc_keyinput {
@@ -445,57 +445,11 @@ static struct attribute_group pcc_attr_group = {
 
 /* hotkey input device driver */
 
-static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
-{
-	struct pcc_acpi *pcc = input_get_drvdata(dev);
-
-	if (scancode >= ARRAY_SIZE(pcc->keymap))
-		return -EINVAL;
-
-	*keycode = pcc->keymap[scancode];
-
-	return 0;
-}
-
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
-		if (pcc->keymap[i] == keycode)
-			return i+1;
-	}
-
-	return 0;
-}
-
-static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
-{
-	struct pcc_acpi *pcc = input_get_drvdata(dev);
-	int oldkeycode;
-
-	if (scancode >= ARRAY_SIZE(pcc->keymap))
-		return -EINVAL;
-
-	if (keycode < 0 || keycode > KEY_MAX)
-		return -EINVAL;
-
-	oldkeycode = pcc->keymap[scancode];
-	pcc->keymap[scancode] = keycode;
-
-	set_bit(keycode, dev->keybit);
-
-	if (!keymap_get_by_keycode(pcc, oldkeycode))
-		clear_bit(oldkeycode, dev->keybit);
-
-	return 0;
-}
-
 static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
 {
+	struct key_entry *key;
 	struct input_dev *hotk_input_dev = pcc->input_dev;
 	int rc;
-	int key_code, hkey_num;
 	unsigned long long result;
 
 	rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
@@ -508,25 +462,18 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
 
 	acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
 
-	hkey_num = result & 0xf;
-
-	if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "hotkey number out of range: %d\n",
-				  hkey_num));
-		return;
+	key = sparse_keymap_entry_from_scancode(hotk_input_dev, result & 0xf);
+	if (key) {
+		switch (key->type) {
+		case KE_KEY:
+			input_report_key(hotk_input_dev,
+					 key->keycode, result & 0x80);
+			input_sync(hotk_input_dev);
+			return;
+		}
 	}
 
-	key_code = pcc->keymap[hkey_num];
-
-	if (key_code != KEY_RESERVED) {
-		int pushed = (result & 0x80) ? TRUE : FALSE;
-
-		input_report_key(hotk_input_dev, key_code, pushed);
-		input_sync(hotk_input_dev);
-	}
-
-	return;
+	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown hotkey event: %d\n", result));
 }
 
 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -545,40 +492,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
 
 static int acpi_pcc_init_input(struct pcc_acpi *pcc)
 {
-	int i, rc;
+	struct input_dev *input_dev;
+	int error;
 
-	pcc->input_dev = input_allocate_device();
-	if (!pcc->input_dev) {
+	input_dev = input_allocate_device();
+	if (!input_dev) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Couldn't allocate input device for hotkey"));
 		return -ENOMEM;
 	}
 
-	pcc->input_dev->evbit[0] = BIT(EV_KEY);
+	input_dev->name = ACPI_PCC_DRIVER_NAME;
+	input_dev->phys = ACPI_PCC_INPUT_PHYS;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
 
-	pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
-	pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
-	pcc->input_dev->id.bustype = BUS_HOST;
-	pcc->input_dev->id.vendor = 0x0001;
-	pcc->input_dev->id.product = 0x0001;
-	pcc->input_dev->id.version = 0x0100;
-	pcc->input_dev->getkeycode = pcc_getkeycode;
-	pcc->input_dev->setkeycode = pcc_setkeycode;
+	error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
+	if (error) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Unable to setup input device keymap\n"));
+		goto err_free_dev;
+	}
 
-	/* load initial keymap */
-	memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+	input_set_drvdata(input_dev, pcc);
 
-	for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
-		__set_bit(pcc->keymap[i], pcc->input_dev->keybit);
-	__clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+	error = input_register_device(input_dev);
+	if (error) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Unable to register input device\n"));
+		goto err_free_keymap;
+	}
 
-	input_set_drvdata(pcc->input_dev, pcc);
+	pcc->input_dev = input_dev;
+	return 0;
 
-	rc = input_register_device(pcc->input_dev);
-	if (rc < 0)
-		input_free_device(pcc->input_dev);
+ err_free_keymap:
+	sparse_keymap_free(input_dev);
+ err_free_dev:
+	input_free_device(input_dev);
+	return error;
+}
 
-	return rc;
+static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
+{
+	sparse_keymap_free(pcc->input_dev);
+	input_unregister_device(pcc->input_dev);
+	/* no need to input_free_device() since core input API refcount and
+	 * free()s the device */
 }
 
 /* kernel module interface */
@@ -671,9 +633,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
 out_backlight:
 	backlight_device_unregister(pcc->backlight);
 out_input:
-	input_unregister_device(pcc->input_dev);
-	/* no need to input_free_device() since core input API refcount and
-	 * free()s the device */
+	acpi_pcc_destroy_input(pcc);
 out_sinf:
 	kfree(pcc->sinf);
 out_hotkey:
@@ -710,9 +670,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
 
 	backlight_device_unregister(pcc->backlight);
 
-	input_unregister_device(pcc->input_dev);
-	/* no need to input_free_device() since core input API refcount and
-	 * free()s the device */
+	acpi_pcc_destroy_input(pcc);
 
 	kfree(pcc->sinf);
 	kfree(pcc);


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/8] Input: hp-wmi - switch to using sparse keymap library
  2009-12-02  9:24 ` [PATCH 4/8] Input: hp-wmi " Dmitry Torokhov
@ 2009-12-03  9:58   ` Anisse Astier
  2009-12-03 10:03     ` Dmitry Torokhov
  0 siblings, 1 reply; 11+ messages in thread
From: Anisse Astier @ 2009-12-03  9:58 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, linux-acpi, Len Brown, Herton Ronaldo Krzesinski,
	Harald Welte, Corentin Chary, Carlos Corbacho, Wu Zhangjin

Hi Dmitry,

On Wed, 02 Dec 2009 01:24:25 -0800, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote :

> diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> index c284217..8868610 100644
> --- a/drivers/platform/x86/hp-wmi.c
> +++ b/drivers/platform/x86/hp-wmi.c
> @@ -411,14 +342,29 @@ static int __init hp_wmi_input_setup(void)
>  			    hp_wmi_tablet_state());
>  	input_sync(hp_wmi_input_dev);
>  
> -	err = input_register_device(hp_wmi_input_dev);
> +	err = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
> +	if (err)
> +		goto err_free_keymap;
>  
> -	if (err) {
> -		input_free_device(hp_wmi_input_dev);
> -		return err;
> -	}
> +	err = input_register_device(hp_wmi_input_dev);
> +	if (err)
> +		goto err_uninstall_notifier;
>  
>  	return 0;
> +
> + err_uninstall_notifier:
> +	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
> + err_free_keymap:
> +	(hp_wmi_input_dev);
> + err_free_dev:
> +	input_free_device(hp_wmi_input_dev);
> +	return err;
> +}
> +
> +static void __exit hp_wmi_input_destroy(void)
> +{
> +	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
> +	input_unregister_device(hp_wmi_input_dev);
>  }
I'm not sure if you're calling sparse_keymap_free on the exit path.

>  
>  static void cleanup_sysfs(struct platform_device *device)
> @@ -564,10 +509,9 @@ static int __init hp_wmi_init(void)
>  
>  static void __exit hp_wmi_exit(void)
>  {
> -	if (wmi_has_guid(HPWMI_EVENT_GUID)) {
> -		wmi_remove_notify_handler(HPWMI_EVENT_GUID);
> -		input_unregister_device(hp_wmi_input_dev);
> -	}
> +	if (wmi_has_guid(HPWMI_EVENT_GUID))
> +		hp_wmi_input_destroy();
> +
>  	if (hp_wmi_platform_dev) {
>  		platform_device_del(hp_wmi_platform_dev);
>  		platform_driver_unregister(&hp_wmi_driver);
> 
OK, I'm guilty, I copied my sparse keymap adaptation for msi-wmi from this
patch :-)

--
Anisse

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/8] Input: hp-wmi - switch to using sparse keymap library
  2009-12-03  9:58   ` Anisse Astier
@ 2009-12-03 10:03     ` Dmitry Torokhov
  0 siblings, 0 replies; 11+ messages in thread
From: Dmitry Torokhov @ 2009-12-03 10:03 UTC (permalink / raw)
  To: Anisse Astier
  Cc: linux-input, linux-acpi, Len Brown, Herton Ronaldo Krzesinski,
	Harald Welte, Corentin Chary, Carlos Corbacho, Wu Zhangjin

On Thu, Dec 03, 2009 at 10:58:11AM +0100, Anisse Astier wrote:
> Hi Dmitry,
> 
> On Wed, 02 Dec 2009 01:24:25 -0800, Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote :
> 
> > diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
> > index c284217..8868610 100644
> > --- a/drivers/platform/x86/hp-wmi.c
> > +++ b/drivers/platform/x86/hp-wmi.c
> > @@ -411,14 +342,29 @@ static int __init hp_wmi_input_setup(void)
> >  			    hp_wmi_tablet_state());
> >  	input_sync(hp_wmi_input_dev);
> >  
> > -	err = input_register_device(hp_wmi_input_dev);
> > +	err = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
> > +	if (err)
> > +		goto err_free_keymap;
> >  
> > -	if (err) {
> > -		input_free_device(hp_wmi_input_dev);
> > -		return err;
> > -	}
> > +	err = input_register_device(hp_wmi_input_dev);
> > +	if (err)
> > +		goto err_uninstall_notifier;
> >  
> >  	return 0;
> > +
> > + err_uninstall_notifier:
> > +	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
> > + err_free_keymap:
> > +	(hp_wmi_input_dev);
> > + err_free_dev:
> > +	input_free_device(hp_wmi_input_dev);
> > +	return err;
> > +}
> > +
> > +static void __exit hp_wmi_input_destroy(void)
> > +{
> > +	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
> > +	input_unregister_device(hp_wmi_input_dev);
> >  }
> I'm not sure if you're calling sparse_keymap_free on the exit path.
> 

Guilty as charged ;)

-- 
Dmitry

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2009-12-03 10:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-02  9:24 [PATCH 0/8] [RFC/RFT] Implement sparse keymap library Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 1/8] Input: add generic support for sparse keymaps Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 2/8] Input: wistron_btns - switch to using sparse keymap library Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 3/8] Input: dell-wmi " Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 4/8] Input: hp-wmi " Dmitry Torokhov
2009-12-03  9:58   ` Anisse Astier
2009-12-03 10:03     ` Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 5/8] Input: eeepc-laptop " Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 6/8] Input: asus-laptop " Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 7/8] Input: topstar-laptop " Dmitry Torokhov
2009-12-02  9:24 ` [PATCH 8/8] Input: panasonic-laptop " Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).