linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] Input/HID: Bits and Pieces
@ 2013-11-01 20:16 David Herrmann
  2013-11-01 20:16 ` [PATCH 01/13] Input: uinput: add full absinfo support David Herrmann
                   ` (13 more replies)
  0 siblings, 14 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Hi

My backlog kept growing and most of the stuff depends on the ABS_* fixes, so I
gave it another try. The first 2 patches introduce EVIOC[GS]ABS2 and friends.
The rest is wiimote stuff that was laying around for some time and just needs
new ABS bits. So once the ABS stuff is in, I see no reason to delay the wiimote
patches (as they're even tested already). Hence, I put it all in a single
series.

Jiri, Dmitry, feel free to bribe me to split / not split the series so the
other one has to take it through their tree. Highest bid wins!

And I am still running tests, so please don't merge, yet. I will report back my
results. Besides, it's probably too late for 3.13, anyway and we should put it
into -next for 3.14 for some while.

Comments welcome!
David

David Herrmann (12):
  Input: uinput: add full absinfo support
  Input: introduce ABS_MAX2/CNT2 and friends
  Input: remove ambigious gamepad comment
  Input: add motion-tracking ABS_* bits and docs
  HID: wiimote: add hid_wiimote.legacy parameter
  HID: wiimote: adjust button-mapping to gamepad rules
  HID: wiimote: map nunchuk as real gamepad
  HID: wiimote: map classic controller as gamepad
  HID: wiimote: use ABS_ACCEL_* for accelerometer
  HID: wiimote: use ABS_GYRO_* bits for MP
  Input: introduce BTN/ABS bits for drums and guitars
  HID: wiimote: add support for Guitar-Hero drums

Nicolas Adenis-Lamarre (1):
  HID: wiimote: add support for Guitar-Hero guitars

 Documentation/input/gamepad.txt          |   9 +-
 Documentation/input/motion-tracking.txt  | 149 ++++++
 drivers/hid/hid-debug.c                  |   2 +-
 drivers/hid/hid-input.c                  |   2 +-
 drivers/hid/hid-wiimote-core.c           |  23 +
 drivers/hid/hid-wiimote-modules.c        | 761 ++++++++++++++++++++++++++-----
 drivers/hid/hid-wiimote.h                |   4 +
 drivers/input/evdev.c                    |  88 +++-
 drivers/input/input.c                    |  14 +-
 drivers/input/keyboard/goldfish_events.c |   6 +-
 drivers/input/keyboard/hil_kbd.c         |   2 +-
 drivers/input/misc/uinput.c              | 146 ++++--
 include/linux/hid.h                      |   2 +-
 include/linux/input.h                    |   6 +-
 include/linux/mod_devicetable.h          |   2 +-
 include/uapi/linux/input.h               |  66 ++-
 include/uapi/linux/uinput.h              |   9 +
 17 files changed, 1125 insertions(+), 166 deletions(-)
 create mode 100644 Documentation/input/motion-tracking.txt

-- 
1.8.4.1


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

* [PATCH 01/13] Input: uinput: add full absinfo support
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends David Herrmann
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

We currently lack support for abs-resolution and abs-value parameters
during uinput ABS initialization. Furthermore, our parsers don't allow
growing ABS_CNT values. Therefore, introduce uinput_user_dev2.

User-space is free to write uinput_user_dev2 objects instead of
uinput_user_dev legacy objects now. If the kernel lacks support for it,
our comparison for "count != sizeof(struct uinput_user_dev)" will catch
this and return EINVAL. User-space shall retry with the legacy mode then.

Internally, we transform the legacy object into uinput_user_dev2 and then
handle both the same way.

The new uinput_user_dev2 object has multiple new features:
 - abs payload now has "value" and "resolution" parameters as part of the
   switch to "struct input_absinfo". We simply copy these over.
 - Our parser allows growing ABS_CNT. We automatically detect the payload
   size of the caller, thus, calculating the ABS_CNT the program was
   compiled with.
 - A "version" field to denote the uinput-version used. This is required
   to properly support changing "struct input_user_dev2" changes in the
   future. Due to the dynamic ABS_CNT support, we cannot simply add new
   fields, as we cannot deduce the structure size from the user-space
   given size. Thus, we need the "version" field to allow changing the
   object and properly detecting it in our write() handler.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/input/misc/uinput.c | 142 ++++++++++++++++++++++++++++++++------------
 include/uapi/linux/uinput.h |   9 +++
 2 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index a0a4bba..3cd84d2 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -358,14 +358,16 @@ static int uinput_allocate_device(struct uinput_device *udev)
 }
 
 static int uinput_setup_device(struct uinput_device *udev,
-			       const char __user *buffer, size_t count)
+			       struct uinput_user_dev2 *user_dev2,
+			       size_t abscnt)
 {
-	struct uinput_user_dev	*user_dev;
 	struct input_dev	*dev;
 	int			i;
 	int			retval;
+	struct input_absinfo	*abs;
 
-	if (count != sizeof(struct uinput_user_dev))
+	/* Ensure name is filled in */
+	if (!user_dev2->name[0])
 		return -EINVAL;
 
 	if (!udev->dev) {
@@ -375,37 +377,27 @@ static int uinput_setup_device(struct uinput_device *udev,
 	}
 
 	dev = udev->dev;
-
-	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
-	if (IS_ERR(user_dev))
-		return PTR_ERR(user_dev);
-
-	udev->ff_effects_max = user_dev->ff_effects_max;
-
-	/* Ensure name is filled in */
-	if (!user_dev->name[0]) {
-		retval = -EINVAL;
-		goto exit;
-	}
+	udev->ff_effects_max = user_dev2->ff_effects_max;
 
 	kfree(dev->name);
-	dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
+	dev->name = kstrndup(user_dev2->name, UINPUT_MAX_NAME_SIZE,
 			     GFP_KERNEL);
-	if (!dev->name) {
-		retval = -ENOMEM;
-		goto exit;
-	}
-
-	dev->id.bustype	= user_dev->id.bustype;
-	dev->id.vendor	= user_dev->id.vendor;
-	dev->id.product	= user_dev->id.product;
-	dev->id.version	= user_dev->id.version;
+	if (!dev->name)
+		return -ENOMEM;
 
-	for (i = 0; i < ABS_CNT; i++) {
-		input_abs_set_max(dev, i, user_dev->absmax[i]);
-		input_abs_set_min(dev, i, user_dev->absmin[i]);
-		input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
-		input_abs_set_flat(dev, i, user_dev->absflat[i]);
+	dev->id.bustype = user_dev2->id.bustype;
+	dev->id.vendor = user_dev2->id.vendor;
+	dev->id.product = user_dev2->id.product;
+	dev->id.version = user_dev2->id.version;
+
+	for (i = 0; i < abscnt; i++) {
+		abs = &user_dev2->abs[i];
+		input_abs_set_val(dev, i, abs->value);
+		input_abs_set_max(dev, i, abs->maximum);
+		input_abs_set_min(dev, i, abs->minimum);
+		input_abs_set_fuzz(dev, i, abs->fuzz);
+		input_abs_set_flat(dev, i, abs->flat);
+		input_abs_set_res(dev, i, abs->resolution);
 	}
 
 	/* check if absmin/absmax/absfuzz/absflat are filled as
@@ -413,7 +405,7 @@ static int uinput_setup_device(struct uinput_device *udev,
 	if (test_bit(EV_ABS, dev->evbit)) {
 		retval = uinput_validate_absbits(dev);
 		if (retval < 0)
-			goto exit;
+			return retval;
 		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
 			int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
 			input_mt_init_slots(dev, nslot, 0);
@@ -423,11 +415,84 @@ static int uinput_setup_device(struct uinput_device *udev,
 	}
 
 	udev->state = UIST_SETUP_COMPLETE;
-	retval = count;
+	return 0;
+}
+
+static int uinput_setup_device1(struct uinput_device *udev,
+				const char __user *buffer, size_t count)
+{
+	struct uinput_user_dev	*user_dev;
+	struct uinput_user_dev2	*user_dev2;
+	int			i;
+	int			retval;
+
+	if (count != sizeof(struct uinput_user_dev))
+		return -EINVAL;
+
+	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
+	if (IS_ERR(user_dev))
+		return PTR_ERR(user_dev);
+
+	user_dev2 = kmalloc(sizeof(*user_dev2), GFP_KERNEL);
+	if (!user_dev2) {
+		kfree(user_dev);
+		return -ENOMEM;
+	}
+
+	user_dev2->version = UINPUT_VERSION;
+	memcpy(user_dev2->name, user_dev->name, UINPUT_MAX_NAME_SIZE);
+	memcpy(&user_dev2->id, &user_dev->id, sizeof(struct input_id));
+	user_dev2->ff_effects_max = user_dev->ff_effects_max;
+
+	for (i = 0; i < ABS_CNT; ++i) {
+		user_dev2->abs[i].value = 0;
+		user_dev2->abs[i].maximum = user_dev->absmax[i];
+		user_dev2->abs[i].minimum = user_dev->absmin[i];
+		user_dev2->abs[i].fuzz = user_dev->absfuzz[i];
+		user_dev2->abs[i].flat = user_dev->absflat[i];
+		user_dev2->abs[i].resolution = 0;
+	}
+
+	retval = uinput_setup_device(udev, user_dev2, ABS_CNT);
 
- exit:
 	kfree(user_dev);
-	return retval;
+	kfree(user_dev2);
+
+	return retval ? retval : count;
+}
+
+static int uinput_setup_device2(struct uinput_device *udev,
+			       const char __user *buffer, size_t count)
+{
+	struct uinput_user_dev2	*user_dev2;
+	int			retval;
+	size_t			off, abscnt, max;
+
+	/* The first revision of "uinput_user_dev2" is bigger than
+	 * "uinput_user_dev" and growing. Disallow any smaller payloads. */
+	if (count <= sizeof(struct uinput_user_dev))
+		return -EINVAL;
+
+	/* rough check to avoid huge kernel space allocations */
+	max = ABS_CNT * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
+	if (count > max)
+		return -EINVAL;
+
+	user_dev2 = memdup_user(buffer, count);
+	if (IS_ERR(user_dev2))
+		return PTR_ERR(user_dev2);
+
+	if (user_dev2->version > UINPUT_VERSION) {
+		retval = -EINVAL;
+	} else {
+		off = offsetof(struct uinput_user_dev2, abs);
+		abscnt = (count - off) / sizeof(*user_dev2->abs);
+		retval = uinput_setup_device(udev, user_dev2, abscnt);
+	}
+
+	kfree(user_dev2);
+
+	return retval ? retval : count;
 }
 
 static ssize_t uinput_inject_event(struct uinput_device *udev,
@@ -459,9 +524,12 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
 	if (retval)
 		return retval;
 
-	retval = udev->state == UIST_CREATED ?
-			uinput_inject_event(udev, buffer, count) :
-			uinput_setup_device(udev, buffer, count);
+	if (udev->state == UIST_CREATED)
+		retval = uinput_inject_event(udev, buffer, count);
+	else if (count <= sizeof(struct uinput_user_dev))
+		retval = uinput_setup_device1(udev, buffer, count);
+	else
+		retval = uinput_setup_device2(udev, buffer, count);
 
 	mutex_unlock(&udev->mutex);
 
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index fe46431..c2e8710 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -134,4 +134,13 @@ struct uinput_user_dev {
 	__s32 absfuzz[ABS_CNT];
 	__s32 absflat[ABS_CNT];
 };
+
+struct uinput_user_dev2 {
+	__u8 version;
+	char name[UINPUT_MAX_NAME_SIZE];
+	struct input_id id;
+	__u32 ff_effects_max;
+	struct input_absinfo abs[ABS_CNT];
+};
+
 #endif /* _UAPI__UINPUT_H_ */
-- 
1.8.4.1


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

* [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
  2013-11-01 20:16 ` [PATCH 01/13] Input: uinput: add full absinfo support David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-05 22:29   ` David Herrmann
  2013-11-01 20:16 ` [PATCH 03/13] Input: remove ambigious gamepad comment David Herrmann
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

As we painfully noticed during the 3.12 merge-window our
EVIOCGABS/EVIOCSABS API is limited to ABS_MAX<=0x3f. We tried several
hacks to work around it but if we ever decide to increase ABS_MAX, the
EVIOCSABS ioctl ABI might overflow into the next byte causing horrible
misinterpretations in the kernel that we cannot catch.

Therefore, we decided to go with ABS_MAX2/CNT2 and introduce two new
ioctls to get/set abs-params. They no longer encode the ABS code in the
ioctl number and thus allow up to 4 billion ABS codes.

The new API also allows to query multiple ABS values with one call. To
allow EVIOCSABS2(code = 0, cnt = ABS_CNT2) we need to silently ignore
writes to ABS_MT_SLOT. Other than that, semantics are the same as for the
legacy API.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-debug.c                  |  2 +-
 drivers/hid/hid-input.c                  |  2 +-
 drivers/input/evdev.c                    | 88 +++++++++++++++++++++++++++++++-
 drivers/input/input.c                    | 14 ++---
 drivers/input/keyboard/goldfish_events.c |  6 +--
 drivers/input/keyboard/hil_kbd.c         |  2 +-
 drivers/input/misc/uinput.c              |  6 +--
 include/linux/hid.h                      |  2 +-
 include/linux/input.h                    |  6 +--
 include/uapi/linux/input.h               | 37 +++++++++++++-
 include/uapi/linux/uinput.h              |  2 +-
 11 files changed, 144 insertions(+), 23 deletions(-)

diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 8453214..d32fa30 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -862,7 +862,7 @@ static const char *relatives[REL_MAX + 1] = {
 	[REL_WHEEL] = "Wheel",		[REL_MISC] = "Misc",
 };
 
-static const char *absolutes[ABS_CNT] = {
+static const char *absolutes[ABS_CNT2] = {
 	[ABS_X] = "X",			[ABS_Y] = "Y",
 	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
 	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d97f232..a02721c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1300,7 +1300,7 @@ static bool hidinput_has_been_populated(struct hid_input *hidinput)
 	for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
 		r |= hidinput->input->relbit[i];
 
-	for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
+	for (i = 0; i < BITS_TO_LONGS(ABS_CNT2); i++)
 		r |= hidinput->input->absbit[i];
 
 	for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index b6ded17..ffe65fd 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -635,7 +635,7 @@ static int handle_eviocgbit(struct input_dev *dev,
 	case      0: bits = dev->evbit;  len = EV_MAX;  break;
 	case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
 	case EV_REL: bits = dev->relbit; len = REL_MAX; break;
-	case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+	case EV_ABS: bits = dev->absbit; len = ABS_MAX2; break;
 	case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
 	case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 	case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
@@ -663,6 +663,86 @@ static int handle_eviocgbit(struct input_dev *dev,
 }
 #undef OLD_KEY_MAX
 
+static int evdev_handle_get_abs2(struct input_dev *dev, void __user *p)
+{
+	u32 code, cnt, i;
+	struct input_absinfo2 __user *pinfo = p;
+	struct input_absinfo abs;
+
+	if (!dev->absinfo)
+		return -EINVAL;
+
+	if (copy_from_user(&code, &pinfo->code, sizeof(code)))
+		return -EFAULT;
+	if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
+		return -EFAULT;
+
+	if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
+		return -EINVAL;
+	if (code + cnt > ABS_MAX2)
+		return -EINVAL;
+
+	for (i = 0; i < cnt; ++i) {
+		/*
+		 * Take event lock to ensure that we are not
+		 * copying data while EVIOCSABS2 changes it.
+		 * Might be inconsistent, otherwise.
+		 */
+		spin_lock_irq(&dev->event_lock);
+		abs = dev->absinfo[code + i];
+		spin_unlock_irq(&dev->event_lock);
+
+		if (copy_to_user(&pinfo->info[i], &abs, sizeof(abs)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int evdev_handle_set_abs2(struct input_dev *dev, void __user *p)
+{
+	struct input_absinfo2 __user *pinfo = p;
+	struct input_absinfo *abs;
+	u32 code, cnt, i;
+	size_t size;
+
+	if (!dev->absinfo)
+		return -EINVAL;
+
+	if (copy_from_user(&code, &pinfo->code, sizeof(code)))
+		return -EFAULT;
+	if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
+		return -EFAULT;
+
+	if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
+		return -EINVAL;
+	if (code + cnt > ABS_MAX2)
+		return -EINVAL;
+
+	size = cnt * sizeof(*abs);
+	abs = memdup_user(&pinfo->info[0], size);
+	if (IS_ERR(abs))
+		return PTR_ERR(abs);
+
+	/*
+	 * Take event lock to ensure that we are not
+	 * changing device parameters in the middle
+	 * of event.
+	 */
+	spin_lock_irq(&dev->event_lock);
+	for (i = 0; i < cnt; ++i) {
+		/* silently drop ABS_MT_SLOT */
+		if (code + i == ABS_MT_SLOT)
+			continue;
+
+		dev->absinfo[code + i] = abs[i];
+	}
+	spin_unlock_irq(&dev->event_lock);
+
+	kfree(abs);
+	return 0;
+}
+
 static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
 {
 	struct input_keymap_entry ke = {
@@ -890,6 +970,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 		client->clkid = i;
 		return 0;
 
+	case EVIOCGABS2:
+		return evdev_handle_get_abs2(dev, p);
+
+	case EVIOCSABS2:
+		return evdev_handle_set_abs2(dev, p);
+
 	case EVIOCGKEYCODE:
 		return evdev_handle_get_keycode(dev, p);
 
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c044699..bc88f17 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -305,7 +305,7 @@ static int input_get_disposition(struct input_dev *dev,
 		break;
 
 	case EV_ABS:
-		if (is_event_supported(code, dev->absbit, ABS_MAX))
+		if (is_event_supported(code, dev->absbit, ABS_MAX2))
 			disposition = input_handle_abs_event(dev, code, &value);
 
 		break;
@@ -474,7 +474,7 @@ EXPORT_SYMBOL(input_inject_event);
 void input_alloc_absinfo(struct input_dev *dev)
 {
 	if (!dev->absinfo)
-		dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo),
+		dev->absinfo = kcalloc(ABS_CNT2, sizeof(struct input_absinfo),
 					GFP_KERNEL);
 
 	WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
@@ -954,7 +954,7 @@ static const struct input_device_id *input_match_device(struct input_handler *ha
 		if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
 			continue;
 
-		if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
+		if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX2))
 			continue;
 
 		if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
@@ -1147,7 +1147,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
 	if (test_bit(EV_REL, dev->evbit))
 		input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
 	if (test_bit(EV_ABS, dev->evbit))
-		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
+		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX2);
 	if (test_bit(EV_MSC, dev->evbit))
 		input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
 	if (test_bit(EV_LED, dev->evbit))
@@ -1333,7 +1333,7 @@ static int input_print_modalias(char *buf, int size, struct input_dev *id,
 	len += input_print_modalias_bits(buf + len, size - len,
 				'r', id->relbit, 0, REL_MAX);
 	len += input_print_modalias_bits(buf + len, size - len,
-				'a', id->absbit, 0, ABS_MAX);
+				'a', id->absbit, 0, ABS_MAX2);
 	len += input_print_modalias_bits(buf + len, size - len,
 				'm', id->mscbit, 0, MSC_MAX);
 	len += input_print_modalias_bits(buf + len, size - len,
@@ -1592,7 +1592,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 	if (test_bit(EV_REL, dev->evbit))
 		INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX);
 	if (test_bit(EV_ABS, dev->evbit))
-		INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX);
+		INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX2);
 	if (test_bit(EV_MSC, dev->evbit))
 		INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX);
 	if (test_bit(EV_LED, dev->evbit))
@@ -1924,7 +1924,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
 
 	events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */
 
-	for (i = 0; i < ABS_CNT; i++) {
+	for (i = 0; i < ABS_CNT2; i++) {
 		if (test_bit(i, dev->absbit)) {
 			if (input_is_mt_axis(i))
 				events += mt_slots;
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
index 9f60a2e..9999cea 100644
--- a/drivers/input/keyboard/goldfish_events.c
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -90,8 +90,8 @@ static void events_import_abs_params(struct event_dev *edev)
 	__raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
 
 	count = __raw_readl(addr + REG_LEN) / sizeof(val);
-	if (count > ABS_MAX)
-		count = ABS_MAX;
+	if (count > ABS_MAX2)
+		count = ABS_MAX2;
 
 	for (i = 0; i < count; i++) {
 		if (!test_bit(i, input_dev->absbit))
@@ -158,7 +158,7 @@ static int events_probe(struct platform_device *pdev)
 	events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
 	events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
 	events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
-	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
+	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX2);
 	events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
 	events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
 	events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 589e3c2..4e4e010 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -387,7 +387,7 @@ static void hil_dev_pointer_setup(struct hil_dev *ptr)
 					0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
 
 #ifdef TABLET_AUTOADJUST
-		for (i = 0; i < ABS_MAX; i++) {
+		for (i = 0; i < ABS_MAX2; i++) {
 			int diff = input_abs_get_max(input_dev, ABS_X + i) / 10;
 			input_abs_set_min(input_dev, ABS_X + i,
 				input_abs_get_min(input_dev, ABS_X + i) + diff);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 3cd84d2..2f7355e 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -311,7 +311,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
 	unsigned int cnt;
 	int retval = 0;
 
-	for (cnt = 0; cnt < ABS_CNT; cnt++) {
+	for (cnt = 0; cnt < ABS_CNT2; cnt++) {
 		int min, max;
 		if (!test_bit(cnt, dev->absbit))
 			continue;
@@ -474,7 +474,7 @@ static int uinput_setup_device2(struct uinput_device *udev,
 		return -EINVAL;
 
 	/* rough check to avoid huge kernel space allocations */
-	max = ABS_CNT * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
+	max = ABS_CNT2 * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
 	if (count > max)
 		return -EINVAL;
 
@@ -770,7 +770,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 			break;
 
 		case UI_SET_ABSBIT:
-			retval = uinput_set_bit(arg, absbit, ABS_MAX);
+			retval = uinput_set_bit(arg, absbit, ABS_MAX2);
 			break;
 
 		case UI_SET_MSCBIT:
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 31b9d29..c21d8bb 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -828,7 +828,7 @@ static inline void hid_map_usage(struct hid_input *hidinput,
 	switch (type) {
 	case EV_ABS:
 		*bit = input->absbit;
-		*max = ABS_MAX;
+		*max = ABS_MAX2;
 		break;
 	case EV_REL:
 		*bit = input->relbit;
diff --git a/include/linux/input.h b/include/linux/input.h
index 82ce323..c6add6f 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -129,7 +129,7 @@ struct input_dev {
 	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
 	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
 	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
-	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
+	unsigned long absbit[BITS_TO_LONGS(ABS_CNT2)];
 	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
 	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
 	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
@@ -210,8 +210,8 @@ struct input_dev {
 #error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match"
 #endif
 
-#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX
-#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match"
+#if ABS_MAX2 != INPUT_DEVICE_ID_ABS_MAX
+#error "ABS_MAX2 and INPUT_DEVICE_ID_ABS_MAX do not match"
 #endif
 
 #if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index a372627..9e525f9 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -74,6 +74,27 @@ struct input_absinfo {
 };
 
 /**
+ * struct input_absinfo2 - used by EVIOC[G/S]ABS2 ioctls
+ * @code: First ABS code to query
+ * @cnt: Number of ABS codes to query starting at @code
+ * @info: #@cnt absinfo structures to get/set abs parameters for all codes
+ *
+ * This structure is used by the new EVIOC[G/S]ABS2 ioctls which
+ * do the same as the old EVIOC[G/S]ABS ioctls but avoid encoding
+ * the ABS code in the ioctl number. This allows a much wider
+ * range of ABS codes. Furthermore, it allows to query multiple codes with a
+ * single call.
+ *
+ * Note that this silently drops any requests to set ABS_MT_SLOT. Hence, it is
+ * allowed to call this with code=0 cnt=ABS_CNT2.
+ */
+struct input_absinfo2 {
+	__u32 code;
+	__u32 cnt;
+	struct input_absinfo info[1];
+};
+
+/**
  * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
  * @scancode: scancode represented in machine-endian form.
  * @len: length of the scancode that resides in @scancode buffer.
@@ -153,6 +174,8 @@ struct input_keymap_entry {
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 #define EVIOCREVOKE		_IOW('E', 0x91, int)			/* Revoke device access */
+#define EVIOCGABS2		_IOR('E', 0x92, struct input_absinfo2)	/* get abs value/limits */
+#define EVIOCSABS2		_IOW('E', 0x93, struct input_absinfo2)	/* set abs value/limits */
 
 #define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */
 
@@ -832,11 +855,23 @@ struct input_keymap_entry {
 #define ABS_MT_TOOL_X		0x3c	/* Center X tool position */
 #define ABS_MT_TOOL_Y		0x3d	/* Center Y tool position */
 
-
+/*
+ * ABS_MAX/CNT is limited to a maximum of 0x3f due to the design of EVIOCGABS
+ * and EVIOCSABS ioctls. Other kernel APIs like uinput also hardcoded it. Do
+ * not modify this value and instead use the extended ABS_MAX2/CNT2 API.
+ */
 #define ABS_MAX			0x3f
 #define ABS_CNT			(ABS_MAX+1)
 
 /*
+ * Due to API restrictions the legacy evdev API only supports ABS values up to
+ * ABS_MAX/CNT. Use the extended *ABS2 ioctls to operate on any ABS values in
+ * between ABS_MAX and ABS_MAX2.
+ */
+#define ABS_MAX2		0x3f
+#define ABS_CNT2		(ABS_MAX2+1)
+
+/*
  * Switch events
  */
 
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index c2e8710..27ee521 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -140,7 +140,7 @@ struct uinput_user_dev2 {
 	char name[UINPUT_MAX_NAME_SIZE];
 	struct input_id id;
 	__u32 ff_effects_max;
-	struct input_absinfo abs[ABS_CNT];
+	struct input_absinfo abs[ABS_CNT2];
 };
 
 #endif /* _UAPI__UINPUT_H_ */
-- 
1.8.4.1


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

* [PATCH 03/13] Input: remove ambigious gamepad comment
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
  2013-11-01 20:16 ` [PATCH 01/13] Input: uinput: add full absinfo support David Herrmann
  2013-11-01 20:16 ` [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs David Herrmann
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

If only a single trigger combination is present on a device, either can be
reported. If the side of the trigger (left/right) cannot be decided (eg.,
if it's centered), then choose any side. User-space automatically notices
that only a single trigger is reported and thus doesn't care how it is
reported.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 Documentation/input/gamepad.txt | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt
index 8002c89..c40b109 100644
--- a/Documentation/input/gamepad.txt
+++ b/Documentation/input/gamepad.txt
@@ -136,8 +136,6 @@ Triggers:
   Upper trigger buttons are reported as BTN_TR or ABS_HAT1X (right) and BTN_TL
   or ABS_HAT1Y (left). Lower trigger buttons are reported as BTN_TR2 or
   ABS_HAT2X (right/ZR) and BTN_TL2 or ABS_HAT2Y (left/ZL).
-  If only one trigger-button combination is present (upper+lower), they are
-  reported as "right" triggers (BTN_TR/ABS_HAT1X).
 
 Menu-Pad:
   Menu buttons are always digital and are mapped according to their location
-- 
1.8.4.1


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

* [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (2 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 03/13] Input: remove ambigious gamepad comment David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-15 10:11   ` Antonio Ospite
  2013-11-01 20:16 ` [PATCH 05/13] HID: wiimote: add hid_wiimote.legacy parameter David Herrmann
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Motion sensors are getting quite common in mobile devices. To avoid
returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
mouse-driver, this adds separate ABS_* bits for that.

This is needed if gaming devices want to report their normal data plus
accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
sticks, so need separate definitions, anyway.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 Documentation/input/gamepad.txt         |   7 ++
 Documentation/input/motion-tracking.txt | 149 ++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h         |   2 +-
 include/uapi/linux/input.h              |   9 +-
 4 files changed, 165 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/input/motion-tracking.txt

diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt
index c40b109..bd168c0 100644
--- a/Documentation/input/gamepad.txt
+++ b/Documentation/input/gamepad.txt
@@ -57,6 +57,9 @@ Most gamepads have the following features:
   - Rumble
     Many devices provide force-feedback features. But are mostly just
     simple rumble motors.
+  - Motion-tracking
+    Gamepads may include motion-tracking sensors like accelerometers and
+    gyroscopes.
 
 3. Detection
 ~~~~~~~~~~~~
@@ -150,5 +153,9 @@ Menu-Pad:
 Rumble:
   Rumble is adverticed as FF_RUMBLE.
 
+Motion-tracking:
+  Motion-tracking is defined in ./Documentation/input/motion-tracking.txt and
+  gamepads shall comply to the rules defined there.
+
 ----------------------------------------------------------------------------
   Written 2013 by David Herrmann <dh.herrmann@gmail.com>
diff --git a/Documentation/input/motion-tracking.txt b/Documentation/input/motion-tracking.txt
new file mode 100644
index 0000000..0885c9a
--- /dev/null
+++ b/Documentation/input/motion-tracking.txt
@@ -0,0 +1,149 @@
+                           Motion Tracking API
+----------------------------------------------------------------------------
+
+1. Intro
+~~~~~~~~
+Motion tracking devices produce device motion events generated from an
+accelerometer, gyroscope or compass. This data can be returned to user-space
+via input events. This document defines how this data is reported.
+
+2. Devices
+~~~~~~~~~~
+In this document, a "device" is one of:
+ - accelerometer
+ - gyroscope
+ - compass
+
+These devices returned their information via different APIs in the past. To
+unify them and define a common API, a set of input evdev codes was created. Old
+drivers might continue using their API, but developers are encouraged to use
+the input evdev API for new drivers.
+
+2.1 Axes
+~~~~~~~~
+Movement data is usually returned as absolute data for the 3 axes of a device.
+In this context, the three axes are defined as:
+ - X: Axis goes from the left to the right side of the device
+ - Y: Axis goes from the bottom to the top of the device
+ - Z: Axis goes from the back to the front of the device
+
+The front of a device is the side faced to the user. For a mobile-phone it
+would be the screen. For devices without a screen, the front is usually the
+side with the most buttons on it.
+
+                           Example: Mobile-Phone
+  +-------------------------------------------------------------------------+
+  |                      TOP                                                |
+  |                                                                         |
+  |                                                                         |
+  |          +---------------------------+                                  |
+  |          |\  ________________________ \      .__                        |
+  |          \ \ \                       \ \     |\                         |
+  |           \ \ \              __       \ \      \                   RIGHT|
+  |            \ \ \              /|       \ \      \__                     |
+  |             \ \ \          __/          \ \     |\                      |
+  |              \ \ \          /|           \ \      \ (Y Axis)            |
+  |               \ \ \      __/  (Z axis)    \ \      \__                  |
+  |                \ \ \      /|               \ \     |\                   |
+  | LEFT            \ \ \    /                  \ \      \                  |
+  |                  \ \ \         FRONT         \ \      \                 |
+  |                   \ \ \                       \ \                       |
+  |                    \ \ \_______________________\ \                      |
+  |                     \ \             ___           \                     |
+  |                     /\ \            \__\           \                    |
+  |                  __/  \ +---------------------------+                   |
+  |                   /|   \|___________________________|                   |
+  |                  / BACK                                                 |
+  |                                      (X axis)                           |
+  |                        ------->------->------->------->                 |
+  |                                                                         |
+  |                                                                         |
+  |                                         BOTTOM                          |
+  +-------------------------------------------------------------------------+
+
+Rotation-data is reported as clock-wise rotation on an axis. For a given axes,
+the reported rotation would be:
+                                          ___
+                                            /|
+                                           / | (axis)
+                                          /
+                                    .-**-.
+                                   /    / \
+                                  |    / \ | /
+                                   \  /   \|/  (clock-wise rotation)
+                                     /
+                                    /
+                                   /
+
+2.2 Calibration
+~~~~~~~~~~~~~~~
+Motion sensors are often highly sensitive and need precise calibration. Users
+are adviced to perform neutral-point calibration themselves or to implement a
+state-machine to normalize input data automatically.
+
+Kernel devices may perform their own calibration and/or normalization. However,
+this is usually sparse and, if implemented, transparent to the user.
+
+There is currently no way to feed calibration data into the kernel in a generic
+way. Proposals welcome!
+
+2.3 Units
+~~~~~~~~~
+(NOTE: This section describes an experimental API. Currently, no device complies
+to these rules so this might change in the future.)
+
+Reported data shall be returned as:
+ - Acceleration: 1/1000 m per s^2
+ - Rotation: 1/1000 degree per second
+
+However, for most devices the reported units are unknown (more precisely: no
+one has the time to measure them and figure them out). Therefore, user-space
+shall use abs-minimum and abs-maximum to calculate relative data and use that
+instead. Devices which return wrong units may be fixed in the future to comply
+to these rules.
+
+3.1 Accelerometer
+~~~~~~~~~~~~~~~~~
+Accelerometers measure movement acceleration of devices. Any combination of the
+three available axes can be used. Usually, all three are supported.
+
+Data is provided as absolute acceleration. A positive integer defines the
+acceleration in the direction of an axis. A negative integer defines
+acceleration in the opposite direction.
+
+The evdev ABS codes used are:
+ - ABS_ACCEL_X: X axis
+ - ABS_ACCEL_Y: Y axis
+ - ABS_ACCEL_Z: Z axis
+
+3.2 Gyroscope
+~~~~~~~~~~~~~
+A gyroscope measures rotational speed (*not* acceleration!). Any combination of
+the three available axes can be used. Usually, all three are supported.
+
+Data is provided as absolute speed. A positive integer defines the rotational
+speed in clock-wise order around a given axis. A negative integer defines it in
+counter-clock-wise order.
+
+The evdev ABS codes used are:
+ - ABS_GYRO_X: X axis (also: Pitch)
+ - ABS_GYRO_Y: Y axis (also: Roll)
+ - ABS_GYRO_Z: Z axis (also: Azimuth/Yaw)
+
+3.3 Compass
+~~~~~~~~~~~
+(NOTE: No compass device currently uses the evdev input subsystem. Thus, this
+API is only a proposal, it hasn't been implemented, yet.)
+
+A compass measures the ambient magnetic field of the three defined axes. This
+makes the data self-contained and independent of the current device position.
+Any combination of the three axes can be used. Usually all three are supported,
+otherwise, it's not really useful as a compass.
+
+Proposed evdev ABS codes are:
+ - ABS_COMPASS_X: X axis
+ - ABS_COMPASS_Y: Y axis
+ - ABS_COMPASS_Z: Z axis
+
+----------------------------------------------------------------------------
+  Written 2013 by David Herrmann <dh.herrmann@gmail.com>
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 45e9214..329aa30 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -277,7 +277,7 @@ struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING	0x71
 #define INPUT_DEVICE_ID_KEY_MAX		0x2ff
 #define INPUT_DEVICE_ID_REL_MAX		0x0f
-#define INPUT_DEVICE_ID_ABS_MAX		0x3f
+#define INPUT_DEVICE_ID_ABS_MAX		0x4f
 #define INPUT_DEVICE_ID_MSC_MAX		0x07
 #define INPUT_DEVICE_ID_LED_MAX		0x0f
 #define INPUT_DEVICE_ID_SND_MAX		0x07
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 9e525f9..f347498 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -863,12 +863,19 @@ struct input_keymap_entry {
 #define ABS_MAX			0x3f
 #define ABS_CNT			(ABS_MAX+1)
 
+#define ABS_ACCEL_X		0x40	/* Accelerometer X axis */
+#define ABS_ACCEL_Y		0x41	/* Accelerometer Y axis */
+#define ABS_ACCEL_Z		0x42	/* Accelerometer Z axis */
+#define ABS_GYRO_X		0x43	/* Gyroscope X axis */
+#define ABS_GYRO_Y		0x44	/* Gyroscope Y axis */
+#define ABS_GYRO_Z		0x45	/* Gyroscope Z axis */
+
 /*
  * Due to API restrictions the legacy evdev API only supports ABS values up to
  * ABS_MAX/CNT. Use the extended *ABS2 ioctls to operate on any ABS values in
  * between ABS_MAX and ABS_MAX2.
  */
-#define ABS_MAX2		0x3f
+#define ABS_MAX2		0x4f
 #define ABS_CNT2		(ABS_MAX2+1)
 
 /*
-- 
1.8.4.1


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

* [PATCH 05/13] HID: wiimote: add hid_wiimote.legacy parameter
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (3 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 06/13] HID: wiimote: adjust button-mapping to gamepad rules David Herrmann
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

The first hid-wiimote driver had horrible default mappings which we have
to support now for compatibility reasons. This was no big problem as the
wiimote needs special user-space drivers to really make sense, anyway.

However, there are several wiimote extensions which can be used on their
own (especially the gamepads). To allow new mappings which comply to the
common gamepad rules, we introduce the hid_wiimote.legacy parameter so
users can get the old behavior back, if they need it.

This patch only introduces the module parameter, the following patches
will change the mappings.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-core.c | 9 +++++++++
 drivers/hid/hid-wiimote.h      | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 1446f52..89ca031 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -20,6 +20,9 @@
 #include "hid-ids.h"
 #include "hid-wiimote.h"
 
+/* set to 1 to enable legacy-mode and old reports */
+static unsigned int wiimote_legacy = 0;
+
 /* output queue handling */
 
 static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
@@ -1731,6 +1734,9 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	wdata->hdev = hdev;
 	hid_set_drvdata(hdev, wdata);
 
+	if (wiimote_legacy)
+		wdata->state.flags |= WIIPROTO_FLAG_LEGACY;
+
 	spin_lock_init(&wdata->queue.lock);
 	INIT_WORK(&wdata->queue.worker, wiimote_queue_worker);
 
@@ -1873,6 +1879,9 @@ static struct hid_driver wiimote_hid_driver = {
 };
 module_hid_driver(wiimote_hid_driver);
 
+MODULE_PARM_DESC(legacy, "Enable legacy mode and reports");
+module_param_named(legacy, wiimote_legacy, int, 0600);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
 MODULE_DESCRIPTION("Driver for Nintendo Wii / Wii U peripherals");
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 03065f1..6f70823 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -47,6 +47,7 @@
 #define WIIPROTO_FLAG_BUILTIN_MP	0x010000
 #define WIIPROTO_FLAG_NO_MP		0x020000
 #define WIIPROTO_FLAG_PRO_CALIB_DONE	0x040000
+#define WIIPROTO_FLAG_LEGACY		0x080000
 
 #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
 					WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
-- 
1.8.4.1


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

* [PATCH 06/13] HID: wiimote: adjust button-mapping to gamepad rules
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (4 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 05/13] HID: wiimote: add hid_wiimote.legacy parameter David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 07/13] HID: wiimote: map nunchuk as real gamepad David Herrmann
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Our gamepad API (./Documentation/input/gamepad.txt) clearly defines rules
how to map buttons for gamepads. A wiimote can easily be used as gamepad
and provides most of the features. Unfortunately, the gamepad API didn't
exist when hid-wiimote was written.

This patch changes the button-mappings to comply to gamepad rules. For
compatibility reasons, we keep the old mappings if legacy-mode was
enabled.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-modules.c | 49 ++++++++++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 13 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 6b61f01..372fec1 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -48,7 +48,7 @@
  * It uses the shared input device.
  */
 
-static const __u16 wiimod_keys_map[] = {
+static const __u16 wiimod_keys_map_legacy[] = {
 	KEY_LEFT,	/* WIIPROTO_KEY_LEFT */
 	KEY_RIGHT,	/* WIIPROTO_KEY_RIGHT */
 	KEY_UP,		/* WIIPROTO_KEY_UP */
@@ -62,29 +62,48 @@ static const __u16 wiimod_keys_map[] = {
 	BTN_MODE,	/* WIIPROTO_KEY_HOME */
 };
 
+static const __u16 wiimod_keys_map[] = {
+	BTN_DPAD_LEFT,		/* WIIPROTO_KEY_LEFT */
+	BTN_DPAD_RIGHT,		/* WIIPROTO_KEY_RIGHT */
+	BTN_DPAD_UP,		/* WIIPROTO_KEY_UP */
+	BTN_DPAD_DOWN,		/* WIIPROTO_KEY_DOWN */
+	BTN_START,		/* WIIPROTO_KEY_PLUS */
+	BTN_SELECT,		/* WIIPROTO_KEY_MINUS */
+	BTN_TRIGGER_HAPPY1,	/* WIIPROTO_KEY_ONE */
+	BTN_TRIGGER_HAPPY2,	/* WIIPROTO_KEY_TWO */
+	BTN_SOUTH,		/* WIIPROTO_KEY_A */
+	BTN_TR,			/* WIIPROTO_KEY_B */
+	BTN_MODE,		/* WIIPROTO_KEY_HOME */
+};
+
 static void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys)
 {
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT],
+	const __u16 *map = wiimod_keys_map;
+
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_keys_map_legacy;
+
+	input_report_key(wdata->input, map[WIIPROTO_KEY_LEFT],
 							!!(keys[0] & 0x01));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_RIGHT],
 							!!(keys[0] & 0x02));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_DOWN],
 							!!(keys[0] & 0x04));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_UP],
 							!!(keys[0] & 0x08));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_PLUS],
 							!!(keys[0] & 0x10));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_TWO],
 							!!(keys[1] & 0x01));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_ONE],
 							!!(keys[1] & 0x02));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_B],
 							!!(keys[1] & 0x04));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_A],
 							!!(keys[1] & 0x08));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_MINUS],
 							!!(keys[1] & 0x10));
-	input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME],
+	input_report_key(wdata->input, map[WIIPROTO_KEY_HOME],
 							!!(keys[1] & 0x80));
 	input_sync(wdata->input);
 }
@@ -92,11 +111,15 @@ static void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys)
 static int wiimod_keys_probe(const struct wiimod_ops *ops,
 			     struct wiimote_data *wdata)
 {
+	const __u16 *map = wiimod_keys_map;
 	unsigned int i;
 
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_keys_map_legacy;
+
 	set_bit(EV_KEY, wdata->input->evbit);
 	for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
-		set_bit(wiimod_keys_map[i], wdata->input->keybit);
+		set_bit(map[i], wdata->input->keybit);
 
 	return 0;
 }
-- 
1.8.4.1


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

* [PATCH 07/13] HID: wiimote: map nunchuk as real gamepad
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (5 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 06/13] HID: wiimote: adjust button-mapping to gamepad rules David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 08/13] HID: wiimote: map classic controller as gamepad David Herrmann
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

The nunchuk device can easily be used as reduced gamepad. Add a new
mapping according to linux gamepad rules.

Note that we map it as gamepad with:
 - one analog-stick (left)
 - two trigger buttons (left upper+lower)
 - accelerometer

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-modules.c | 94 ++++++++++++++++++++++++++++-----------
 1 file changed, 67 insertions(+), 27 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 372fec1..a02059c 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -839,15 +839,24 @@ enum wiimod_nunchuk_keys {
 	WIIMOD_NUNCHUK_KEY_NUM,
 };
 
-static const __u16 wiimod_nunchuk_map[] = {
+static const __u16 wiimod_nunchuk_map_legacy[] = {
 	BTN_C,		/* WIIMOD_NUNCHUK_KEY_C */
 	BTN_Z,		/* WIIMOD_NUNCHUK_KEY_Z */
 };
 
+static const __u16 wiimod_nunchuk_map[] = {
+	BTN_TL,		/* WIIMOD_NUNCHUK_KEY_C */
+	BTN_TL2,	/* WIIMOD_NUNCHUK_KEY_Z */
+};
+
 static void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 {
+	const __u16 *map = wiimod_nunchuk_map;
 	__s16 x, y, z, bx, by;
 
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_nunchuk_map_legacy;
+
 	/*   Byte |   8    7 |  6    5 |  4    3 |  2 |  1  |
 	 *   -----+----------+---------+---------+----+-----+
 	 *    1   |              Button X <7:0>             |
@@ -902,26 +911,35 @@ static void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 	y -= 0x200;
 	z -= 0x200;
 
-	input_report_abs(wdata->extension.input, ABS_HAT0X, bx);
-	input_report_abs(wdata->extension.input, ABS_HAT0Y, by);
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		input_report_abs(wdata->extension.input, ABS_HAT0X, bx);
+		input_report_abs(wdata->extension.input, ABS_HAT0Y, by);
 
-	input_report_abs(wdata->extension.input, ABS_RX, x);
-	input_report_abs(wdata->extension.input, ABS_RY, y);
-	input_report_abs(wdata->extension.input, ABS_RZ, z);
+		input_report_abs(wdata->extension.input, ABS_RX, x);
+		input_report_abs(wdata->extension.input, ABS_RY, y);
+		input_report_abs(wdata->extension.input, ABS_RZ, z);
+	} else {
+		input_report_abs(wdata->extension.input, ABS_X, bx);
+		input_report_abs(wdata->extension.input, ABS_Y, -by);
+
+		input_report_abs(wdata->extension.input, ABS_ACCEL_X, x);
+		input_report_abs(wdata->extension.input, ABS_ACCEL_Y, y);
+		input_report_abs(wdata->extension.input, ABS_ACCEL_Z, z);
+	}
 
 	if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
 		input_report_key(wdata->extension.input,
-			wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
+			map[WIIMOD_NUNCHUK_KEY_Z],
 			!(ext[5] & 0x04));
 		input_report_key(wdata->extension.input,
-			wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
+			map[WIIMOD_NUNCHUK_KEY_C],
 			!(ext[5] & 0x08));
 	} else {
 		input_report_key(wdata->extension.input,
-			wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
+			map[WIIMOD_NUNCHUK_KEY_Z],
 			!(ext[5] & 0x01));
 		input_report_key(wdata->extension.input,
-			wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
+			map[WIIMOD_NUNCHUK_KEY_C],
 			!(ext[5] & 0x02));
 	}
 
@@ -955,12 +973,16 @@ static void wiimod_nunchuk_close(struct input_dev *dev)
 static int wiimod_nunchuk_probe(const struct wiimod_ops *ops,
 				struct wiimote_data *wdata)
 {
+	const __u16 *map = wiimod_nunchuk_map;
 	int ret, i;
 
 	wdata->extension.input = input_allocate_device();
 	if (!wdata->extension.input)
 		return -ENOMEM;
 
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_nunchuk_map_legacy;
+
 	input_set_drvdata(wdata->extension.input, wdata);
 	wdata->extension.input->open = wiimod_nunchuk_open;
 	wdata->extension.input->close = wiimod_nunchuk_close;
@@ -973,25 +995,43 @@ static int wiimod_nunchuk_probe(const struct wiimod_ops *ops,
 
 	set_bit(EV_KEY, wdata->extension.input->evbit);
 	for (i = 0; i < WIIMOD_NUNCHUK_KEY_NUM; ++i)
-		set_bit(wiimod_nunchuk_map[i],
-			wdata->extension.input->keybit);
+		set_bit(map[i], wdata->extension.input->keybit);
 
 	set_bit(EV_ABS, wdata->extension.input->evbit);
-	set_bit(ABS_HAT0X, wdata->extension.input->absbit);
-	set_bit(ABS_HAT0Y, wdata->extension.input->absbit);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT0X, -120, 120, 2, 4);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT0Y, -120, 120, 2, 4);
-	set_bit(ABS_RX, wdata->extension.input->absbit);
-	set_bit(ABS_RY, wdata->extension.input->absbit);
-	set_bit(ABS_RZ, wdata->extension.input->absbit);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_RX, -500, 500, 2, 4);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_RY, -500, 500, 2, 4);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_RZ, -500, 500, 2, 4);
+
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		set_bit(ABS_HAT0X, wdata->extension.input->absbit);
+		set_bit(ABS_HAT0Y, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT0X, -120, 120, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT0Y, -120, 120, 2, 4);
+		set_bit(ABS_RX, wdata->extension.input->absbit);
+		set_bit(ABS_RY, wdata->extension.input->absbit);
+		set_bit(ABS_RZ, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_RX, -500, 500, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_RY, -500, 500, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_RZ, -500, 500, 2, 4);
+	} else {
+		set_bit(ABS_X, wdata->extension.input->absbit);
+		set_bit(ABS_Y, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_X, -120, 120, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_Y, -120, 120, 2, 4);
+		set_bit(ABS_ACCEL_X, wdata->extension.input->absbit);
+		set_bit(ABS_ACCEL_Y, wdata->extension.input->absbit);
+		set_bit(ABS_ACCEL_Z, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_ACCEL_X, -500, 500, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_ACCEL_Y, -500, 500, 2, 4);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_ACCEL_Z, -500, 500, 2, 4);
+	}
 
 	ret = input_register_device(wdata->extension.input);
 	if (ret)
-- 
1.8.4.1


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

* [PATCH 08/13] HID: wiimote: map classic controller as gamepad
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (6 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 07/13] HID: wiimote: map nunchuk as real gamepad David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 09/13] HID: wiimote: use ABS_ACCEL_* for accelerometer David Herrmann
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Adjust the mappings for the classic-controller extension so it's reported
as normal gamepad. Keep the compatibility mappings so legacy-mode still
works.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-modules.c | 144 ++++++++++++++++++++++++++------------
 1 file changed, 100 insertions(+), 44 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index a02059c..f3de94e 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -1090,7 +1090,7 @@ enum wiimod_classic_keys {
 	WIIMOD_CLASSIC_KEY_NUM,
 };
 
-static const __u16 wiimod_classic_map[] = {
+static const __u16 wiimod_classic_map_legacy[] = {
 	BTN_A,		/* WIIMOD_CLASSIC_KEY_A */
 	BTN_B,		/* WIIMOD_CLASSIC_KEY_B */
 	BTN_X,		/* WIIMOD_CLASSIC_KEY_X */
@@ -1108,10 +1108,32 @@ static const __u16 wiimod_classic_map[] = {
 	BTN_TR,		/* WIIMOD_CLASSIC_KEY_RT */
 };
 
+static const __u16 wiimod_classic_map[] = {
+	BTN_EAST,		/* WIIMOD_CLASSIC_KEY_A */
+	BTN_SOUTH,		/* WIIMOD_CLASSIC_KEY_B */
+	BTN_NORTH,		/* WIIMOD_CLASSIC_KEY_X */
+	BTN_WEST,		/* WIIMOD_CLASSIC_KEY_Y */
+	BTN_TL2,		/* WIIMOD_CLASSIC_KEY_ZL */
+	BTN_TR2,		/* WIIMOD_CLASSIC_KEY_ZR */
+	BTN_START,		/* WIIMOD_CLASSIC_KEY_PLUS */
+	BTN_SELECT,		/* WIIMOD_CLASSIC_KEY_MINUS */
+	BTN_MODE,		/* WIIMOD_CLASSIC_KEY_HOME */
+	BTN_DPAD_LEFT,		/* WIIMOD_CLASSIC_KEY_LEFT */
+	BTN_DPAD_RIGHT,		/* WIIMOD_CLASSIC_KEY_RIGHT */
+	BTN_DPAD_UP,		/* WIIMOD_CLASSIC_KEY_UP */
+	BTN_DPAD_DOWN,		/* WIIMOD_CLASSIC_KEY_DOWN */
+	BTN_TL,			/* WIIMOD_CLASSIC_KEY_LT */
+	BTN_TR,			/* WIIMOD_CLASSIC_KEY_RT */
+};
+
 static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 {
+	const __u16 *map = wiimod_classic_map;
 	__s8 rx, ry, lx, ly, lt, rt;
 
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_classic_map_legacy;
+
 	/*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
 	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
 	 *    1   | RX <5:4>  |              LX <5:0>             |
@@ -1177,66 +1199,75 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 	rt <<= 1;
 	lt <<= 1;
 
-	input_report_abs(wdata->extension.input, ABS_HAT1X, lx - 0x20);
-	input_report_abs(wdata->extension.input, ABS_HAT1Y, ly - 0x20);
-	input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20);
-	input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20);
-	input_report_abs(wdata->extension.input, ABS_HAT3X, rt);
-	input_report_abs(wdata->extension.input, ABS_HAT3Y, lt);
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		input_report_abs(wdata->extension.input, ABS_HAT1X, lx - 0x20);
+		input_report_abs(wdata->extension.input, ABS_HAT1Y, ly - 0x20);
+		input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20);
+		input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20);
+		input_report_abs(wdata->extension.input, ABS_HAT3X, rt);
+		input_report_abs(wdata->extension.input, ABS_HAT3Y, lt);
+	} else {
+		input_report_abs(wdata->extension.input, ABS_X, lx - 0x20);
+		input_report_abs(wdata->extension.input, ABS_Y, 0x20 - ly);
+		input_report_abs(wdata->extension.input, ABS_RX, rx - 0x20);
+		input_report_abs(wdata->extension.input, ABS_RY, 0x20 - ry);
+		input_report_abs(wdata->extension.input, ABS_HAT1X, rt);
+		input_report_abs(wdata->extension.input, ABS_HAT1Y, lt);
+	}
 
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT],
+			 map[WIIMOD_CLASSIC_KEY_RIGHT],
 			 !(ext[4] & 0x80));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN],
+			 map[WIIMOD_CLASSIC_KEY_DOWN],
 			 !(ext[4] & 0x40));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT],
+			 map[WIIMOD_CLASSIC_KEY_LT],
 			 !(ext[4] & 0x20));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_MINUS],
+			 map[WIIMOD_CLASSIC_KEY_MINUS],
 			 !(ext[4] & 0x10));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_HOME],
+			 map[WIIMOD_CLASSIC_KEY_HOME],
 			 !(ext[4] & 0x08));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_PLUS],
+			 map[WIIMOD_CLASSIC_KEY_PLUS],
 			 !(ext[4] & 0x04));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_RT],
+			 map[WIIMOD_CLASSIC_KEY_RT],
 			 !(ext[4] & 0x02));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZL],
+			 map[WIIMOD_CLASSIC_KEY_ZL],
 			 !(ext[5] & 0x80));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_B],
+			 map[WIIMOD_CLASSIC_KEY_B],
 			 !(ext[5] & 0x40));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_Y],
+			 map[WIIMOD_CLASSIC_KEY_Y],
 			 !(ext[5] & 0x20));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_A],
+			 map[WIIMOD_CLASSIC_KEY_A],
 			 !(ext[5] & 0x10));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_X],
+			 map[WIIMOD_CLASSIC_KEY_X],
 			 !(ext[5] & 0x08));
 	input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR],
+			 map[WIIMOD_CLASSIC_KEY_ZR],
 			 !(ext[5] & 0x04));
 
 	if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
 		input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
+			 map[WIIMOD_CLASSIC_KEY_LEFT],
 			 !(ext[1] & 0x01));
 		input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
+			 map[WIIMOD_CLASSIC_KEY_UP],
 			 !(ext[0] & 0x01));
 	} else {
 		input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
+			 map[WIIMOD_CLASSIC_KEY_LEFT],
 			 !(ext[5] & 0x02));
 		input_report_key(wdata->extension.input,
-			 wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
+			 map[WIIMOD_CLASSIC_KEY_UP],
 			 !(ext[5] & 0x01));
 	}
 
@@ -1270,12 +1301,16 @@ static void wiimod_classic_close(struct input_dev *dev)
 static int wiimod_classic_probe(const struct wiimod_ops *ops,
 				struct wiimote_data *wdata)
 {
+	const __u16 *map = wiimod_classic_map;
 	int ret, i;
 
 	wdata->extension.input = input_allocate_device();
 	if (!wdata->extension.input)
 		return -ENOMEM;
 
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY)
+		map = wiimod_classic_map_legacy;
+
 	input_set_drvdata(wdata->extension.input, wdata);
 	wdata->extension.input->open = wiimod_classic_open;
 	wdata->extension.input->close = wiimod_classic_close;
@@ -1288,28 +1323,49 @@ static int wiimod_classic_probe(const struct wiimod_ops *ops,
 
 	set_bit(EV_KEY, wdata->extension.input->evbit);
 	for (i = 0; i < WIIMOD_CLASSIC_KEY_NUM; ++i)
-		set_bit(wiimod_classic_map[i],
-			wdata->extension.input->keybit);
+		set_bit(map[i], wdata->extension.input->keybit);
 
 	set_bit(EV_ABS, wdata->extension.input->evbit);
-	set_bit(ABS_HAT1X, wdata->extension.input->absbit);
-	set_bit(ABS_HAT1Y, wdata->extension.input->absbit);
-	set_bit(ABS_HAT2X, wdata->extension.input->absbit);
-	set_bit(ABS_HAT2Y, wdata->extension.input->absbit);
-	set_bit(ABS_HAT3X, wdata->extension.input->absbit);
-	set_bit(ABS_HAT3Y, wdata->extension.input->absbit);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT1X, -30, 30, 1, 1);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT1Y, -30, 30, 1, 1);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT2X, -30, 30, 1, 1);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT2Y, -30, 30, 1, 1);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT3X, -30, 30, 1, 1);
-	input_set_abs_params(wdata->extension.input,
-			     ABS_HAT3Y, -30, 30, 1, 1);
+
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		set_bit(ABS_HAT1X, wdata->extension.input->absbit);
+		set_bit(ABS_HAT1Y, wdata->extension.input->absbit);
+		set_bit(ABS_HAT2X, wdata->extension.input->absbit);
+		set_bit(ABS_HAT2Y, wdata->extension.input->absbit);
+		set_bit(ABS_HAT3X, wdata->extension.input->absbit);
+		set_bit(ABS_HAT3Y, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT1X, -30, 30, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT1Y, -30, 30, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT2X, -30, 30, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT2Y, -30, 30, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT3X, -30, 30, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT3Y, -30, 30, 1, 1);
+	} else {
+		set_bit(ABS_X, wdata->extension.input->absbit);
+		set_bit(ABS_Y, wdata->extension.input->absbit);
+		set_bit(ABS_RX, wdata->extension.input->absbit);
+		set_bit(ABS_RY, wdata->extension.input->absbit);
+		set_bit(ABS_HAT1X, wdata->extension.input->absbit);
+		set_bit(ABS_HAT1Y, wdata->extension.input->absbit);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_X, -24, 24, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_Y, -24, 24, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_RX, -24, 24, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_RY, -24, 24, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT1X, 0, 52, 1, 1);
+		input_set_abs_params(wdata->extension.input,
+				     ABS_HAT1Y, 0, 52, 1, 1);
+	}
 
 	ret = input_register_device(wdata->extension.input);
 	if (ret)
-- 
1.8.4.1


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

* [PATCH 09/13] HID: wiimote: use ABS_ACCEL_* for accelerometer
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (7 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 08/13] HID: wiimote: map classic controller as gamepad David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 10/13] HID: wiimote: use ABS_GYRO_* bits for MP David Herrmann
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Use the new ABS_ACCEL_* bits for accelerometer data _iff_ legacy mode is
not selected. ABS_R? is confusing and ambigiuous. ABS_ACCEL_* was
introduced exactly for accelerometers like the one of the wiimote.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-modules.c | 38 +++++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index f3de94e..777f932 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -477,9 +477,16 @@ static void wiimod_accel_in_accel(struct wiimote_data *wdata,
 	y |= (accel[1] >> 4) & 0x2;
 	z |= (accel[1] >> 5) & 0x2;
 
-	input_report_abs(wdata->accel, ABS_RX, x - 0x200);
-	input_report_abs(wdata->accel, ABS_RY, y - 0x200);
-	input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		input_report_abs(wdata->accel, ABS_RX, x - 0x200);
+		input_report_abs(wdata->accel, ABS_RY, y - 0x200);
+		input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
+	} else {
+		input_report_abs(wdata->accel, ABS_ACCEL_X, x - 0x200);
+		input_report_abs(wdata->accel, ABS_ACCEL_Y, y - 0x200);
+		input_report_abs(wdata->accel, ABS_ACCEL_Z, z - 0x200);
+	}
+
 	input_sync(wdata->accel);
 }
 
@@ -525,12 +532,25 @@ static int wiimod_accel_probe(const struct wiimod_ops *ops,
 	wdata->accel->name = WIIMOTE_NAME " Accelerometer";
 
 	set_bit(EV_ABS, wdata->accel->evbit);
-	set_bit(ABS_RX, wdata->accel->absbit);
-	set_bit(ABS_RY, wdata->accel->absbit);
-	set_bit(ABS_RZ, wdata->accel->absbit);
-	input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
-	input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
-	input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
+
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		set_bit(ABS_RX, wdata->accel->absbit);
+		set_bit(ABS_RY, wdata->accel->absbit);
+		set_bit(ABS_RZ, wdata->accel->absbit);
+		input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
+		input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
+		input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
+	} else {
+		set_bit(ABS_ACCEL_X, wdata->accel->absbit);
+		set_bit(ABS_ACCEL_Y, wdata->accel->absbit);
+		set_bit(ABS_ACCEL_Z, wdata->accel->absbit);
+		input_set_abs_params(wdata->accel, ABS_ACCEL_X,
+				     -500, 500, 2, 4);
+		input_set_abs_params(wdata->accel, ABS_ACCEL_Y,
+				     -500, 500, 2, 4);
+		input_set_abs_params(wdata->accel, ABS_ACCEL_Z,
+				     -500, 500, 2, 4);
+	}
 
 	ret = input_register_device(wdata->accel);
 	if (ret) {
-- 
1.8.4.1


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

* [PATCH 10/13] HID: wiimote: use ABS_GYRO_* bits for MP
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (8 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 09/13] HID: wiimote: use ABS_ACCEL_* for accelerometer David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 11/13] Input: introduce BTN/ABS bits for drums and guitars David Herrmann
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Use the new gyroscope bits for motion-plus. The used ABS_R? bits are
ambiguous and should be replaced by proper bits to not confuse generic
user-space.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-modules.c | 44 ++++++++++++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 777f932..e51e82b 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -2222,9 +2222,16 @@ static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
 	else
 		z *= 9;
 
-	input_report_abs(wdata->mp, ABS_RX, x);
-	input_report_abs(wdata->mp, ABS_RY, y);
-	input_report_abs(wdata->mp, ABS_RZ, z);
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		input_report_abs(wdata->mp, ABS_RX, x);
+		input_report_abs(wdata->mp, ABS_RY, y);
+		input_report_abs(wdata->mp, ABS_RZ, z);
+	} else {
+		input_report_abs(wdata->mp, ABS_GYRO_X, x);
+		input_report_abs(wdata->mp, ABS_GYRO_Y, y);
+		input_report_abs(wdata->mp, ABS_GYRO_Z, z);
+	}
+
 	input_sync(wdata->mp);
 }
 
@@ -2274,15 +2281,28 @@ static int wiimod_mp_probe(const struct wiimod_ops *ops,
 	wdata->mp->name = WIIMOTE_NAME " Motion Plus";
 
 	set_bit(EV_ABS, wdata->mp->evbit);
-	set_bit(ABS_RX, wdata->mp->absbit);
-	set_bit(ABS_RY, wdata->mp->absbit);
-	set_bit(ABS_RZ, wdata->mp->absbit);
-	input_set_abs_params(wdata->mp,
-			     ABS_RX, -16000, 16000, 4, 8);
-	input_set_abs_params(wdata->mp,
-			     ABS_RY, -16000, 16000, 4, 8);
-	input_set_abs_params(wdata->mp,
-			     ABS_RZ, -16000, 16000, 4, 8);
+
+	if (wdata->state.flags & WIIPROTO_FLAG_LEGACY) {
+		set_bit(ABS_RX, wdata->mp->absbit);
+		set_bit(ABS_RY, wdata->mp->absbit);
+		set_bit(ABS_RZ, wdata->mp->absbit);
+		input_set_abs_params(wdata->mp,
+				     ABS_RX, -16000, 16000, 4, 8);
+		input_set_abs_params(wdata->mp,
+				     ABS_RY, -16000, 16000, 4, 8);
+		input_set_abs_params(wdata->mp,
+				     ABS_RZ, -16000, 16000, 4, 8);
+	} else {
+		set_bit(ABS_GYRO_X, wdata->mp->absbit);
+		set_bit(ABS_GYRO_Y, wdata->mp->absbit);
+		set_bit(ABS_GYRO_Z, wdata->mp->absbit);
+		input_set_abs_params(wdata->mp,
+				     ABS_GYRO_X, -16000, 16000, 4, 8);
+		input_set_abs_params(wdata->mp,
+				     ABS_GYRO_Y, -16000, 16000, 4, 8);
+		input_set_abs_params(wdata->mp,
+				     ABS_GYRO_Z, -16000, 16000, 4, 8);
+	}
 
 	ret = input_register_device(wdata->mp);
 	if (ret)
-- 
1.8.4.1


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

* [PATCH 11/13] Input: introduce BTN/ABS bits for drums and guitars
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (9 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 10/13] HID: wiimote: use ABS_GYRO_* bits for MP David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 12/13] HID: wiimote: add support for Guitar-Hero drums David Herrmann
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

There are a bunch of guitar and drums devices out there that all report
similar data. To avoid reporting this as BTN_MISC or ABS_MISC, we
allocate some proper namespace for them. Note that most of these devices
are toys and we cannot report any sophisticated physics via this API.

I did some google-images research and tried to provide definitions that
work with all common devices. That's why I went with 4 toms, 4 cymbals,
one bass, one hi-hat. I haven't seen other drums and I doubt that we need
any additions to that. Anyway, the naming-scheme is intentionally done in
an extensible way.

For guitars, we support 5 frets (normally aligned vertically, compared to
the real horizontal layouts), a single strum-bar with up/down directions,
an optional fret-board and a whammy-bar.

Most of the devices provide pressure values so I went with ABS_* bits. If
we ever support devices which only provide digital input, we have to
decide whether to emulate pressure data or add additional BTN_* bits.

If someone is not familiar with these devices, here are two pictures which
provide almost all introduced interfaces (or try the given keywords
with a google-image search):
  Guitar: ("guitar hero world tour guitar")
    http://images1.wikia.nocookie.net/__cb20120911023442/applezone/es/images/f/f9/Wii_Guitar.jpg
  Drums: ("guitar hero drums")
    http://oyster.ignimgs.com/franchises/images/03/55/35526_band-hero-drum-set-hands-on-20090929040735768.jpg

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 include/linux/mod_devicetable.h |  2 +-
 include/uapi/linux/input.h      | 24 +++++++++++++++++++++++-
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 329aa30..61f358a 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -277,7 +277,7 @@ struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING	0x71
 #define INPUT_DEVICE_ID_KEY_MAX		0x2ff
 #define INPUT_DEVICE_ID_REL_MAX		0x0f
-#define INPUT_DEVICE_ID_ABS_MAX		0x4f
+#define INPUT_DEVICE_ID_ABS_MAX		0x5f
 #define INPUT_DEVICE_ID_MSC_MAX		0x07
 #define INPUT_DEVICE_ID_LED_MAX		0x0f
 #define INPUT_DEVICE_ID_SND_MAX		0x07
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index f347498..3aac45a 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -742,6 +742,14 @@ struct input_keymap_entry {
 #define BTN_DPAD_LEFT		0x222
 #define BTN_DPAD_RIGHT		0x223
 
+#define BTN_FRET_FAR_UP		0x224
+#define BTN_FRET_UP		0x225
+#define BTN_FRET_MID		0x226
+#define BTN_FRET_LOW		0x227
+#define BTN_FRET_FAR_LOW	0x228
+#define BTN_STRUM_BAR_UP	0x229
+#define BTN_STRUM_BAR_DOWN	0x22a
+
 #define BTN_TRIGGER_HAPPY		0x2c0
 #define BTN_TRIGGER_HAPPY1		0x2c0
 #define BTN_TRIGGER_HAPPY2		0x2c1
@@ -870,12 +878,26 @@ struct input_keymap_entry {
 #define ABS_GYRO_Y		0x44	/* Gyroscope Y axis */
 #define ABS_GYRO_Z		0x45	/* Gyroscope Z axis */
 
+/* Drums and guitars (mostly toys) */
+#define ABS_TOM_FAR_LEFT	0x50
+#define ABS_TOM_LEFT		0x51
+#define ABS_TOM_RIGHT		0x52
+#define ABS_TOM_FAR_RIGHT	0x53
+#define ABS_CYMBAL_FAR_LEFT	0x54
+#define ABS_CYMBAL_LEFT		0x55
+#define ABS_CYMBAL_RIGHT	0x56
+#define ABS_CYMBAL_FAR_RIGHT	0x57
+#define ABS_BASS		0x58
+#define ABS_HI_HAT		0x59
+#define ABS_FRET_BOARD		0x5a	/* Guitar fret board, vertical pos */
+#define ABS_WHAMMY_BAR		0x5b	/* Guitar whammy bar (or vibrato) */
+
 /*
  * Due to API restrictions the legacy evdev API only supports ABS values up to
  * ABS_MAX/CNT. Use the extended *ABS2 ioctls to operate on any ABS values in
  * between ABS_MAX and ABS_MAX2.
  */
-#define ABS_MAX2		0x4f
+#define ABS_MAX2		0x5f
 #define ABS_CNT2		(ABS_MAX2+1)
 
 /*
-- 
1.8.4.1


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

* [PATCH 12/13] HID: wiimote: add support for Guitar-Hero drums
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (10 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 11/13] Input: introduce BTN/ABS bits for drums and guitars David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-01 20:16 ` [PATCH 13/13] HID: wiimote: add support for Guitar-Hero guitars David Herrmann
  2013-11-04 13:04 ` [PATCH 00/13] Input/HID: Bits and Pieces Jiri Kosina
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Guitar-Hero comes with a drums extension. Use the newly introduced input
drums-bits to report this back to user-space. This is a usual extension
like any other device. Nothing special to take care of.

We report this to user-space as "Nintendo Wii Remote Drums". There are
other drums (like "RockBand" drums) which we currently do not support and
maybe will at some point. However, it is quite likely that we can report
these via the same interface. This allows user-space to work with them
without knowing the exact branding.
I couldn't find anyone who owns a "RockBand" device, though.

Initial-work-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-core.c    |   7 ++
 drivers/hid/hid-wiimote-modules.c | 218 ++++++++++++++++++++++++++++++++++++++
 drivers/hid/hid-wiimote.h         |   2 +
 3 files changed, 227 insertions(+)

diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 89ca031..6212678 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -458,6 +458,9 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
 		return WIIMOTE_EXT_BALANCE_BOARD;
 	if (rmem[4] == 0x01 && rmem[5] == 0x20)
 		return WIIMOTE_EXT_PRO_CONTROLLER;
+	if (rmem[0] == 0x01 && rmem[1] == 0x00 &&
+	    rmem[4] == 0x01 && rmem[5] == 0x03)
+		return WIIMOTE_EXT_GUITAR_HERO_DRUMS;
 
 	return WIIMOTE_EXT_UNKNOWN;
 }
@@ -491,6 +494,7 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
 	/* map MP with correct pass-through mode */
 	switch (exttype) {
 	case WIIMOTE_EXT_CLASSIC_CONTROLLER:
+	case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
 		wmem = 0x07;
 		break;
 	case WIIMOTE_EXT_NUNCHUK:
@@ -1079,6 +1083,7 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
 	[WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
 	[WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
 	[WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
+	[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = "Nintendo Wii Guitar Hero Drums",
 };
 
 /*
@@ -1664,6 +1669,8 @@ static ssize_t wiimote_ext_show(struct device *dev,
 		return sprintf(buf, "balanceboard\n");
 	case WIIMOTE_EXT_PRO_CONTROLLER:
 		return sprintf(buf, "procontroller\n");
+	case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
+		return sprintf(buf, "drums\n");
 	case WIIMOTE_EXT_UNKNOWN:
 		/* fallthrough */
 	default:
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index e51e82b..5f6d66b 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -2090,6 +2090,223 @@ static const struct wiimod_ops wiimod_pro = {
 };
 
 /*
+ * Drums
+ * Guitar-Hero, Rock-Band and other games came bundled with drums which can
+ * be plugged as extension to a Wiimote. Drum-reports are still not entirely
+ * figured out, but the most important information is known.
+ * We create a separate device for drums and report all information via this
+ * input device.
+ */
+
+static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata,
+						__u8 none, __u8 which,
+						__u8 pressure, __u8 onoff,
+						__u8 *store, __u16 code,
+						__u8 which_code)
+{
+	static const __u8 default_pressure = 3;
+
+	if (!none && which == which_code) {
+		*store = pressure;
+		input_report_abs(wdata->extension.input, code, *store);
+	} else if (onoff != !!*store) {
+		*store = onoff ? default_pressure : 0;
+		input_report_abs(wdata->extension.input, code, *store);
+	}
+}
+
+static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+	__u8 pressure, which, none, hhp, sx, sy;
+	__u8 o, r, y, g, b, bass, bm, bp;
+
+	/*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    1   |  0  |  0  |              SX <5:0>             |
+	 *    2   |  0  |  0  |              SY <5:0>             |
+	 *   -----+-----+-----+-----------------------------+-----+
+	 *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |  ?  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |  1  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 * All buttons are 0 if pressed
+	 *
+	 * With Motion+ enabled, the following bits will get invalid:
+	 *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
+	 *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
+	 *   -----+-----+-----+-----------------------------+-----+
+	 *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |XXXXX|
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |XXXXX|XXXXX|
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 */
+
+	pressure = 7 - (ext[3] >> 5);
+	which = (ext[2] >> 1) & 0x1f;
+	none = !!(ext[2] & 0x40);
+	hhp = !(ext[2] & 0x80);
+	sx = ext[0] & 0x3f;
+	sy = ext[1] & 0x3f;
+	o = !(ext[5] & 0x80);
+	r = !(ext[5] & 0x40);
+	y = !(ext[5] & 0x20);
+	g = !(ext[5] & 0x10);
+	b = !(ext[5] & 0x08);
+	bass = !(ext[5] & 0x04);
+	bm = !(ext[4] & 0x10);
+	bp = !(ext[4] & 0x04);
+
+	wiimod_drums_report_pressure(wdata, none, which, pressure,
+				     o, &wdata->state.pressure_drums[0],
+				     ABS_CYMBAL_RIGHT, 0x0e);
+	wiimod_drums_report_pressure(wdata, none, which, pressure,
+				     r, &wdata->state.pressure_drums[1],
+				     ABS_TOM_LEFT, 0x19);
+	wiimod_drums_report_pressure(wdata, none, which, pressure,
+				     y, &wdata->state.pressure_drums[2],
+				     ABS_CYMBAL_LEFT, 0x11);
+	wiimod_drums_report_pressure(wdata, none, which, pressure,
+				     g, &wdata->state.pressure_drums[3],
+				     ABS_TOM_FAR_RIGHT, 0x12);
+	wiimod_drums_report_pressure(wdata, none, which, pressure,
+				     b, &wdata->state.pressure_drums[4],
+				     ABS_TOM_RIGHT, 0x0f);
+
+	/* Bass shares pressure with hi-hat (set via hhp) */
+	wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure,
+				     bass, &wdata->state.pressure_drums[5],
+				     ABS_BASS, 0x1b);
+	/* Hi-hat has no on/off values, just pressure. Force to off/0. */
+	wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure,
+				     0, &wdata->state.pressure_drums[6],
+				     ABS_HI_HAT, 0x0e);
+
+	input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
+	input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
+
+	input_report_key(wdata->extension.input, BTN_START, bp);
+	input_report_key(wdata->extension.input, BTN_SELECT, bm);
+
+	input_sync(wdata->extension.input);
+}
+
+static int wiimod_drums_open(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return 0;
+}
+
+static void wiimod_drums_close(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_drums_probe(const struct wiimod_ops *ops,
+			      struct wiimote_data *wdata)
+{
+	int ret;
+
+	wdata->extension.input = input_allocate_device();
+	if (!wdata->extension.input)
+		return -ENOMEM;
+
+	input_set_drvdata(wdata->extension.input, wdata);
+	wdata->extension.input->open = wiimod_drums_open;
+	wdata->extension.input->close = wiimod_drums_close;
+	wdata->extension.input->dev.parent = &wdata->hdev->dev;
+	wdata->extension.input->id.bustype = wdata->hdev->bus;
+	wdata->extension.input->id.vendor = wdata->hdev->vendor;
+	wdata->extension.input->id.product = wdata->hdev->product;
+	wdata->extension.input->id.version = wdata->hdev->version;
+	wdata->extension.input->name = WIIMOTE_NAME " Drums";
+
+	set_bit(EV_KEY, wdata->extension.input->evbit);
+	set_bit(BTN_START, wdata->extension.input->keybit);
+	set_bit(BTN_SELECT, wdata->extension.input->keybit);
+
+	set_bit(EV_ABS, wdata->extension.input->evbit);
+	set_bit(ABS_X, wdata->extension.input->absbit);
+	set_bit(ABS_Y, wdata->extension.input->absbit);
+	set_bit(ABS_TOM_LEFT, wdata->extension.input->absbit);
+	set_bit(ABS_TOM_RIGHT, wdata->extension.input->absbit);
+	set_bit(ABS_TOM_FAR_RIGHT, wdata->extension.input->absbit);
+	set_bit(ABS_CYMBAL_LEFT, wdata->extension.input->absbit);
+	set_bit(ABS_CYMBAL_RIGHT, wdata->extension.input->absbit);
+	set_bit(ABS_BASS, wdata->extension.input->absbit);
+	set_bit(ABS_HI_HAT, wdata->extension.input->absbit);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_X, -32, 31, 1, 1);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_Y, -32, 31, 1, 1);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_TOM_LEFT, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_TOM_RIGHT, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_TOM_FAR_RIGHT, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_CYMBAL_LEFT, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_CYMBAL_RIGHT, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_BASS, 0, 7, 0, 0);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_HI_HAT, 0, 7, 0, 0);
+
+	ret = input_register_device(wdata->extension.input);
+	if (ret)
+		goto err_free;
+
+	return 0;
+
+err_free:
+	input_free_device(wdata->extension.input);
+	wdata->extension.input = NULL;
+	return ret;
+}
+
+static void wiimod_drums_remove(const struct wiimod_ops *ops,
+				struct wiimote_data *wdata)
+{
+	if (!wdata->extension.input)
+		return;
+
+	input_unregister_device(wdata->extension.input);
+	wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_drums = {
+	.flags = 0,
+	.arg = 0,
+	.probe = wiimod_drums_probe,
+	.remove = wiimod_drums_remove,
+	.in_ext = wiimod_drums_in_ext,
+};
+
+/*
  * Builtin Motion Plus
  * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
  * disables polling for Motion-Plus. This should be set only for devices which
@@ -2359,4 +2576,5 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
 	[WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic,
 	[WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
 	[WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
+	[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = &wiimod_drums,
 };
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 6f70823..c8a7fc3 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -90,6 +90,7 @@ enum wiimote_exttype {
 	WIIMOTE_EXT_CLASSIC_CONTROLLER,
 	WIIMOTE_EXT_BALANCE_BOARD,
 	WIIMOTE_EXT_PRO_CONTROLLER,
+	WIIMOTE_EXT_GUITAR_HERO_DRUMS,
 	WIIMOTE_EXT_NUM,
 };
 
@@ -139,6 +140,7 @@ struct wiimote_state {
 	__u16 calib_bboard[4][3];
 	__s16 calib_pro_sticks[4];
 	__u8 cache_rumble;
+	__u8 pressure_drums[7];
 };
 
 struct wiimote_data {
-- 
1.8.4.1


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

* [PATCH 13/13] HID: wiimote: add support for Guitar-Hero guitars
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (11 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 12/13] HID: wiimote: add support for Guitar-Hero drums David Herrmann
@ 2013-11-01 20:16 ` David Herrmann
  2013-11-04 13:04 ` [PATCH 00/13] Input/HID: Bits and Pieces Jiri Kosina
  13 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	Nicolas Adenis-Lamarre, David Herrmann

From: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>

Apart from drums, Guitar-Hero also ships with guitars. Use the recently
introduced input ABS/BTN-bits to report this to user-space.

Devices are reported as "Nintendo Wii Remote Guitar". If I ever get my
hands on "RockBand" guitars, I will try to report them via the same
interface so user-space does not have to bother which device it deals
with.

Signed-off-by: Nicolas.Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
(add commit-msg and adjust to new BTN_* IDs)
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-wiimote-core.c    |   7 ++
 drivers/hid/hid-wiimote-modules.c | 174 ++++++++++++++++++++++++++++++++++++++
 drivers/hid/hid-wiimote.h         |   1 +
 3 files changed, 182 insertions(+)

diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 6212678..829e437 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -461,6 +461,9 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
 	if (rmem[0] == 0x01 && rmem[1] == 0x00 &&
 	    rmem[4] == 0x01 && rmem[5] == 0x03)
 		return WIIMOTE_EXT_GUITAR_HERO_DRUMS;
+	if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
+	    rmem[4] == 0x01 && rmem[5] == 0x03)
+		return WIIMOTE_EXT_GUITAR_HERO_GUITAR;
 
 	return WIIMOTE_EXT_UNKNOWN;
 }
@@ -495,6 +498,7 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
 	switch (exttype) {
 	case WIIMOTE_EXT_CLASSIC_CONTROLLER:
 	case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
+	case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
 		wmem = 0x07;
 		break;
 	case WIIMOTE_EXT_NUNCHUK:
@@ -1084,6 +1088,7 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
 	[WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
 	[WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
 	[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = "Nintendo Wii Guitar Hero Drums",
+	[WIIMOTE_EXT_GUITAR_HERO_GUITAR] = "Nintendo Wii Guitar Hero Guitar",
 };
 
 /*
@@ -1671,6 +1676,8 @@ static ssize_t wiimote_ext_show(struct device *dev,
 		return sprintf(buf, "procontroller\n");
 	case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
 		return sprintf(buf, "drums\n");
+	case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
+		return sprintf(buf, "guitar\n");
 	case WIIMOTE_EXT_UNKNOWN:
 		/* fallthrough */
 	default:
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 5f6d66b..625e1f3 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -2307,6 +2307,179 @@ static const struct wiimod_ops wiimod_drums = {
 };
 
 /*
+ * Guitar
+ * Guitar-Hero, Rock-Band and other games came bundled with guitars which can
+ * be plugged as extension to a Wiimote.
+ * We create a separate device for guitars and report all information via this
+ * input device.
+ */
+
+static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+	__u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu;
+
+	/*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    1   |  0  |  0  |              SX <5:0>             |
+	 *    2   |  0  |  0  |              SY <5:0>             |
+	 *   -----+-----+-----+-----+-----------------------------+
+	 *    3   |  0  |  0  |  0  |      TB <4:0>               |
+	 *   -----+-----+-----+-----+-----------------------------+
+	 *    4   |  0  |  0  |  0  |      WB <4:0>               |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    6   | BO  | BR  | BB  | BG  | BY  |  1  |  1  | BU  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 * All buttons are 0 if pressed
+	 *
+	 * With Motion+ enabled, the following bits will get invalid:
+	 *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
+	 *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
+	 *   -----+-----+-----+-----+-----------------------+-----+
+	 *    3   |  0  |  0  |  0  |      TB <4:0>               |
+	 *   -----+-----+-----+-----+-----------------------------+
+	 *    4   |  0  |  0  |  0  |      WB <4:0>               |
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |XXXXX|
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 *    6   | BO  | BR  | BB  | BG  | BY  |  1  |XXXXX|XXXXX|
+	 *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+	 */
+
+	sx = ext[0] & 0x3f;
+	sy = ext[1] & 0x3f;
+	tb = ext[2] & 0x1f;
+	wb = ext[3] & 0x1f;
+	bd = !(ext[4] & 0x40);
+	bm = !(ext[4] & 0x10);
+	bp = !(ext[4] & 0x04);
+	bo = !(ext[5] & 0x80);
+	br = !(ext[5] & 0x40);
+	bb = !(ext[5] & 0x20);
+	bg = !(ext[5] & 0x10);
+	by = !(ext[5] & 0x08);
+	bu = !(ext[5] & 0x01);
+
+	input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
+	input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
+	input_report_abs(wdata->extension.input, ABS_FRET_BOARD, tb);
+	input_report_abs(wdata->extension.input, ABS_WHAMMY_BAR, wb - 0x10);
+
+	input_report_key(wdata->extension.input, BTN_MODE, bm);
+	input_report_key(wdata->extension.input, BTN_START, bp);
+	input_report_key(wdata->extension.input, BTN_STRUM_BAR_UP, bu);
+	input_report_key(wdata->extension.input, BTN_STRUM_BAR_DOWN, bd);
+	input_report_key(wdata->extension.input, BTN_FRET_FAR_UP, bg);
+	input_report_key(wdata->extension.input, BTN_FRET_UP, br);
+	input_report_key(wdata->extension.input, BTN_FRET_MID, by);
+	input_report_key(wdata->extension.input, BTN_FRET_LOW, bb);
+	input_report_key(wdata->extension.input, BTN_FRET_FAR_LOW, bo);
+
+	input_sync(wdata->extension.input);
+}
+
+static int wiimod_guitar_open(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return 0;
+}
+
+static void wiimod_guitar_close(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_guitar_probe(const struct wiimod_ops *ops,
+			       struct wiimote_data *wdata)
+{
+	int ret;
+
+	wdata->extension.input = input_allocate_device();
+	if (!wdata->extension.input)
+		return -ENOMEM;
+
+	input_set_drvdata(wdata->extension.input, wdata);
+	wdata->extension.input->open = wiimod_guitar_open;
+	wdata->extension.input->close = wiimod_guitar_close;
+	wdata->extension.input->dev.parent = &wdata->hdev->dev;
+	wdata->extension.input->id.bustype = wdata->hdev->bus;
+	wdata->extension.input->id.vendor = wdata->hdev->vendor;
+	wdata->extension.input->id.product = wdata->hdev->product;
+	wdata->extension.input->id.version = wdata->hdev->version;
+	wdata->extension.input->name = WIIMOTE_NAME " Guitar";
+
+	set_bit(EV_KEY, wdata->extension.input->evbit);
+	set_bit(BTN_MODE, wdata->extension.input->keybit);
+	set_bit(BTN_START, wdata->extension.input->keybit);
+	set_bit(BTN_FRET_FAR_UP, wdata->extension.input->keybit);
+	set_bit(BTN_FRET_UP, wdata->extension.input->keybit);
+	set_bit(BTN_FRET_MID, wdata->extension.input->keybit);
+	set_bit(BTN_FRET_LOW, wdata->extension.input->keybit);
+	set_bit(BTN_FRET_FAR_LOW, wdata->extension.input->keybit);
+	set_bit(BTN_STRUM_BAR_UP, wdata->extension.input->keybit);
+	set_bit(BTN_STRUM_BAR_DOWN, wdata->extension.input->keybit);
+
+	set_bit(EV_ABS, wdata->extension.input->evbit);
+	set_bit(ABS_X, wdata->extension.input->absbit);
+	set_bit(ABS_Y, wdata->extension.input->absbit);
+	set_bit(ABS_FRET_BOARD, wdata->extension.input->absbit);
+	set_bit(ABS_WHAMMY_BAR, wdata->extension.input->absbit);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_X, -32, 31, 1, 1);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_Y, -32, 31, 1, 1);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_FRET_BOARD, 0, 0x1f, 1, 1);
+	input_set_abs_params(wdata->extension.input,
+			     ABS_WHAMMY_BAR, 0, 0x0f, 1, 1);
+
+	ret = input_register_device(wdata->extension.input);
+	if (ret)
+		goto err_free;
+
+	return 0;
+
+err_free:
+	input_free_device(wdata->extension.input);
+	wdata->extension.input = NULL;
+	return ret;
+}
+
+static void wiimod_guitar_remove(const struct wiimod_ops *ops,
+				 struct wiimote_data *wdata)
+{
+	if (!wdata->extension.input)
+		return;
+
+	input_unregister_device(wdata->extension.input);
+	wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_guitar = {
+	.flags = 0,
+	.arg = 0,
+	.probe = wiimod_guitar_probe,
+	.remove = wiimod_guitar_remove,
+	.in_ext = wiimod_guitar_in_ext,
+};
+
+/*
  * Builtin Motion Plus
  * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
  * disables polling for Motion-Plus. This should be set only for devices which
@@ -2577,4 +2750,5 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
 	[WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
 	[WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
 	[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = &wiimod_drums,
+	[WIIMOTE_EXT_GUITAR_HERO_GUITAR] = &wiimod_guitar,
 };
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index c8a7fc3..0ca6262 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -91,6 +91,7 @@ enum wiimote_exttype {
 	WIIMOTE_EXT_BALANCE_BOARD,
 	WIIMOTE_EXT_PRO_CONTROLLER,
 	WIIMOTE_EXT_GUITAR_HERO_DRUMS,
+	WIIMOTE_EXT_GUITAR_HERO_GUITAR,
 	WIIMOTE_EXT_NUM,
 };
 
-- 
1.8.4.1


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

* Re: [PATCH 00/13] Input/HID: Bits and Pieces
  2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
                   ` (12 preceding siblings ...)
  2013-11-01 20:16 ` [PATCH 13/13] HID: wiimote: add support for Guitar-Hero guitars David Herrmann
@ 2013-11-04 13:04 ` Jiri Kosina
  13 siblings, 0 replies; 20+ messages in thread
From: Jiri Kosina @ 2013-11-04 13:04 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-input, Dmitry Torokhov, Peter Hutterer, Benjamin Tissoires

On Fri, 1 Nov 2013, David Herrmann wrote:

> My backlog kept growing and most of the stuff depends on the ABS_* fixes, so I
> gave it another try. The first 2 patches introduce EVIOC[GS]ABS2 and friends.
> The rest is wiimote stuff that was laying around for some time and just needs
> new ABS bits. So once the ABS stuff is in, I see no reason to delay the wiimote
> patches (as they're even tested already). Hence, I put it all in a single
> series.
> 
> Jiri, Dmitry, feel free to bribe me to split / not split the series so the
> other one has to take it through their tree. Highest bid wins!

I am fine with the HID changes, but Dmitry definitely needs to Ack the 
ABS_MAX2 stuff.

After that is done, I can either take the series through my tree with his 
Ack, or vice versa, I don't really have strong opinion there.

> And I am still running tests, so please don't merge, yet. I will report back my
> results. Besides, it's probably too late for 3.13, anyway and we should put it
> into -next for 3.14 for some while.

Thanks,

-- 
Jiri Kosina
SUSE Labs

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

* Re: [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends
  2013-11-01 20:16 ` [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends David Herrmann
@ 2013-11-05 22:29   ` David Herrmann
  0 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-05 22:29 UTC (permalink / raw)
  To: open list:HID CORE LAYER
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Hi

On Fri, Nov 1, 2013 at 9:16 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> As we painfully noticed during the 3.12 merge-window our
> EVIOCGABS/EVIOCSABS API is limited to ABS_MAX<=0x3f. We tried several
> hacks to work around it but if we ever decide to increase ABS_MAX, the
> EVIOCSABS ioctl ABI might overflow into the next byte causing horrible
> misinterpretations in the kernel that we cannot catch.
>
> Therefore, we decided to go with ABS_MAX2/CNT2 and introduce two new
> ioctls to get/set abs-params. They no longer encode the ABS code in the
> ioctl number and thus allow up to 4 billion ABS codes.
>
> The new API also allows to query multiple ABS values with one call. To
> allow EVIOCSABS2(code = 0, cnt = ABS_CNT2) we need to silently ignore
> writes to ABS_MT_SLOT. Other than that, semantics are the same as for the
> legacy API.

I'm currently having a hard time making this properly work with
backwards-compatibility in mind. It can get really hairy to properly
detect whether a kernel supports   ABS2 or not (during runtime). Any
objections to increasing the EVDEV version field? User-space could
then easily know whether EVIOCGABS2 is supported.

Just as a note: the libevdev test-suite runs just fine with this
patch, so at least it shouldn't break backwards-compat this time.
Anyway, I would feel a lot better if we can let this stay in
linux-next for one cycle.

Thanks
David

> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
>  drivers/hid/hid-debug.c                  |  2 +-
>  drivers/hid/hid-input.c                  |  2 +-
>  drivers/input/evdev.c                    | 88 +++++++++++++++++++++++++++++++-
>  drivers/input/input.c                    | 14 ++---
>  drivers/input/keyboard/goldfish_events.c |  6 +--
>  drivers/input/keyboard/hil_kbd.c         |  2 +-
>  drivers/input/misc/uinput.c              |  6 +--
>  include/linux/hid.h                      |  2 +-
>  include/linux/input.h                    |  6 +--
>  include/uapi/linux/input.h               | 37 +++++++++++++-
>  include/uapi/linux/uinput.h              |  2 +-
>  11 files changed, 144 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
> index 8453214..d32fa30 100644
> --- a/drivers/hid/hid-debug.c
> +++ b/drivers/hid/hid-debug.c
> @@ -862,7 +862,7 @@ static const char *relatives[REL_MAX + 1] = {
>         [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
>  };
>
> -static const char *absolutes[ABS_CNT] = {
> +static const char *absolutes[ABS_CNT2] = {
>         [ABS_X] = "X",                  [ABS_Y] = "Y",
>         [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
>         [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index d97f232..a02721c 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -1300,7 +1300,7 @@ static bool hidinput_has_been_populated(struct hid_input *hidinput)
>         for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
>                 r |= hidinput->input->relbit[i];
>
> -       for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
> +       for (i = 0; i < BITS_TO_LONGS(ABS_CNT2); i++)
>                 r |= hidinput->input->absbit[i];
>
>         for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
> diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
> index b6ded17..ffe65fd 100644
> --- a/drivers/input/evdev.c
> +++ b/drivers/input/evdev.c
> @@ -635,7 +635,7 @@ static int handle_eviocgbit(struct input_dev *dev,
>         case      0: bits = dev->evbit;  len = EV_MAX;  break;
>         case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
>         case EV_REL: bits = dev->relbit; len = REL_MAX; break;
> -       case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
> +       case EV_ABS: bits = dev->absbit; len = ABS_MAX2; break;
>         case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
>         case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
>         case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
> @@ -663,6 +663,86 @@ static int handle_eviocgbit(struct input_dev *dev,
>  }
>  #undef OLD_KEY_MAX
>
> +static int evdev_handle_get_abs2(struct input_dev *dev, void __user *p)
> +{
> +       u32 code, cnt, i;
> +       struct input_absinfo2 __user *pinfo = p;
> +       struct input_absinfo abs;
> +
> +       if (!dev->absinfo)
> +               return -EINVAL;
> +
> +       if (copy_from_user(&code, &pinfo->code, sizeof(code)))
> +               return -EFAULT;
> +       if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
> +               return -EFAULT;
> +
> +       if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
> +               return -EINVAL;
> +       if (code + cnt > ABS_MAX2)
> +               return -EINVAL;
> +
> +       for (i = 0; i < cnt; ++i) {
> +               /*
> +                * Take event lock to ensure that we are not
> +                * copying data while EVIOCSABS2 changes it.
> +                * Might be inconsistent, otherwise.
> +                */
> +               spin_lock_irq(&dev->event_lock);
> +               abs = dev->absinfo[code + i];
> +               spin_unlock_irq(&dev->event_lock);
> +
> +               if (copy_to_user(&pinfo->info[i], &abs, sizeof(abs)))
> +                       return -EFAULT;
> +       }
> +
> +       return 0;
> +}
> +
> +static int evdev_handle_set_abs2(struct input_dev *dev, void __user *p)
> +{
> +       struct input_absinfo2 __user *pinfo = p;
> +       struct input_absinfo *abs;
> +       u32 code, cnt, i;
> +       size_t size;
> +
> +       if (!dev->absinfo)
> +               return -EINVAL;
> +
> +       if (copy_from_user(&code, &pinfo->code, sizeof(code)))
> +               return -EFAULT;
> +       if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
> +               return -EFAULT;
> +
> +       if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
> +               return -EINVAL;
> +       if (code + cnt > ABS_MAX2)
> +               return -EINVAL;
> +
> +       size = cnt * sizeof(*abs);
> +       abs = memdup_user(&pinfo->info[0], size);
> +       if (IS_ERR(abs))
> +               return PTR_ERR(abs);
> +
> +       /*
> +        * Take event lock to ensure that we are not
> +        * changing device parameters in the middle
> +        * of event.
> +        */
> +       spin_lock_irq(&dev->event_lock);
> +       for (i = 0; i < cnt; ++i) {
> +               /* silently drop ABS_MT_SLOT */
> +               if (code + i == ABS_MT_SLOT)
> +                       continue;
> +
> +               dev->absinfo[code + i] = abs[i];
> +       }
> +       spin_unlock_irq(&dev->event_lock);
> +
> +       kfree(abs);
> +       return 0;
> +}
> +
>  static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
>  {
>         struct input_keymap_entry ke = {
> @@ -890,6 +970,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
>                 client->clkid = i;
>                 return 0;
>
> +       case EVIOCGABS2:
> +               return evdev_handle_get_abs2(dev, p);
> +
> +       case EVIOCSABS2:
> +               return evdev_handle_set_abs2(dev, p);
> +
>         case EVIOCGKEYCODE:
>                 return evdev_handle_get_keycode(dev, p);
>
> diff --git a/drivers/input/input.c b/drivers/input/input.c
> index c044699..bc88f17 100644
> --- a/drivers/input/input.c
> +++ b/drivers/input/input.c
> @@ -305,7 +305,7 @@ static int input_get_disposition(struct input_dev *dev,
>                 break;
>
>         case EV_ABS:
> -               if (is_event_supported(code, dev->absbit, ABS_MAX))
> +               if (is_event_supported(code, dev->absbit, ABS_MAX2))
>                         disposition = input_handle_abs_event(dev, code, &value);
>
>                 break;
> @@ -474,7 +474,7 @@ EXPORT_SYMBOL(input_inject_event);
>  void input_alloc_absinfo(struct input_dev *dev)
>  {
>         if (!dev->absinfo)
> -               dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo),
> +               dev->absinfo = kcalloc(ABS_CNT2, sizeof(struct input_absinfo),
>                                         GFP_KERNEL);
>
>         WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
> @@ -954,7 +954,7 @@ static const struct input_device_id *input_match_device(struct input_handler *ha
>                 if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
>                         continue;
>
> -               if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
> +               if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX2))
>                         continue;
>
>                 if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
> @@ -1147,7 +1147,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
>         if (test_bit(EV_REL, dev->evbit))
>                 input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
>         if (test_bit(EV_ABS, dev->evbit))
> -               input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
> +               input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX2);
>         if (test_bit(EV_MSC, dev->evbit))
>                 input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
>         if (test_bit(EV_LED, dev->evbit))
> @@ -1333,7 +1333,7 @@ static int input_print_modalias(char *buf, int size, struct input_dev *id,
>         len += input_print_modalias_bits(buf + len, size - len,
>                                 'r', id->relbit, 0, REL_MAX);
>         len += input_print_modalias_bits(buf + len, size - len,
> -                               'a', id->absbit, 0, ABS_MAX);
> +                               'a', id->absbit, 0, ABS_MAX2);
>         len += input_print_modalias_bits(buf + len, size - len,
>                                 'm', id->mscbit, 0, MSC_MAX);
>         len += input_print_modalias_bits(buf + len, size - len,
> @@ -1592,7 +1592,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
>         if (test_bit(EV_REL, dev->evbit))
>                 INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX);
>         if (test_bit(EV_ABS, dev->evbit))
> -               INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX);
> +               INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX2);
>         if (test_bit(EV_MSC, dev->evbit))
>                 INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX);
>         if (test_bit(EV_LED, dev->evbit))
> @@ -1924,7 +1924,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
>
>         events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */
>
> -       for (i = 0; i < ABS_CNT; i++) {
> +       for (i = 0; i < ABS_CNT2; i++) {
>                 if (test_bit(i, dev->absbit)) {
>                         if (input_is_mt_axis(i))
>                                 events += mt_slots;
> diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
> index 9f60a2e..9999cea 100644
> --- a/drivers/input/keyboard/goldfish_events.c
> +++ b/drivers/input/keyboard/goldfish_events.c
> @@ -90,8 +90,8 @@ static void events_import_abs_params(struct event_dev *edev)
>         __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
>
>         count = __raw_readl(addr + REG_LEN) / sizeof(val);
> -       if (count > ABS_MAX)
> -               count = ABS_MAX;
> +       if (count > ABS_MAX2)
> +               count = ABS_MAX2;
>
>         for (i = 0; i < count; i++) {
>                 if (!test_bit(i, input_dev->absbit))
> @@ -158,7 +158,7 @@ static int events_probe(struct platform_device *pdev)
>         events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
>         events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
>         events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
> -       events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
> +       events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX2);
>         events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
>         events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
>         events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
> diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
> index 589e3c2..4e4e010 100644
> --- a/drivers/input/keyboard/hil_kbd.c
> +++ b/drivers/input/keyboard/hil_kbd.c
> @@ -387,7 +387,7 @@ static void hil_dev_pointer_setup(struct hil_dev *ptr)
>                                         0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
>
>  #ifdef TABLET_AUTOADJUST
> -               for (i = 0; i < ABS_MAX; i++) {
> +               for (i = 0; i < ABS_MAX2; i++) {
>                         int diff = input_abs_get_max(input_dev, ABS_X + i) / 10;
>                         input_abs_set_min(input_dev, ABS_X + i,
>                                 input_abs_get_min(input_dev, ABS_X + i) + diff);
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index 3cd84d2..2f7355e 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -311,7 +311,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
>         unsigned int cnt;
>         int retval = 0;
>
> -       for (cnt = 0; cnt < ABS_CNT; cnt++) {
> +       for (cnt = 0; cnt < ABS_CNT2; cnt++) {
>                 int min, max;
>                 if (!test_bit(cnt, dev->absbit))
>                         continue;
> @@ -474,7 +474,7 @@ static int uinput_setup_device2(struct uinput_device *udev,
>                 return -EINVAL;
>
>         /* rough check to avoid huge kernel space allocations */
> -       max = ABS_CNT * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
> +       max = ABS_CNT2 * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
>         if (count > max)
>                 return -EINVAL;
>
> @@ -770,7 +770,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>                         break;
>
>                 case UI_SET_ABSBIT:
> -                       retval = uinput_set_bit(arg, absbit, ABS_MAX);
> +                       retval = uinput_set_bit(arg, absbit, ABS_MAX2);
>                         break;
>
>                 case UI_SET_MSCBIT:
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index 31b9d29..c21d8bb 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -828,7 +828,7 @@ static inline void hid_map_usage(struct hid_input *hidinput,
>         switch (type) {
>         case EV_ABS:
>                 *bit = input->absbit;
> -               *max = ABS_MAX;
> +               *max = ABS_MAX2;
>                 break;
>         case EV_REL:
>                 *bit = input->relbit;
> diff --git a/include/linux/input.h b/include/linux/input.h
> index 82ce323..c6add6f 100644
> --- a/include/linux/input.h
> +++ b/include/linux/input.h
> @@ -129,7 +129,7 @@ struct input_dev {
>         unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
>         unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
>         unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
> -       unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
> +       unsigned long absbit[BITS_TO_LONGS(ABS_CNT2)];
>         unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
>         unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
>         unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
> @@ -210,8 +210,8 @@ struct input_dev {
>  #error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match"
>  #endif
>
> -#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX
> -#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match"
> +#if ABS_MAX2 != INPUT_DEVICE_ID_ABS_MAX
> +#error "ABS_MAX2 and INPUT_DEVICE_ID_ABS_MAX do not match"
>  #endif
>
>  #if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX
> diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
> index a372627..9e525f9 100644
> --- a/include/uapi/linux/input.h
> +++ b/include/uapi/linux/input.h
> @@ -74,6 +74,27 @@ struct input_absinfo {
>  };
>
>  /**
> + * struct input_absinfo2 - used by EVIOC[G/S]ABS2 ioctls
> + * @code: First ABS code to query
> + * @cnt: Number of ABS codes to query starting at @code
> + * @info: #@cnt absinfo structures to get/set abs parameters for all codes
> + *
> + * This structure is used by the new EVIOC[G/S]ABS2 ioctls which
> + * do the same as the old EVIOC[G/S]ABS ioctls but avoid encoding
> + * the ABS code in the ioctl number. This allows a much wider
> + * range of ABS codes. Furthermore, it allows to query multiple codes with a
> + * single call.
> + *
> + * Note that this silently drops any requests to set ABS_MT_SLOT. Hence, it is
> + * allowed to call this with code=0 cnt=ABS_CNT2.
> + */
> +struct input_absinfo2 {
> +       __u32 code;
> +       __u32 cnt;
> +       struct input_absinfo info[1];
> +};
> +
> +/**
>   * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
>   * @scancode: scancode represented in machine-endian form.
>   * @len: length of the scancode that resides in @scancode buffer.
> @@ -153,6 +174,8 @@ struct input_keymap_entry {
>
>  #define EVIOCGRAB              _IOW('E', 0x90, int)                    /* Grab/Release device */
>  #define EVIOCREVOKE            _IOW('E', 0x91, int)                    /* Revoke device access */
> +#define EVIOCGABS2             _IOR('E', 0x92, struct input_absinfo2)  /* get abs value/limits */
> +#define EVIOCSABS2             _IOW('E', 0x93, struct input_absinfo2)  /* set abs value/limits */
>
>  #define EVIOCSCLOCKID          _IOW('E', 0xa0, int)                    /* Set clockid to be used for timestamps */
>
> @@ -832,11 +855,23 @@ struct input_keymap_entry {
>  #define ABS_MT_TOOL_X          0x3c    /* Center X tool position */
>  #define ABS_MT_TOOL_Y          0x3d    /* Center Y tool position */
>
> -
> +/*
> + * ABS_MAX/CNT is limited to a maximum of 0x3f due to the design of EVIOCGABS
> + * and EVIOCSABS ioctls. Other kernel APIs like uinput also hardcoded it. Do
> + * not modify this value and instead use the extended ABS_MAX2/CNT2 API.
> + */
>  #define ABS_MAX                        0x3f
>  #define ABS_CNT                        (ABS_MAX+1)
>
>  /*
> + * Due to API restrictions the legacy evdev API only supports ABS values up to
> + * ABS_MAX/CNT. Use the extended *ABS2 ioctls to operate on any ABS values in
> + * between ABS_MAX and ABS_MAX2.
> + */
> +#define ABS_MAX2               0x3f
> +#define ABS_CNT2               (ABS_MAX2+1)
> +
> +/*
>   * Switch events
>   */
>
> diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
> index c2e8710..27ee521 100644
> --- a/include/uapi/linux/uinput.h
> +++ b/include/uapi/linux/uinput.h
> @@ -140,7 +140,7 @@ struct uinput_user_dev2 {
>         char name[UINPUT_MAX_NAME_SIZE];
>         struct input_id id;
>         __u32 ff_effects_max;
> -       struct input_absinfo abs[ABS_CNT];
> +       struct input_absinfo abs[ABS_CNT2];
>  };
>
>  #endif /* _UAPI__UINPUT_H_ */
> --
> 1.8.4.1
>

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

* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
  2013-11-01 20:16 ` [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs David Herrmann
@ 2013-11-15 10:11   ` Antonio Ospite
  2013-11-15 10:17     ` David Herrmann
  0 siblings, 1 reply; 20+ messages in thread
From: Antonio Ospite @ 2013-11-15 10:11 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-input, Dmitry Torokhov, Jiri Kosina, Peter Hutterer,
	Benjamin Tissoires

On Fri,  1 Nov 2013 21:16:15 +0100
David Herrmann <dh.herrmann@gmail.com> wrote:

> Motion sensors are getting quite common in mobile devices. To avoid
> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
> mouse-driver, this adds separate ABS_* bits for that.
> 
> This is needed if gaming devices want to report their normal data plus
> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
> sticks, so need separate definitions, anyway.
> 
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

Hi, what's the status of this patch?
I cannot see it in Dmitry's repository, David maybe you have another
repository I can pull from? 

Thanks,
   Antonio

-- 
Antonio Ospite
http://ao2.it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

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

* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
  2013-11-15 10:11   ` Antonio Ospite
@ 2013-11-15 10:17     ` David Herrmann
  2013-11-16 17:53       ` Antonio Ospite
  0 siblings, 1 reply; 20+ messages in thread
From: David Herrmann @ 2013-11-15 10:17 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: open list:HID CORE LAYER, Dmitry Torokhov, Jiri Kosina,
	Peter Hutterer, Benjamin Tissoires

Hi Antonio

On Fri, Nov 15, 2013 at 11:11 AM, Antonio Ospite
<ospite@studenti.unina.it> wrote:
> On Fri,  1 Nov 2013 21:16:15 +0100
> David Herrmann <dh.herrmann@gmail.com> wrote:
>
>> Motion sensors are getting quite common in mobile devices. To avoid
>> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
>> mouse-driver, this adds separate ABS_* bits for that.
>>
>> This is needed if gaming devices want to report their normal data plus
>> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
>> sticks, so need separate definitions, anyway.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>
> Hi, what's the status of this patch?
> I cannot see it in Dmitry's repository, David maybe you have another
> repository I can pull from?

Please see patch 1/13 and 2/13. They fix the kernel ABI to support new
ABS_* bits (the current ABI is broken in that regard). As this is
quite critical and caused breaks during the last merge-window, we
haven't merged it yet. I hope to get it into 3.14, though. The current
patches seem fine and work for me. I will try to get the user-space
part working in the next weeks.

Any help is welcome!

Thanks
David

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

* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
  2013-11-15 10:17     ` David Herrmann
@ 2013-11-16 17:53       ` Antonio Ospite
  2013-11-16 18:07         ` David Herrmann
  0 siblings, 1 reply; 20+ messages in thread
From: Antonio Ospite @ 2013-11-16 17:53 UTC (permalink / raw)
  To: David Herrmann
  Cc: open list:HID CORE LAYER, Dmitry Torokhov, Jiri Kosina,
	Peter Hutterer, Benjamin Tissoires

On Fri, 15 Nov 2013 11:17:31 +0100
David Herrmann <dh.herrmann@gmail.com> wrote:

> Hi Antonio
> 
> On Fri, Nov 15, 2013 at 11:11 AM, Antonio Ospite
> <ospite@studenti.unina.it> wrote:
> > On Fri,  1 Nov 2013 21:16:15 +0100
> > David Herrmann <dh.herrmann@gmail.com> wrote:
> >
> >> Motion sensors are getting quite common in mobile devices. To avoid
> >> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
> >> mouse-driver, this adds separate ABS_* bits for that.
> >>
> >> This is needed if gaming devices want to report their normal data plus
> >> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
> >> sticks, so need separate definitions, anyway.
> >>
> >> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> >
> > Hi, what's the status of this patch?
> > I cannot see it in Dmitry's repository, David maybe you have another
> > repository I can pull from?
> 
> Please see patch 1/13 and 2/13. They fix the kernel ABI to support new
> ABS_* bits (the current ABI is broken in that regard). As this is
> quite critical and caused breaks during the last merge-window, we
> haven't merged it yet. I hope to get it into 3.14, though. The current
> patches seem fine and work for me. I will try to get the user-space
> part working in the next weeks.
> 
> Any help is welcome!
> 

I can try updating evtest, any idea about how I should check at
runtime whether ABS_MAX2 is supported or not?

Ciao,
   Antonio

-- 
Antonio Ospite
http://ao2.it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

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

* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
  2013-11-16 17:53       ` Antonio Ospite
@ 2013-11-16 18:07         ` David Herrmann
  0 siblings, 0 replies; 20+ messages in thread
From: David Herrmann @ 2013-11-16 18:07 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: open list:HID CORE LAYER, Dmitry Torokhov, Jiri Kosina,
	Peter Hutterer, Benjamin Tissoires

Hi

On Sat, Nov 16, 2013 at 6:53 PM, Antonio Ospite
<ospite@studenti.unina.it> wrote:
> On Fri, 15 Nov 2013 11:17:31 +0100
> David Herrmann <dh.herrmann@gmail.com> wrote:
>
>> Hi Antonio
>>
>> On Fri, Nov 15, 2013 at 11:11 AM, Antonio Ospite
>> <ospite@studenti.unina.it> wrote:
>> > On Fri,  1 Nov 2013 21:16:15 +0100
>> > David Herrmann <dh.herrmann@gmail.com> wrote:
>> >
>> >> Motion sensors are getting quite common in mobile devices. To avoid
>> >> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
>> >> mouse-driver, this adds separate ABS_* bits for that.
>> >>
>> >> This is needed if gaming devices want to report their normal data plus
>> >> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
>> >> sticks, so need separate definitions, anyway.
>> >>
>> >> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> >
>> > Hi, what's the status of this patch?
>> > I cannot see it in Dmitry's repository, David maybe you have another
>> > repository I can pull from?
>>
>> Please see patch 1/13 and 2/13. They fix the kernel ABI to support new
>> ABS_* bits (the current ABI is broken in that regard). As this is
>> quite critical and caused breaks during the last merge-window, we
>> haven't merged it yet. I hope to get it into 3.14, though. The current
>> patches seem fine and work for me. I will try to get the user-space
>> part working in the next weeks.
>>
>> Any help is welcome!
>>
>
> I can try updating evtest, any idea about how I should check at
> runtime whether ABS_MAX2 is supported or not?

That's still my current issue that I need to fix. My intention is to
increase EVDEV_VERSION, so EVIOCGVERSION will suffice to test for it.

Thanks
David

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

end of thread, other threads:[~2013-11-16 18:07 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-01 20:16 [PATCH 00/13] Input/HID: Bits and Pieces David Herrmann
2013-11-01 20:16 ` [PATCH 01/13] Input: uinput: add full absinfo support David Herrmann
2013-11-01 20:16 ` [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends David Herrmann
2013-11-05 22:29   ` David Herrmann
2013-11-01 20:16 ` [PATCH 03/13] Input: remove ambigious gamepad comment David Herrmann
2013-11-01 20:16 ` [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs David Herrmann
2013-11-15 10:11   ` Antonio Ospite
2013-11-15 10:17     ` David Herrmann
2013-11-16 17:53       ` Antonio Ospite
2013-11-16 18:07         ` David Herrmann
2013-11-01 20:16 ` [PATCH 05/13] HID: wiimote: add hid_wiimote.legacy parameter David Herrmann
2013-11-01 20:16 ` [PATCH 06/13] HID: wiimote: adjust button-mapping to gamepad rules David Herrmann
2013-11-01 20:16 ` [PATCH 07/13] HID: wiimote: map nunchuk as real gamepad David Herrmann
2013-11-01 20:16 ` [PATCH 08/13] HID: wiimote: map classic controller as gamepad David Herrmann
2013-11-01 20:16 ` [PATCH 09/13] HID: wiimote: use ABS_ACCEL_* for accelerometer David Herrmann
2013-11-01 20:16 ` [PATCH 10/13] HID: wiimote: use ABS_GYRO_* bits for MP David Herrmann
2013-11-01 20:16 ` [PATCH 11/13] Input: introduce BTN/ABS bits for drums and guitars David Herrmann
2013-11-01 20:16 ` [PATCH 12/13] HID: wiimote: add support for Guitar-Hero drums David Herrmann
2013-11-01 20:16 ` [PATCH 13/13] HID: wiimote: add support for Guitar-Hero guitars David Herrmann
2013-11-04 13:04 ` [PATCH 00/13] Input/HID: Bits and Pieces Jiri Kosina

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).