All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] Extended Wiimote Support
@ 2011-08-29 13:37 David Herrmann
  2011-08-29 13:37 ` [PATCH 01/14] HID: wiimote: Support rumble device David Herrmann
                   ` (13 more replies)
  0 siblings, 14 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:37 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Hi

This adds support for accelerometer, IR-cam, force-feedback and battery-requests
of the wiimote.
Input support is split into 3 devices to allow huge power-savings on the
wiimote. As extension support must add at least 2 new input devices since the
ABS_XY ids are needed, I thought adding 2 more for accelerometer and IR doesn't
bother that much, but helps saving lots of power of the wiimote.

This patchset basically just extends the current driver with trivial DRM-modes
and further input reports. The only new _more complex_ feature is probably the
stream-locking/unlocking for synchronous requests.

For userspace tools, see (as always): http://github.com/dvdhrm/xwiimote

Thanks for reviewing,
David

David Herrmann (14):
  HID: wiimote: Support rumble device
  HID: wiimote: Add force-feedback support
  HID: wiimote: Add accelerometer input device
  HID: wiimote: Parse accelerometer data
  HID: wiimote: Add IR input device
  HID: wiimote: Parse IR data
  HID: wiimote: Add missing extension DRM handlers
  HID: wiimote: Add register/eeprom memory support
  HID: wiimote: Helper functions for synchronous requests
  HID: wiimote: Add write-register helpers
  HID: wiimote: Add IR initializer
  HID: wiimote: Initialize IR cam on request
  HID: wiimote: Add status request
  HID: wiimote: Read wiimote battery charge level

 Documentation/ABI/testing/sysfs-driver-hid-wiimote |    8 +
 drivers/hid/hid-wiimote.c                          |  776 +++++++++++++++++++-
 2 files changed, 768 insertions(+), 16 deletions(-)

-- 
1.7.6.1


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

* [PATCH 01/14] HID: wiimote: Support rumble device
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
@ 2011-08-29 13:37 ` David Herrmann
  2011-08-29 13:37 ` [PATCH 02/14] HID: wiimote: Add force-feedback support David Herrmann
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:37 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

This adds support for the wiimote's rumble device. Every output report can
enable and disable the rumble motor. Hence, every output report must look up our
new RUMBLE flag and make sure that it does not unintentionally toggle the
rumble motor.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   45 +++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 85a02e5..6809754 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -46,10 +46,11 @@ struct wiimote_data {
 	struct wiimote_state state;
 };
 
-#define WIIPROTO_FLAG_LED1 0x01
-#define WIIPROTO_FLAG_LED2 0x02
-#define WIIPROTO_FLAG_LED3 0x04
-#define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAG_LED1		0x01
+#define WIIPROTO_FLAG_LED2		0x02
+#define WIIPROTO_FLAG_LED3		0x04
+#define WIIPROTO_FLAG_LED4		0x08
+#define WIIPROTO_FLAG_RUMBLE		0x10
 #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
 					WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
 
@@ -58,6 +59,7 @@ struct wiimote_data {
 
 enum wiiproto_reqs {
 	WIIPROTO_REQ_NULL = 0x0,
+	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM = 0x12,
 	WIIPROTO_REQ_STATUS = 0x20,
@@ -172,6 +174,39 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
 	spin_unlock_irqrestore(&wdata->qlock, flags);
 }
 
+/*
+ * This sets the rumble bit on the given output report if rumble is
+ * currently enabled.
+ * \cmd1 must point to the second byte in the output report => &cmd[1]
+ * This must be called on nearly every output report before passing it
+ * into the output queue!
+ */
+static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
+{
+	if (wdata->state.flags & WIIPROTO_FLAG_RUMBLE)
+		*cmd1 |= 0x01;
+}
+
+static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
+{
+	__u8 cmd[2];
+
+	rumble = !!rumble;
+	if (rumble == !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE))
+		return;
+
+	if (rumble)
+		wdata->state.flags |= WIIPROTO_FLAG_RUMBLE;
+	else
+		wdata->state.flags &= ~WIIPROTO_FLAG_RUMBLE;
+
+	cmd[0] = WIIPROTO_REQ_RUMBLE;
+	cmd[1] = 0;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
 {
 	__u8 cmd[2];
@@ -193,6 +228,7 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
 	if (leds & WIIPROTO_FLAG_LED4)
 		cmd[1] |= 0x80;
 
+	wiiproto_keep_rumble(wdata, &cmd[1]);
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
@@ -217,6 +253,7 @@ static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
 	cmd[1] = 0;
 	cmd[2] = drm;
 
+	wiiproto_keep_rumble(wdata, &cmd[1]);
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
-- 
1.7.6.1


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

* [PATCH 02/14] HID: wiimote: Add force-feedback support
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
  2011-08-29 13:37 ` [PATCH 01/14] HID: wiimote: Support rumble device David Herrmann
@ 2011-08-29 13:37 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 03/14] HID: wiimote: Add accelerometer input device David Herrmann
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:37 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

The wiimote has a single rumble motor. This adds force feedback support for
wiimote devices with FF_RUMBLE. The rumble motor is very simple and only
supports an on/off switch so no complex ff-effects are supported.

This also removes the event callback that was registered before but unused. The
ff-device overwrites this callback, anyway.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   31 ++++++++++++++++++++++++++++---
 1 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 6809754..57faac5 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -305,9 +305,28 @@ static void wiimote_leds_set(struct led_classdev *led_dev,
 	}
 }
 
-static int wiimote_input_event(struct input_dev *dev, unsigned int type,
-						unsigned int code, int value)
+static int wiimote_ff_play(struct input_dev *dev, void *data,
+							struct ff_effect *eff)
 {
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	__u8 value;
+	unsigned long flags;
+
+	/*
+	 * The wiimote supports only a single rumble motor so if any magnitude
+	 * is set to non-zero then we start the rumble motor. If both are set to
+	 * zero, we stop the rumble motor.
+	 */
+
+	if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+		value = 1;
+	else
+		value = 0;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiiproto_req_rumble(wdata, value);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
 	return 0;
 }
 
@@ -480,7 +499,6 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	hid_set_drvdata(hdev, wdata);
 
 	input_set_drvdata(wdata->input, wdata);
-	wdata->input->event = wiimote_input_event;
 	wdata->input->open = wiimote_input_open;
 	wdata->input->close = wiimote_input_close;
 	wdata->input->dev.parent = &wdata->hdev->dev;
@@ -494,6 +512,13 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
 		set_bit(wiiproto_keymap[i], wdata->input->keybit);
 
+	set_bit(FF_RUMBLE, wdata->input->ffbit);
+	if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play)) {
+		input_free_device(wdata->input);
+		kfree(wdata);
+		return NULL;
+	}
+
 	spin_lock_init(&wdata->qlock);
 	INIT_WORK(&wdata->worker, wiimote_worker);
 
-- 
1.7.6.1


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

* [PATCH 03/14] HID: wiimote: Add accelerometer input device
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
  2011-08-29 13:37 ` [PATCH 01/14] HID: wiimote: Support rumble device David Herrmann
  2011-08-29 13:37 ` [PATCH 02/14] HID: wiimote: Add force-feedback support David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 04/14] HID: wiimote: Parse accelerometer data David Herrmann
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Add new input device for every wiimote which is used to report accelerometer
data to userspace. Only if the input device is currently open, we make the
wiimote send accelerometer data. This saves a whole lot of energy on the wiimote
if an application is only interested in button input reports.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   99 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 89 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 57faac5..9fb7bd6 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -36,6 +36,7 @@ struct wiimote_data {
 	struct hid_device *hdev;
 	struct input_dev *input;
 	struct led_classdev *leds[4];
+	struct input_dev *accel;
 
 	spinlock_t qlock;
 	__u8 head;
@@ -51,6 +52,7 @@ struct wiimote_data {
 #define WIIPROTO_FLAG_LED3		0x04
 #define WIIPROTO_FLAG_LED4		0x08
 #define WIIPROTO_FLAG_RUMBLE		0x10
+#define WIIPROTO_FLAG_ACCEL		0x20
 #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
 					WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
 
@@ -257,6 +259,20 @@ static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
+{
+	accel = !!accel;
+	if (accel == !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
+		return;
+
+	if (accel)
+		wdata->state.flags |= WIIPROTO_FLAG_ACCEL;
+	else
+		wdata->state.flags &= ~WIIPROTO_FLAG_ACCEL;
+
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
 static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
 {
 	struct wiimote_data *wdata;
@@ -344,6 +360,35 @@ static void wiimote_input_close(struct input_dev *dev)
 	hid_hw_close(wdata->hdev);
 }
 
+static int wiimote_accel_open(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	int ret;
+	unsigned long flags;
+
+	ret = hid_hw_open(wdata->hdev);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiiproto_req_accel(wdata, true);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return 0;
+}
+
+static void wiimote_accel_close(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiiproto_req_accel(wdata, false);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	hid_hw_close(wdata->hdev);
+}
+
 static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 {
 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
@@ -490,10 +535,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 		return NULL;
 
 	wdata->input = input_allocate_device();
-	if (!wdata->input) {
-		kfree(wdata);
-		return NULL;
-	}
+	if (!wdata->input)
+		goto err;
 
 	wdata->hdev = hdev;
 	hid_set_drvdata(hdev, wdata);
@@ -513,11 +556,30 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 		set_bit(wiiproto_keymap[i], wdata->input->keybit);
 
 	set_bit(FF_RUMBLE, wdata->input->ffbit);
-	if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play)) {
-		input_free_device(wdata->input);
-		kfree(wdata);
-		return NULL;
-	}
+	if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play))
+		goto err_input;
+
+	wdata->accel = input_allocate_device();
+	if (!wdata->accel)
+		goto err_input;
+
+	input_set_drvdata(wdata->accel, wdata);
+	wdata->accel->open = wiimote_accel_open;
+	wdata->accel->close = wiimote_accel_close;
+	wdata->accel->dev.parent = &wdata->hdev->dev;
+	wdata->accel->id.bustype = wdata->hdev->bus;
+	wdata->accel->id.vendor = wdata->hdev->vendor;
+	wdata->accel->id.product = wdata->hdev->product;
+	wdata->accel->id.version = wdata->hdev->version;
+	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);
 
 	spin_lock_init(&wdata->qlock);
 	INIT_WORK(&wdata->worker, wiimote_worker);
@@ -525,12 +587,19 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	spin_lock_init(&wdata->state.lock);
 
 	return wdata;
+
+err_input:
+	input_free_device(wdata->input);
+err:
+	kfree(wdata);
+	return NULL;
 }
 
 static void wiimote_destroy(struct wiimote_data *wdata)
 {
 	wiimote_leds_destroy(wdata);
 
+	input_unregister_device(wdata->accel);
 	input_unregister_device(wdata->input);
 	cancel_work_sync(&wdata->worker);
 	hid_hw_stop(wdata->hdev);
@@ -562,12 +631,18 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 		goto err;
 	}
 
-	ret = input_register_device(wdata->input);
+	ret = input_register_device(wdata->accel);
 	if (ret) {
 		hid_err(hdev, "Cannot register input device\n");
 		goto err_stop;
 	}
 
+	ret = input_register_device(wdata->input);
+	if (ret) {
+		hid_err(hdev, "Cannot register input device\n");
+		goto err_input;
+	}
+
 	ret = wiimote_leds_create(wdata);
 	if (ret)
 		goto err_free;
@@ -585,9 +660,13 @@ err_free:
 	wiimote_destroy(wdata);
 	return ret;
 
+err_input:
+	input_unregister_device(wdata->accel);
+	wdata->accel = NULL;
 err_stop:
 	hid_hw_stop(hdev);
 err:
+	input_free_device(wdata->accel);
 	input_free_device(wdata->input);
 	kfree(wdata);
 	return ret;
-- 
1.7.6.1


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

* [PATCH 04/14] HID: wiimote: Parse accelerometer data
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (2 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 03/14] HID: wiimote: Add accelerometer input device David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 05/14] HID: wiimote: Add IR input device David Herrmann
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Add parser functions for accelerometer data reported by the wiimote. The data is
almost always reported in the same format, so we can use a single handler.
However, an own handler function is created for each DRM-mode because when IR
and extension support is added, each of them is parsed differently.

Also set the appropriate DRM including accelerometer data on DRM requests to
actually retrieve the accelerometer data.

Data is reported to userspace as ABS_RX/Y/Z values. The values are between -500
and 500 and 0 means no acceleration. See also userspace xwiimote library for
data parsing.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |  102 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 101 insertions(+), 1 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 9fb7bd6..de9aadf 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -30,6 +30,7 @@ struct wiimote_buf {
 struct wiimote_state {
 	spinlock_t lock;
 	__u8 flags;
+	__u8 accel_split[2];
 };
 
 struct wiimote_data {
@@ -67,6 +68,12 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_STATUS = 0x20,
 	WIIPROTO_REQ_RETURN = 0x22,
 	WIIPROTO_REQ_DRM_K = 0x30,
+	WIIPROTO_REQ_DRM_KA = 0x31,
+	WIIPROTO_REQ_DRM_KAI = 0x33,
+	WIIPROTO_REQ_DRM_KAE = 0x35,
+	WIIPROTO_REQ_DRM_KAIE = 0x37,
+	WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
+	WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
 };
 
 enum wiiproto_keys {
@@ -241,7 +248,10 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
  */
 static __u8 select_drm(struct wiimote_data *wdata)
 {
-	return WIIPROTO_REQ_DRM_K;
+	if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
+		return WIIPROTO_REQ_DRM_KA;
+	else
+		return WIIPROTO_REQ_DRM_K;
 }
 
 static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
@@ -416,6 +426,40 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 	input_sync(wdata->input);
 }
 
+static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
+{
+	__u16 x, y, z;
+
+	if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
+		return;
+
+	/*
+	 * payload is: BB BB XX YY ZZ
+	 * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
+	 * contain the upper 8 bits of each value. The lower 2 bits are
+	 * contained in the buttons data BB BB.
+	 * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
+	 * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
+	 * accel value and bit 6 is the second bit of the Z value.
+	 * The first bit of Y and Z values is not available and always set to 0.
+	 * 0x200 is returned on no movement.
+	 */
+
+	x = payload[2] << 2;
+	y = payload[3] << 2;
+	z = payload[4] << 2;
+
+	x |= (payload[0] >> 5) & 0x3;
+	y |= (payload[1] >> 4) & 0x2;
+	z |= (payload[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);
+	input_sync(wdata->accel);
+}
+
+
 static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
@@ -436,6 +480,56 @@ static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
 									cmd);
 }
 
+static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+	handler_accel(wdata, payload);
+}
+
+static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+	handler_accel(wdata, payload);
+}
+
+static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+	handler_accel(wdata, payload);
+}
+
+static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+	handler_accel(wdata, payload);
+}
+
+static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+
+	wdata->state.accel_split[0] = payload[2];
+	wdata->state.accel_split[1] = (payload[0] >> 1) & (0x10 | 0x20);
+	wdata->state.accel_split[1] |= (payload[1] << 1) & (0x40 | 0x80);
+}
+
+static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
+{
+	__u8 buf[5];
+
+	handler_keys(wdata, payload);
+
+	wdata->state.accel_split[1] |= (payload[0] >> 5) & (0x01 | 0x02);
+	wdata->state.accel_split[1] |= (payload[1] >> 3) & (0x04 | 0x08);
+
+	buf[0] = 0;
+	buf[1] = 0;
+	buf[2] = wdata->state.accel_split[0];
+	buf[3] = payload[2];
+	buf[4] = wdata->state.accel_split[1];
+	handler_accel(wdata, buf);
+}
+
 struct wiiproto_handler {
 	__u8 id;
 	size_t size;
@@ -446,6 +540,12 @@ static struct wiiproto_handler handlers[] = {
 	{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
 	{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
 	{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
+	{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
+	{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
+	{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
+	{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
+	{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
+	{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
 	{ .id = 0 }
 };
 
-- 
1.7.6.1


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

* [PATCH 05/14] HID: wiimote: Add IR input device
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (3 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 04/14] HID: wiimote: Parse accelerometer data David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 06/14] HID: wiimote: Parse IR data David Herrmann
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

The IR cam of the wiimote reports 4 trackable lights as absolute values. Since
we can turn the IR cam on and off, we register a separate input device so we can
react on open/close callbacks to save wiimote battery power when IR cam is not
needed.

The cam can be in four states: off, basic, extended and full
The DRM chooser automatically selects a proper DRM that includes all required IR
data so no information is lost.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   71 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index de9aadf..4cdaaf6 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -38,6 +38,7 @@ struct wiimote_data {
 	struct input_dev *input;
 	struct led_classdev *leds[4];
 	struct input_dev *accel;
+	struct input_dev *ir;
 
 	spinlock_t qlock;
 	__u8 head;
@@ -54,8 +55,13 @@ struct wiimote_data {
 #define WIIPROTO_FLAG_LED4		0x08
 #define WIIPROTO_FLAG_RUMBLE		0x10
 #define WIIPROTO_FLAG_ACCEL		0x20
+#define WIIPROTO_FLAG_IR_BASIC		0x40
+#define WIIPROTO_FLAG_IR_EXT		0x80
+#define WIIPROTO_FLAG_IR_FULL		0xc0 /* IR_BASIC | IR_EXT */
 #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
 					WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
+#define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \
+							WIIPROTO_FLAG_IR_FULL)
 
 /* return flag for led \num */
 #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
@@ -71,6 +77,7 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_DRM_KA = 0x31,
 	WIIPROTO_REQ_DRM_KAI = 0x33,
 	WIIPROTO_REQ_DRM_KAE = 0x35,
+	WIIPROTO_REQ_DRM_KIE = 0x36,
 	WIIPROTO_REQ_DRM_KAIE = 0x37,
 	WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
 	WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
@@ -248,10 +255,23 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
  */
 static __u8 select_drm(struct wiimote_data *wdata)
 {
-	if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
-		return WIIPROTO_REQ_DRM_KA;
-	else
-		return WIIPROTO_REQ_DRM_K;
+	__u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
+
+	if (ir == WIIPROTO_FLAG_IR_BASIC) {
+		if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
+			return WIIPROTO_REQ_DRM_KAIE;
+		else
+			return WIIPROTO_REQ_DRM_KIE;
+	} else if (ir == WIIPROTO_FLAG_IR_EXT) {
+		return WIIPROTO_REQ_DRM_KAI;
+	} else if (ir == WIIPROTO_FLAG_IR_FULL) {
+		return WIIPROTO_REQ_DRM_SKAI1;
+	} else {
+		if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
+			return WIIPROTO_REQ_DRM_KA;
+		else
+			return WIIPROTO_REQ_DRM_K;
+	}
 }
 
 static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
@@ -681,6 +701,36 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
 	input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
 
+	wdata->ir = input_allocate_device();
+	if (!wdata->ir)
+		goto err_ir;
+
+	input_set_drvdata(wdata->ir, wdata);
+	wdata->ir->dev.parent = &wdata->hdev->dev;
+	wdata->ir->id.bustype = wdata->hdev->bus;
+	wdata->ir->id.vendor = wdata->hdev->vendor;
+	wdata->ir->id.product = wdata->hdev->product;
+	wdata->ir->id.version = wdata->hdev->version;
+	wdata->ir->name = WIIMOTE_NAME " IR";
+
+	set_bit(EV_ABS, wdata->ir->evbit);
+	set_bit(ABS_HAT0X, wdata->ir->absbit);
+	set_bit(ABS_HAT0Y, wdata->ir->absbit);
+	set_bit(ABS_HAT1X, wdata->ir->absbit);
+	set_bit(ABS_HAT1Y, wdata->ir->absbit);
+	set_bit(ABS_HAT2X, wdata->ir->absbit);
+	set_bit(ABS_HAT2Y, wdata->ir->absbit);
+	set_bit(ABS_HAT3X, wdata->ir->absbit);
+	set_bit(ABS_HAT3Y, wdata->ir->absbit);
+	input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4);
+
 	spin_lock_init(&wdata->qlock);
 	INIT_WORK(&wdata->worker, wiimote_worker);
 
@@ -688,6 +738,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 
 	return wdata;
 
+err_ir:
+	input_free_device(wdata->accel);
 err_input:
 	input_free_device(wdata->input);
 err:
@@ -700,6 +752,7 @@ static void wiimote_destroy(struct wiimote_data *wdata)
 	wiimote_leds_destroy(wdata);
 
 	input_unregister_device(wdata->accel);
+	input_unregister_device(wdata->ir);
 	input_unregister_device(wdata->input);
 	cancel_work_sync(&wdata->worker);
 	hid_hw_stop(wdata->hdev);
@@ -737,6 +790,12 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 		goto err_stop;
 	}
 
+	ret = input_register_device(wdata->ir);
+	if (ret) {
+		hid_err(hdev, "Cannot register input device\n");
+		goto err_ir;
+	}
+
 	ret = input_register_device(wdata->input);
 	if (ret) {
 		hid_err(hdev, "Cannot register input device\n");
@@ -761,11 +820,15 @@ err_free:
 	return ret;
 
 err_input:
+	input_unregister_device(wdata->ir);
+	wdata->ir = NULL;
+err_ir:
 	input_unregister_device(wdata->accel);
 	wdata->accel = NULL;
 err_stop:
 	hid_hw_stop(hdev);
 err:
+	input_free_device(wdata->ir);
 	input_free_device(wdata->accel);
 	input_free_device(wdata->input);
 	kfree(wdata);
-- 
1.7.6.1


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

* [PATCH 06/14] HID: wiimote: Parse IR data
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (4 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 05/14] HID: wiimote: Add IR input device David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 07/14] HID: wiimote: Add missing extension DRM handlers David Herrmann
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Parse IR data and report it to IR input-device. IR data is sent in 3 different
formats, but we only support the basic format as there is no way to send the
additional information to userspace.
All three formats are compatible with the basic IR data format so we need only
one parser.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   73 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 4cdaaf6..3a7dec0 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -479,6 +479,50 @@ static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
 	input_sync(wdata->accel);
 }
 
+#define ir_to_input0(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+							ABS_HAT0X, ABS_HAT0Y)
+#define ir_to_input1(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+							ABS_HAT1X, ABS_HAT1Y)
+#define ir_to_input2(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+							ABS_HAT2X, ABS_HAT2Y)
+#define ir_to_input3(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+							ABS_HAT3X, ABS_HAT3Y)
+
+static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
+						bool packed, __u8 xid, __u8 yid)
+{
+	__u16 x, y;
+
+	if (!(wdata->state.flags & WIIPROTO_FLAGS_IR))
+		return;
+
+	/*
+	 * Basic IR data is encoded into 3 bytes. The first two bytes are the
+	 * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+	 * of both.
+	 * If data is packed, then the 3rd byte is put first and slightly
+	 * reordered. This allows to interleave packed and non-packed data to
+	 * have two IR sets in 5 bytes instead of 6.
+	 * The resulting 10bit X/Y values are passed to the ABS_HATXY input dev.
+	 */
+
+	if (packed) {
+		x = ir[1] << 2;
+		y = ir[2] << 2;
+
+		x |= ir[0] & 0x3;
+		y |= (ir[0] >> 2) & 0x3;
+	} else {
+		x = ir[0] << 2;
+		y = ir[1] << 2;
+
+		x |= (ir[2] >> 4) & 0x3;
+		y |= (ir[2] >> 6) & 0x3;
+	}
+
+	input_report_abs(wdata->ir, xid, x);
+	input_report_abs(wdata->ir, yid, y);
+}
 
 static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 {
@@ -510,6 +554,21 @@ static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
 	handler_accel(wdata, payload);
+	ir_to_input0(wdata, &payload[5], false);
+	ir_to_input1(wdata, &payload[8], false);
+	ir_to_input2(wdata, &payload[11], false);
+	ir_to_input3(wdata, &payload[14], false);
+	input_sync(wdata->ir);
+}
+
+static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+	ir_to_input0(wdata, &payload[2], false);
+	ir_to_input1(wdata, &payload[4], true);
+	ir_to_input2(wdata, &payload[7], false);
+	ir_to_input3(wdata, &payload[9], true);
+	input_sync(wdata->ir);
 }
 
 static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
@@ -522,6 +581,11 @@ static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
 	handler_accel(wdata, payload);
+	ir_to_input0(wdata, &payload[5], false);
+	ir_to_input1(wdata, &payload[7], true);
+	ir_to_input2(wdata, &payload[10], false);
+	ir_to_input3(wdata, &payload[12], true);
+	input_sync(wdata->ir);
 }
 
 static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
@@ -531,6 +595,10 @@ static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
 	wdata->state.accel_split[0] = payload[2];
 	wdata->state.accel_split[1] = (payload[0] >> 1) & (0x10 | 0x20);
 	wdata->state.accel_split[1] |= (payload[1] << 1) & (0x40 | 0x80);
+
+	ir_to_input0(wdata, &payload[3], false);
+	ir_to_input1(wdata, &payload[12], false);
+	input_sync(wdata->ir);
 }
 
 static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
@@ -548,6 +616,10 @@ static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
 	buf[3] = payload[2];
 	buf[4] = wdata->state.accel_split[1];
 	handler_accel(wdata, buf);
+
+	ir_to_input2(wdata, &payload[3], false);
+	ir_to_input3(wdata, &payload[12], false);
+	input_sync(wdata->ir);
 }
 
 struct wiiproto_handler {
@@ -563,6 +635,7 @@ static struct wiiproto_handler handlers[] = {
 	{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
 	{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
 	{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
+	{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
 	{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
 	{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
 	{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
-- 
1.7.6.1


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

* [PATCH 07/14] HID: wiimote: Add missing extension DRM handlers
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (5 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 06/14] HID: wiimote: Parse IR data David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 08/14] HID: wiimote: Add register/eeprom memory support David Herrmann
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

If an extension is connected the wiimote may report data though DRMs that
contain extension data. This adds handlers for these DRMs but discards extension
data since we do not support it, yet.
It prints a warning to kernel log if an unhandled report is catched. Since we
handle all requests now, this should never happen, though.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 3a7dec0..a99e058 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -75,10 +75,13 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_RETURN = 0x22,
 	WIIPROTO_REQ_DRM_K = 0x30,
 	WIIPROTO_REQ_DRM_KA = 0x31,
+	WIIPROTO_REQ_DRM_KE = 0x32,
 	WIIPROTO_REQ_DRM_KAI = 0x33,
+	WIIPROTO_REQ_DRM_KEE = 0x34,
 	WIIPROTO_REQ_DRM_KAE = 0x35,
 	WIIPROTO_REQ_DRM_KIE = 0x36,
 	WIIPROTO_REQ_DRM_KAIE = 0x37,
+	WIIPROTO_REQ_DRM_E = 0x3d,
 	WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
 	WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
 };
@@ -550,6 +553,11 @@ static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
 	handler_accel(wdata, payload);
 }
 
+static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+}
+
 static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
@@ -561,6 +569,11 @@ static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
 	input_sync(wdata->ir);
 }
 
+static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+}
+
 static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
@@ -588,6 +601,10 @@ static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
 	input_sync(wdata->ir);
 }
 
+static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload)
+{
+}
+
 static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
@@ -633,10 +650,13 @@ static struct wiiproto_handler handlers[] = {
 	{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
 	{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
 	{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
+	{ .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
 	{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
+	{ .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
 	{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
 	{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
 	{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
+	{ .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
 	{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
 	{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
 	{ .id = 0 }
@@ -649,6 +669,7 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
 	struct wiiproto_handler *h;
 	int i;
 	unsigned long flags;
+	bool handled = false;
 
 	if (size < 1)
 		return -EINVAL;
@@ -657,10 +678,16 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
 
 	for (i = 0; handlers[i].id; ++i) {
 		h = &handlers[i];
-		if (h->id == raw_data[0] && h->size < size)
+		if (h->id == raw_data[0] && h->size < size) {
 			h->func(wdata, &raw_data[1]);
+			handled = true;
+		}
 	}
 
+	if (!handled)
+		hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
+									size);
+
 	spin_unlock_irqrestore(&wdata->state.lock, flags);
 
 	return 0;
-- 
1.7.6.1


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

* [PATCH 08/14] HID: wiimote: Add register/eeprom memory support
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (6 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 07/14] HID: wiimote: Add missing extension DRM handlers David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 09/14] HID: wiimote: Helper functions for synchronous requests David Herrmann
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

The wiimote allows direct access to its memory mapped registers and
internal eeprom. This adds support to access this memory and handle
memory events.

There are two macros which wrap up the memory access functions to avoid
accidentally overwriting sensitive eeprom data because a boolean value
was wrongly set.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index a99e058..c811a7d 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -71,7 +71,10 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM = 0x12,
+	WIIPROTO_REQ_WMEM = 0x16,
+	WIIPROTO_REQ_RMEM = 0x17,
 	WIIPROTO_REQ_STATUS = 0x20,
+	WIIPROTO_REQ_DATA = 0x21,
 	WIIPROTO_REQ_RETURN = 0x22,
 	WIIPROTO_REQ_DRM_K = 0x30,
 	WIIPROTO_REQ_DRM_KA = 0x31,
@@ -306,6 +309,37 @@ static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
 }
 
+#define wiiproto_req_wreg(wdata, os, buf, sz) \
+			wiiproto_req_wmem((wdata), false, (os), (buf), (sz))
+
+#define wiiproto_req_weeprom(wdata, os, buf, sz) \
+			wiiproto_req_wmem((wdata), true, (os), (buf), (sz))
+
+static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
+				__u32 offset, const __u8 *buf, __u8 size)
+{
+	__u8 cmd[22];
+
+	if (size > 16 || size == 0) {
+		hid_warn(wdata->hdev, "Invalid length %d wmem request\n", size);
+		return;
+	}
+
+	memset(cmd, 0, sizeof(cmd));
+	cmd[0] = WIIPROTO_REQ_WMEM;
+	cmd[2] = (offset >> 16) & 0xff;
+	cmd[3] = (offset >> 8) & 0xff;
+	cmd[4] = offset & 0xff;
+	cmd[5] = size;
+	memcpy(&cmd[6], buf, size);
+
+	if (!eeprom)
+		cmd[1] |= 0x04;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
 {
 	struct wiimote_data *wdata;
@@ -535,6 +569,11 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
 }
 
+static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+}
+
 static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
 {
 	__u8 err = payload[3];
@@ -647,6 +686,7 @@ struct wiiproto_handler {
 
 static struct wiiproto_handler handlers[] = {
 	{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+	{ .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
 	{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
 	{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
 	{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
-- 
1.7.6.1


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

* [PATCH 09/14] HID: wiimote: Helper functions for synchronous requests
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (7 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 08/14] HID: wiimote: Add register/eeprom memory support David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 10/14] HID: wiimote: Add write-register helpers David Herrmann
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

To initialize wiimote peripherals, the stream to the wiimote must be held
exclusively by the initializer, otherwise the initialization will fail. Many
initializations require multiple memory requests to be sent synchronously so we
need a way to lock the stream and release it when we are done.

This adds several helper functions which allow to lock the stream, then send
requests, wait for the answers and release the stream again.

When holding the lock, the function may sleep and interrupted by signals.
Also it returns after a short timeout so userspace shouldn't notice long
delays.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   56 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index c811a7d..0a5e458 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -10,11 +10,13 @@
  * any later version.
  */
 
+#include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include "hid-ids.h"
 
@@ -31,6 +33,12 @@ struct wiimote_state {
 	spinlock_t lock;
 	__u8 flags;
 	__u8 accel_split[2];
+
+	/* synchronous cmd requests */
+	struct mutex sync;
+	struct completion ready;
+	int cmd;
+	__u32 opt;
 };
 
 struct wiimote_data {
@@ -118,6 +126,52 @@ static __u16 wiiproto_keymap[] = {
 	BTN_MODE,	/* WIIPROTO_KEY_HOME */
 };
 
+/* requires the state.lock spinlock to be held */
+static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
+								__u32 opt)
+{
+	return wdata->state.cmd == cmd && wdata->state.opt == opt;
+}
+
+/* requires the state.lock spinlock to be held */
+static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
+{
+	wdata->state.cmd = WIIPROTO_REQ_NULL;
+	complete(&wdata->state.ready);
+}
+
+static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
+{
+	return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
+}
+
+/* requires the state.lock spinlock to be held */
+static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd,
+								__u32 opt)
+{
+	INIT_COMPLETION(wdata->state.ready);
+	wdata->state.cmd = cmd;
+	wdata->state.opt = opt;
+}
+
+static inline void wiimote_cmd_release(struct wiimote_data *wdata)
+{
+	mutex_unlock(&wdata->state.sync);
+}
+
+static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
+{
+	int ret;
+
+	ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
+	if (ret < 0)
+		return -ERESTARTSYS;
+	else if (ret == 0)
+		return -EIO;
+	else
+		return 0;
+}
+
 static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
 								size_t count)
 {
@@ -875,6 +929,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	INIT_WORK(&wdata->worker, wiimote_worker);
 
 	spin_lock_init(&wdata->state.lock);
+	init_completion(&wdata->state.ready);
+	mutex_init(&wdata->state.sync);
 
 	return wdata;
 
-- 
1.7.6.1


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

* [PATCH 10/14] HID: wiimote: Add write-register helpers
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (8 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 09/14] HID: wiimote: Helper functions for synchronous requests David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 11/14] HID: wiimote: Add IR initializer David Herrmann
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Add helpers to synchronously write registers of the wiimote. This is heavily
used by initialization functions for wiimote peripherals.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   28 +++++++++++++++++++++++++++-
 1 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 0a5e458..59a0893 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -39,6 +39,9 @@ struct wiimote_state {
 	struct completion ready;
 	int cmd;
 	__u32 opt;
+
+	/* results of synchronous requests */
+	__u8 cmd_err;
 };
 
 struct wiimote_data {
@@ -394,6 +397,25 @@ static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+/* requries the cmd-mutex to be held */
+static int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
+						const __u8 *wmem, __u8 size)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiimote_cmd_set(wdata, WIIPROTO_REQ_WMEM, 0);
+	wiiproto_req_wreg(wdata, offset, wmem, size);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_wait(wdata);
+	if (!ret && wdata->state.cmd_err)
+		ret = -EIO;
+
+	return ret;
+}
+
 static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
 {
 	struct wiimote_data *wdata;
@@ -635,9 +657,13 @@ static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
 
 	handler_keys(wdata, payload);
 
-	if (err)
+	if (wiimote_cmd_pending(wdata, cmd, 0)) {
+		wdata->state.cmd_err = err;
+		wiimote_cmd_complete(wdata);
+	} else if (err) {
 		hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
 									cmd);
+	}
 }
 
 static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
-- 
1.7.6.1


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

* [PATCH 11/14] HID: wiimote: Add IR initializer
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (9 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 10/14] HID: wiimote: Add write-register helpers David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 12/14] HID: wiimote: Initialize IR cam on request David Herrmann
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

The wiimote IR cam needs a fairly complex initialization sequence. This adds a
helper function that performs IR initialization synchronously.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |  136 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 136 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 59a0893..35dc293 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -82,8 +82,10 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM = 0x12,
+	WIIPROTO_REQ_IR1 = 0x13,
 	WIIPROTO_REQ_WMEM = 0x16,
 	WIIPROTO_REQ_RMEM = 0x17,
+	WIIPROTO_REQ_IR2 = 0x1a,
 	WIIPROTO_REQ_STATUS = 0x20,
 	WIIPROTO_REQ_DATA = 0x21,
 	WIIPROTO_REQ_RETURN = 0x22,
@@ -366,6 +368,28 @@ static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
 }
 
+static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
+{
+	__u8 cmd[2];
+
+	cmd[0] = WIIPROTO_REQ_IR1;
+	cmd[1] = flags;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags)
+{
+	__u8 cmd[2];
+
+	cmd[0] = WIIPROTO_REQ_IR2;
+	cmd[1] = flags;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 #define wiiproto_req_wreg(wdata, os, buf, sz) \
 			wiiproto_req_wmem((wdata), false, (os), (buf), (sz))
 
@@ -416,6 +440,118 @@ static int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
 	return ret;
 }
 
+static int wiimote_init_ir(struct wiimote_data *wdata, __u16 mode)
+{
+	int ret;
+	unsigned long flags;
+	__u8 format = 0;
+	static const __u8 data_enable[] = { 0x01 };
+	static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01,
+						0x00, 0xaa, 0x00, 0x64 };
+	static const __u8 data_sens2[] = { 0x63, 0x03 };
+	static const __u8 data_fin[] = { 0x08 };
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+
+	if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
+		spin_unlock_irqrestore(&wdata->state.lock, flags);
+		return 0;
+	}
+
+	if (mode == 0) {
+		wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+		wiiproto_req_ir1(wdata, 0);
+		wiiproto_req_ir2(wdata, 0);
+		wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+		spin_unlock_irqrestore(&wdata->state.lock, flags);
+		return 0;
+	}
+
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_acquire(wdata);
+	if (ret)
+		return ret;
+
+	/* send PIXEL CLOCK ENABLE cmd first */
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0);
+	wiiproto_req_ir1(wdata, 0x06);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_wait(wdata);
+	if (ret)
+		goto unlock;
+	if (wdata->state.cmd_err) {
+		ret = -EIO;
+		goto unlock;
+	}
+
+	/* enable IR LOGIC */
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0);
+	wiiproto_req_ir2(wdata, 0x06);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_wait(wdata);
+	if (ret)
+		goto unlock;
+	if (wdata->state.cmd_err) {
+		ret = -EIO;
+		goto unlock;
+	}
+
+	/* enable IR cam but do not make it send data, yet */
+	ret = wiimote_cmd_write(wdata, 0xb00030, data_enable,
+							sizeof(data_enable));
+	if (ret)
+		goto unlock;
+
+	/* write first sensitivity block */
+	ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1,
+							sizeof(data_sens1));
+	if (ret)
+		goto unlock;
+
+	/* write second sensitivity block */
+	ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2,
+							sizeof(data_sens2));
+	if (ret)
+		goto unlock;
+
+	/* put IR cam into desired state */
+	switch (mode) {
+		case WIIPROTO_FLAG_IR_FULL:
+			format = 5;
+			break;
+		case WIIPROTO_FLAG_IR_EXT:
+			format = 3;
+			break;
+		case WIIPROTO_FLAG_IR_BASIC:
+			format = 1;
+			break;
+	}
+	ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format));
+	if (ret)
+		goto unlock;
+
+	/* make IR cam send data */
+	ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin));
+	if (ret)
+		goto unlock;
+
+	/* request new DRM mode compatible to IR mode */
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+	wdata->state.flags |= mode & WIIPROTO_FLAGS_IR;
+	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+unlock:
+	wiimote_cmd_release(wdata);
+	return ret;
+}
+
 static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
 {
 	struct wiimote_data *wdata;
-- 
1.7.6.1


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

* [PATCH 12/14] HID: wiimote: Initialize IR cam on request
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (10 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 11/14] HID: wiimote: Add IR initializer David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 13/14] HID: wiimote: Add status request David Herrmann
  2011-08-29 13:38 ` [PATCH 14/14] HID: wiimote: Read wiimote battery charge level David Herrmann
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

Initialize the IR cam if the related input device is opened by userspace. Stop
IR cam again if userspace is no longer interested in its data events.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 35dc293..6658398 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -668,6 +668,32 @@ static void wiimote_accel_close(struct input_dev *dev)
 	hid_hw_close(wdata->hdev);
 }
 
+static int wiimote_ir_open(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+	int ret;
+
+	ret = hid_hw_open(wdata->hdev);
+	if (ret)
+		return ret;
+
+	ret = wiimote_init_ir(wdata, WIIPROTO_FLAG_IR_BASIC);
+	if (ret) {
+		hid_hw_close(wdata->hdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void wiimote_ir_close(struct input_dev *dev)
+{
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+
+	wiimote_init_ir(wdata, 0);
+	hid_hw_close(wdata->hdev);
+}
+
 static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 {
 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
@@ -1062,6 +1088,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 		goto err_ir;
 
 	input_set_drvdata(wdata->ir, wdata);
+	wdata->ir->open = wiimote_ir_open;
+	wdata->ir->close = wiimote_ir_close;
 	wdata->ir->dev.parent = &wdata->hdev->dev;
 	wdata->ir->id.bustype = wdata->hdev->bus;
 	wdata->ir->id.vendor = wdata->hdev->vendor;
-- 
1.7.6.1


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

* [PATCH 13/14] HID: wiimote: Add status request
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (11 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 12/14] HID: wiimote: Initialize IR cam on request David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 13:38 ` [PATCH 14/14] HID: wiimote: Read wiimote battery charge level David Herrmann
  13 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

The wiimote does not send status reports continuously so this adds a helper
function to request a status report and parses the battery charge level.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 6658398..48198cb 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -41,6 +41,7 @@ struct wiimote_state {
 	__u32 opt;
 
 	/* results of synchronous requests */
+	__u8 cmd_battery;
 	__u8 cmd_err;
 };
 
@@ -83,6 +84,7 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM = 0x12,
 	WIIPROTO_REQ_IR1 = 0x13,
+	WIIPROTO_REQ_SREQ = 0x15,
 	WIIPROTO_REQ_WMEM = 0x16,
 	WIIPROTO_REQ_RMEM = 0x17,
 	WIIPROTO_REQ_IR2 = 0x1a,
@@ -354,6 +356,17 @@ static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+static void wiiproto_req_status(struct wiimote_data *wdata)
+{
+	__u8 cmd[2];
+
+	cmd[0] = WIIPROTO_REQ_SREQ;
+	cmd[1] = 0;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
 {
 	accel = !!accel;
@@ -805,6 +818,11 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 
 	/* on status reports the drm is reset so we need to resend the drm */
 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+
+	if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
+		wdata->state.cmd_battery = payload[5];
+		wiimote_cmd_complete(wdata);
+	}
 }
 
 static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
-- 
1.7.6.1


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

* [PATCH 14/14] HID: wiimote: Read wiimote battery charge level
  2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
                   ` (12 preceding siblings ...)
  2011-08-29 13:38 ` [PATCH 13/14] HID: wiimote: Add status request David Herrmann
@ 2011-08-29 13:38 ` David Herrmann
  2011-08-29 14:28   ` Oliver Neukum
  13 siblings, 1 reply; 17+ messages in thread
From: David Herrmann @ 2011-08-29 13:38 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, oliver, David Herrmann

This adds a new sysfs file for wiimotes which returns the current battery charge
level of the device. Since this information is not sent by the wiimote
continously, we need to explicitely request it.

Also bump version number since the core driver is feature complete now.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 Documentation/ABI/testing/sysfs-driver-hid-wiimote |    8 ++++
 drivers/hid/hid-wiimote.c                          |   38 +++++++++++++++++++-
 2 files changed, 45 insertions(+), 1 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index 5d5a16e..817aa82 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote
+++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
@@ -8,3 +8,11 @@ Contact:	David Herrmann <dh.herrmann@googlemail.com>
 Description:	Make it possible to set/get current led state. Reading from it
 		returns 0 if led is off and 1 if it is on. Writing 0 to it
 		disables the led, writing 1 enables it.
+
+What:		/sys/bus/hid/drivers/wiimote/<dev>/battery
+Date:		July 2011
+KernelVersion:	3.2
+Contact:	David Herrmann <dh.herrmann@googlemail.com>
+Description:	Readonly attribute which returns the current battery charge
+		level. An integer between 0 and 255 is returned, 0 means empty
+		and 255 full.
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 48198cb..271630c 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -20,7 +20,7 @@
 #include <linux/spinlock.h>
 #include "hid-ids.h"
 
-#define WIIMOTE_VERSION "0.1"
+#define WIIMOTE_VERSION "0.2"
 #define WIIMOTE_NAME "Nintendo Wii Remote"
 #define WIIMOTE_BUFSIZE 32
 
@@ -133,6 +133,9 @@ static __u16 wiiproto_keymap[] = {
 	BTN_MODE,	/* WIIPROTO_KEY_HOME */
 };
 
+#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
+									dev))
+
 /* requires the state.lock spinlock to be held */
 static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
 								__u32 opt)
@@ -638,6 +641,34 @@ static int wiimote_ff_play(struct input_dev *dev, void *data,
 	return 0;
 }
 
+static ssize_t wiifs_battery_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	unsigned long flags;
+	int state, ret;
+
+	ret = wiimote_cmd_acquire(wdata);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
+	wiiproto_req_status(wdata);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_wait(wdata);
+	state = wdata->state.cmd_battery;
+	wiimote_cmd_release(wdata);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d\n", state);
+}
+
+static DEVICE_ATTR(battery, S_IRUGO, wiifs_battery_show, NULL);
+
 static int wiimote_input_open(struct input_dev *dev)
 {
 	struct wiimote_data *wdata = input_get_drvdata(dev);
@@ -1154,6 +1185,7 @@ err:
 static void wiimote_destroy(struct wiimote_data *wdata)
 {
 	wiimote_leds_destroy(wdata);
+	device_remove_file(&wdata->hdev->dev, &dev_attr_battery);
 
 	input_unregister_device(wdata->accel);
 	input_unregister_device(wdata->ir);
@@ -1206,6 +1238,10 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 		goto err_input;
 	}
 
+	ret = device_create_file(&hdev->dev, &dev_attr_battery);
+	if (ret)
+		goto err_free;
+
 	ret = wiimote_leds_create(wdata);
 	if (ret)
 		goto err_free;
-- 
1.7.6.1


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

* Re: [PATCH 14/14] HID: wiimote: Read wiimote battery charge level
  2011-08-29 13:38 ` [PATCH 14/14] HID: wiimote: Read wiimote battery charge level David Herrmann
@ 2011-08-29 14:28   ` Oliver Neukum
  2011-08-29 14:41     ` David Herrmann
  0 siblings, 1 reply; 17+ messages in thread
From: Oliver Neukum @ 2011-08-29 14:28 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Montag, 29. August 2011, 15:38:11 schrieb David Herrmann:
> This adds a new sysfs file for wiimotes which returns the current battery charge
> level of the device. Since this information is not sent by the wiimote
> continously, we need to explicitely request it.

Again I need to ask whether you really want a specific interface for
a functionality which is common to many devices.

	Regards
		Oliver

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

* Re: [PATCH 14/14] HID: wiimote: Read wiimote battery charge level
  2011-08-29 14:28   ` Oliver Neukum
@ 2011-08-29 14:41     ` David Herrmann
  0 siblings, 0 replies; 17+ messages in thread
From: David Herrmann @ 2011-08-29 14:41 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-input, jkosina, padovan

On Mon, Aug 29, 2011 at 4:28 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Montag, 29. August 2011, 15:38:11 schrieb David Herrmann:
>> This adds a new sysfs file for wiimotes which returns the current battery charge
>> level of the device. Since this information is not sent by the wiimote
>> continously, we need to explicitely request it.
>
> Again I need to ask whether you really want a specific interface for
> a functionality which is common to many devices.

Thanks for the hint. I will convert it to use "struct power_supply". I
wasn't aware it existed.
So patch 13 and 14 can be dropped from this set.

>        Regards
>                Oliver
>

Thanks
David
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2011-08-29 14:41 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-29 13:37 [PATCH 00/14] Extended Wiimote Support David Herrmann
2011-08-29 13:37 ` [PATCH 01/14] HID: wiimote: Support rumble device David Herrmann
2011-08-29 13:37 ` [PATCH 02/14] HID: wiimote: Add force-feedback support David Herrmann
2011-08-29 13:38 ` [PATCH 03/14] HID: wiimote: Add accelerometer input device David Herrmann
2011-08-29 13:38 ` [PATCH 04/14] HID: wiimote: Parse accelerometer data David Herrmann
2011-08-29 13:38 ` [PATCH 05/14] HID: wiimote: Add IR input device David Herrmann
2011-08-29 13:38 ` [PATCH 06/14] HID: wiimote: Parse IR data David Herrmann
2011-08-29 13:38 ` [PATCH 07/14] HID: wiimote: Add missing extension DRM handlers David Herrmann
2011-08-29 13:38 ` [PATCH 08/14] HID: wiimote: Add register/eeprom memory support David Herrmann
2011-08-29 13:38 ` [PATCH 09/14] HID: wiimote: Helper functions for synchronous requests David Herrmann
2011-08-29 13:38 ` [PATCH 10/14] HID: wiimote: Add write-register helpers David Herrmann
2011-08-29 13:38 ` [PATCH 11/14] HID: wiimote: Add IR initializer David Herrmann
2011-08-29 13:38 ` [PATCH 12/14] HID: wiimote: Initialize IR cam on request David Herrmann
2011-08-29 13:38 ` [PATCH 13/14] HID: wiimote: Add status request David Herrmann
2011-08-29 13:38 ` [PATCH 14/14] HID: wiimote: Read wiimote battery charge level David Herrmann
2011-08-29 14:28   ` Oliver Neukum
2011-08-29 14:41     ` David Herrmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.