All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] Extended wiimote support
@ 2011-07-28 16:08 David Herrmann
  2011-07-28 16:08 ` [PATCH 01/16] HID: wiimote: Support rumble device David Herrmann
                   ` (15 more replies)
  0 siblings, 16 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

Hi

This patch series adds support for extended wiimote features:
 - force-feedback / rumble
 - accelerometer
 - IR cam input for up to 4 trackable items
 - battery charge level
 - raw eeprom access

Most of the patches just extend the current driver with trivial features. The
only new interface is the "synchronous requests" API which allows to lock the
stream for a series of requests.

For userspace tools see:
  http://github.com/dvdhrm/xwiimote
tools/xwiishow.c visualizes all wiimote input and is great to test the driver.

The only missing feature is extension support which I am currently working on
and which is available in my xwiimote_kernel repository. So after this series I
will submit one last series of patches for extension support.

It would be great to get some review and feedback. The current bluez repo also
has a wiimote plugin so pairing should be as simple as with other devices now.
The next bluez release will bring it to the distros, eventually.

I've set the KernelRelease of the sysfs docs to 3.2 so there is no time pressure
for 3.1.

Regards
David

David Herrmann (16):
  HID: wiimote: Support rumble device
  HID: wiimote: Add sysfs rumble attribute
  HID: wiimote: Add drm request
  HID: wiimote: Add status and return request handlers
  HID: wiimote: Reduce input syncs
  HID: wiimote: Enable accelerometer on request
  HID: wiimote: Parse accelerometer data
  HID: wiimote: Parse IR input and report to userspace
  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: Allow userspace to control IR cam
  HID: wiimote: Read wiimote battery charge level
  HID: wiimote: Allow EEPROM debugfs access

 Documentation/ABI/testing/sysfs-driver-hid-wiimote |   34 +
 drivers/hid/hid-wiimote.c                          |  965 +++++++++++++++++++-
 2 files changed, 993 insertions(+), 6 deletions(-)

-- 
1.7.6


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

* [PATCH 01/16] HID: wiimote: Support rumble device
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 02/16] HID: wiimote: Add sysfs rumble attribute David Herrmann
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 |   44 ++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index a594383..6fa73c7 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -46,14 +46,16 @@ 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)
 
 enum wiiproto_reqs {
+	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM_K = 0x30,
 };
@@ -168,6 +170,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];
@@ -189,6 +224,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));
 }
 
-- 
1.7.6


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

* [PATCH 02/16] HID: wiimote: Add sysfs rumble attribute
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
  2011-07-28 16:08 ` [PATCH 01/16] HID: wiimote: Support rumble device David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 03/16] HID: wiimote: Add drm request David Herrmann
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

Add "rumble" attribute to sysfs for every wiimote to allow userspace to control
the rumble motor of a wiimote.

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

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index 5d5a16e..235dd47 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>/rumble
+Date:		July 2011
+KernelVersion:	3.2
+Contact:	David Herrmann <dh.herrmann@googlemail.com>
+Description:	Writing 1 to this file enables the rumble motor on the wiimote
+		and writing 0 disables it again. Reading from this file returns
+		1 if rumble is on and 0 if it is off.
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 6fa73c7..4070060 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -277,6 +277,43 @@ wiifs_led_show_set(2);
 wiifs_led_show_set(3);
 wiifs_led_show_set(4);
 
+static ssize_t wiifs_rumble_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	unsigned long flags;
+	int state;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	state = !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t wiifs_rumble_set(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	int tmp = simple_strtoul(buf, NULL, 10);
+	unsigned long flags;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiiproto_req_rumble(wdata, tmp);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return count;
+}
+
+static DEVICE_ATTR(rumble, S_IRUGO | S_IWUSR, wiifs_rumble_show,
+							wiifs_rumble_set);
+
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
 						unsigned int code, int value)
 {
@@ -425,6 +462,9 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 	ret = device_create_file(&hdev->dev, &dev_attr_led4);
 	if (ret)
 		goto err;
+	ret = device_create_file(&hdev->dev, &dev_attr_rumble);
+	if (ret)
+		goto err;
 
 	ret = hid_parse(hdev);
 	if (ret) {
@@ -464,6 +504,7 @@ err:
 	device_remove_file(&hdev->dev, &dev_attr_led2);
 	device_remove_file(&hdev->dev, &dev_attr_led3);
 	device_remove_file(&hdev->dev, &dev_attr_led4);
+	device_remove_file(&hdev->dev, &dev_attr_rumble);
 	wiimote_destroy(wdata);
 	return ret;
 }
@@ -478,6 +519,7 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 	device_remove_file(&hdev->dev, &dev_attr_led2);
 	device_remove_file(&hdev->dev, &dev_attr_led3);
 	device_remove_file(&hdev->dev, &dev_attr_led4);
+	device_remove_file(&hdev->dev, &dev_attr_rumble);
 
 	hid_hw_stop(hdev);
 	input_unregister_device(wdata->input);
-- 
1.7.6


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

* [PATCH 03/16] HID: wiimote: Add drm request
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
  2011-07-28 16:08 ` [PATCH 01/16] HID: wiimote: Support rumble device David Herrmann
  2011-07-28 16:08 ` [PATCH 02/16] HID: wiimote: Add sysfs rumble attribute David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 18:05   ` Oliver Neukum
  2011-07-28 16:08 ` [PATCH 04/16] HID: wiimote: Add status and return request handlers David Herrmann
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

The wiimote reports data in several data reporting modes (DRM). The DRM
request makes the wiimote send data in the requested drm.

The DRM mode can be set explicitely or can be calculated by the driver. To let
the driver choose the DRM mode, pass WIIPROTO_REQ_NULL placeholder to it. This
is no valid request and is replaced with an appropriate DRM.

Currently, the driver always sets the basic DRM_K mode, but this will be
extended when further peripherals like accelerometer and IR are supported.

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

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 4070060..dfb8707 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -55,8 +55,10 @@ struct wiimote_data {
 					WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
 
 enum wiiproto_reqs {
+	WIIPROTO_REQ_NULL = 0x0,
 	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
+	WIIPROTO_REQ_DRM = 0x12,
 	WIIPROTO_REQ_DRM_K = 0x30,
 };
 
@@ -228,6 +230,31 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+/*
+ * Check what peripherals of the wiimote are currently
+ * active and select a proper DRM that supports all of
+ * the requested data inputs.
+ */
+static __u8 select_drm(struct wiimote_data *wdata)
+{
+	return WIIPROTO_REQ_DRM_K;
+}
+
+static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
+{
+	__u8 cmd[3];
+
+	if (drm == WIIPROTO_REQ_NULL)
+		drm = select_drm(wdata);
+
+	cmd[0] = WIIPROTO_REQ_DRM;
+	cmd[1] = 0;
+	cmd[2] = drm;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 #define wiifs_led_show_set(num)						\
 static ssize_t wiifs_led_show_##num(struct device *dev,			\
 			struct device_attribute *attr, char *buf)	\
-- 
1.7.6


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

* [PATCH 04/16] HID: wiimote: Add status and return request handlers
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (2 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 03/16] HID: wiimote: Add drm request David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 05/16] HID: wiimote: Reduce input syncs David Herrmann
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

The wiimote resets the current drm when an extension is plugged in.
Fortunately, it also sends a status report in this situation so we just
reset the drm on every status report to keep the drm consistent.

Also handle return reports from the wiimote which indicate success and
failure of requests that we've sent.

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

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index dfb8707..859950e 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -59,6 +59,8 @@ enum wiiproto_reqs {
 	WIIPROTO_REQ_RUMBLE = 0x10,
 	WIIPROTO_REQ_LED = 0x11,
 	WIIPROTO_REQ_DRM = 0x12,
+	WIIPROTO_REQ_STATUS = 0x20,
+	WIIPROTO_REQ_RETURN = 0x22,
 	WIIPROTO_REQ_DRM_K = 0x30,
 };
 
@@ -381,6 +383,26 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 	input_sync(wdata->input);
 }
 
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+	handler_keys(wdata, payload);
+
+	/* on status reports the drm is reset so we need to resend the drm */
+	wiiproto_req_drm(wdata, 0);
+}
+
+static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
+{
+	__u8 err = payload[3];
+	__u8 cmd = payload[2];
+
+	handler_keys(wdata, payload);
+
+	if (err)
+		hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
+									cmd);
+}
+
 struct wiiproto_handler {
 	__u8 id;
 	size_t size;
@@ -388,6 +410,8 @@ struct wiiproto_handler {
 };
 
 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 = 0 }
 };
-- 
1.7.6


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

* [PATCH 05/16] HID: wiimote: Reduce input syncs
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (3 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 04/16] HID: wiimote: Add status and return request handlers David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 06/16] HID: wiimote: Enable accelerometer on request David Herrmann
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

To avoid multiple input syncs to be sent when parsing multiple
peripheral inputs from the wiimote in future, we send the input-sync
after handling all input events and not after parsing each value. This avoids
waking up user-space handlers multiple times on a single incoming package.

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

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 859950e..bac4410 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -380,7 +380,6 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 							!!(payload[1] & 0x10));
 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME],
 							!!(payload[1] & 0x80));
-	input_sync(wdata->input);
 }
 
 static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
@@ -440,6 +439,7 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
 			h->func(wdata, &raw_data[1]);
 	}
 
+	input_sync(wdata->input);
 	spin_unlock_irqrestore(&wdata->state.lock, flags);
 
 	return 0;
-- 
1.7.6


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

* [PATCH 06/16] HID: wiimote: Enable accelerometer on request
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (4 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 05/16] HID: wiimote: Reduce input syncs David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 18:08   ` Oliver Neukum
  2011-07-28 16:08 ` [PATCH 07/16] HID: wiimote: Parse accelerometer data David Herrmann
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

The wiimote has an internal accelerometer which can report data to the host.
Userspace may now write to a new sysfs file to make the driver enable
accelerometer reporting. This is not enabled by default to reduce power
consumption of the wiimote. Accelerometer data is reported every few
milliseconds and thus consumes much bluetooth bandwidth which costs much energy
of the wiimote.
By writing 0 to the sysfs file, accelerometer reporting is disabled again.

The wiimotes accelerometer does not need to be enabled explicitely, we only need
to set the DRM to a mode which includes accelerometer data.

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

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index 235dd47..d8ccea8 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote
+++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
@@ -16,3 +16,11 @@ Contact:	David Herrmann <dh.herrmann@googlemail.com>
 Description:	Writing 1 to this file enables the rumble motor on the wiimote
 		and writing 0 disables it again. Reading from this file returns
 		1 if rumble is on and 0 if it is off.
+
+What:		/sys/bus/hid/drivers/wiimote/<dev>/accelerometer
+Date:		July 2011
+KernelVersion:	3.2
+Contact:	David Herrmann <dh.herrmann@googlemail.com>
+Description:	Writing 1 to this file enables accelerometer data reporting of
+		the wiimote, 0 disables it. Reading from this file returns the
+		current value.
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index bac4410..13c27b7 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -51,6 +51,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 +258,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);
+}
+
 #define wiifs_led_show_set(num)						\
 static ssize_t wiifs_led_show_##num(struct device *dev,			\
 			struct device_attribute *attr, char *buf)	\
@@ -343,6 +358,43 @@ static ssize_t wiifs_rumble_set(struct device *dev,
 static DEVICE_ATTR(rumble, S_IRUGO | S_IWUSR, wiifs_rumble_show,
 							wiifs_rumble_set);
 
+static ssize_t wiifs_accel_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	unsigned long flags;
+	int state;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	state = !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t wiifs_accel_set(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	int tmp = simple_strtoul(buf, NULL, 10);
+	unsigned long flags;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wiiproto_req_accel(wdata, tmp);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	return count;
+}
+
+static DEVICE_ATTR(accelerometer, S_IRUGO | S_IWUSR, wiifs_accel_show,
+							wiifs_accel_set);
+
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
 						unsigned int code, int value)
 {
@@ -516,6 +568,9 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 	ret = device_create_file(&hdev->dev, &dev_attr_rumble);
 	if (ret)
 		goto err;
+	ret = device_create_file(&hdev->dev, &dev_attr_accelerometer);
+	if (ret)
+		goto err;
 
 	ret = hid_parse(hdev);
 	if (ret) {
@@ -556,6 +611,7 @@ err:
 	device_remove_file(&hdev->dev, &dev_attr_led3);
 	device_remove_file(&hdev->dev, &dev_attr_led4);
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
+	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
 	wiimote_destroy(wdata);
 	return ret;
 }
@@ -571,6 +627,7 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 	device_remove_file(&hdev->dev, &dev_attr_led3);
 	device_remove_file(&hdev->dev, &dev_attr_led4);
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
+	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
 
 	hid_hw_stop(hdev);
 	input_unregister_device(wdata->input);
-- 
1.7.6


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

* [PATCH 07/16] HID: wiimote: Parse accelerometer data
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (5 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 06/16] HID: wiimote: Enable accelerometer on request David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 18:12   ` Oliver Neukum
  2011-07-28 16:08 ` [PATCH 08/16] HID: wiimote: Parse IR input and report to userspace David Herrmann
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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_X/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 13c27b7..6947c2d 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 {
@@ -63,6 +64,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 {
@@ -240,7 +247,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)
@@ -434,6 +444,32 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 							!!(payload[1] & 0x80));
 }
 
+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
+	 * Buttons data contains LSBs
+	 */
+
+	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_event(wdata->input, EV_ABS, ABS_X, x - 0x200);
+	input_event(wdata->input, EV_ABS, ABS_Y, y - 0x200);
+	input_event(wdata->input, EV_ABS, ABS_Z, z - 0x200);
+}
+
+
 static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 {
 	handler_keys(wdata, payload);
@@ -454,6 +490,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;
@@ -464,6 +550,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 }
 };
 
@@ -528,6 +620,14 @@ 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(EV_ABS, wdata->input->evbit);
+	set_bit(ABS_X, wdata->input->absbit);
+	set_bit(ABS_Y, wdata->input->absbit);
+	set_bit(ABS_Z, wdata->input->absbit);
+	input_set_abs_params(wdata->input, ABS_X, -500, 500, 2, 4);
+	input_set_abs_params(wdata->input, ABS_Y, -500, 500, 2, 4);
+	input_set_abs_params(wdata->input, ABS_Z, -500, 500, 2, 4);
+
 	spin_lock_init(&wdata->qlock);
 	INIT_WORK(&wdata->worker, wiimote_worker);
 
-- 
1.7.6


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

* [PATCH 08/16] HID: wiimote: Parse IR input and report to userspace
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (6 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 07/16] HID: wiimote: Parse accelerometer data David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 09/16] HID: wiimote: Add missing extension DRM handlers David Herrmann
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

A wiimote sends IR pointing information for up to 4 trackable IR lights. If less
lights are visible, the missing lights report max value. This patch adds parser
functions for IR input and reports this via ABS_HAT*XY values to the input
subsystem.

The IR cam can be in four states: off, basic, extended, full
The DRM chooser automatically chosses an DRM that matches the current IR cam
state so no information is lost.

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

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 6947c2d..ed7feb2 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -53,8 +53,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)
 
 enum wiiproto_reqs {
 	WIIPROTO_REQ_NULL = 0x0,
@@ -67,6 +72,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,
@@ -247,10 +253,22 @@ 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)
@@ -469,6 +487,40 @@ static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
 	input_event(wdata->input, EV_ABS, ABS_Z, z - 0x200);
 }
 
+#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;
+
+	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_event(wdata->input, EV_ABS, xid, x);
+	input_event(wdata->input, EV_ABS, yid, y);
+}
 
 static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 {
@@ -500,6 +552,19 @@ 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);
+}
+
+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);
 }
 
 static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
@@ -512,6 +577,10 @@ 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);
 }
 
 static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
@@ -521,6 +590,9 @@ 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);
 }
 
 static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
@@ -538,6 +610,9 @@ 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);
 }
 
 struct wiiproto_handler {
@@ -553,6 +628,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 },
@@ -628,6 +704,23 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 	input_set_abs_params(wdata->input, ABS_Y, -500, 500, 2, 4);
 	input_set_abs_params(wdata->input, ABS_Z, -500, 500, 2, 4);
 
+	set_bit(ABS_HAT0X, wdata->input->absbit);
+	set_bit(ABS_HAT0Y, wdata->input->absbit);
+	set_bit(ABS_HAT1X, wdata->input->absbit);
+	set_bit(ABS_HAT1Y, wdata->input->absbit);
+	set_bit(ABS_HAT2X, wdata->input->absbit);
+	set_bit(ABS_HAT2Y, wdata->input->absbit);
+	set_bit(ABS_HAT3X, wdata->input->absbit);
+	set_bit(ABS_HAT3Y, wdata->input->absbit);
+	input_set_abs_params(wdata->input, ABS_HAT0X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT0Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT1X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT1Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT2X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT2Y, 0, 767, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT3X, 0, 1023, 2, 4);
+	input_set_abs_params(wdata->input, ABS_HAT3Y, 0, 767, 2, 4);
+
 	spin_lock_init(&wdata->qlock);
 	INIT_WORK(&wdata->worker, wiimote_worker);
 
-- 
1.7.6


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

* [PATCH 09/16] HID: wiimote: Add missing extension DRM handlers
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (7 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 08/16] HID: wiimote: Parse IR input and report to userspace David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 10/16] HID: wiimote: Add register/eeprom memory support David Herrmann
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 ed7feb2..066beb5 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -70,10 +70,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,
 };
@@ -548,6 +551,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);
@@ -558,6 +566,11 @@ static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
 	ir_to_input3(wdata, &payload[14], false);
 }
 
+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);
@@ -583,6 +596,10 @@ static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
 	ir_to_input3(wdata, &payload[12], true);
 }
 
+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);
@@ -626,10 +643,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 }
@@ -642,6 +662,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 (!atomic_read(&wdata->ready))
 		return -EBUSY;
@@ -655,13 +676,19 @@ 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;
+		}
 	}
 
 	input_sync(wdata->input);
 	spin_unlock_irqrestore(&wdata->state.lock, flags);
 
+	if (!handled)
+		hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
+									size);
+
 	return 0;
 }
 
-- 
1.7.6


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

* [PATCH 10/16] HID: wiimote: Add register/eeprom memory support
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (8 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 09/16] HID: wiimote: Add missing extension DRM handlers David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 11/16] HID: wiimote: Helper functions for synchronous requests David Herrmann
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 |   71 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 066beb5..7b59822 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -66,7 +66,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,
@@ -303,6 +306,68 @@ 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));
+}
+
+#define wiiproto_req_rreg(wdata, os, sz) \
+			wiiproto_req_rmem((wdata), false, (os), (sz))
+
+#define wiiproto_req_reeprom(wdata, os, sz) \
+			wiiproto_req_rmem((wdata), true, (os), (sz))
+
+static void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
+						__u32 offset, __u16 size)
+{
+	__u8 cmd[7];
+
+	if (size == 0) {
+		hid_warn(wdata->hdev, "Invalid length %d rmem request\n", size);
+		return;
+	}
+
+	cmd[0] = WIIPROTO_REQ_RMEM;
+	cmd[1] = 0;
+	cmd[2] = (offset >> 16) & 0xff;
+	cmd[3] = (offset >> 8) & 0xff;
+	cmd[4] = offset & 0xff;
+	cmd[5] = (size >> 8) & 0xff;
+	cmd[6] = size & 0xff;
+
+	if (!eeprom)
+		cmd[1] |= 0x04;
+
+	wiiproto_keep_rumble(wdata, &cmd[1]);
+	wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
 #define wiifs_led_show_set(num)						\
 static ssize_t wiifs_led_show_##num(struct device *dev,			\
 			struct device_attribute *attr, char *buf)	\
@@ -533,6 +598,11 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 	wiiproto_req_drm(wdata, 0);
 }
 
+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];
@@ -640,6 +710,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


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

* [PATCH 11/16] HID: wiimote: Helper functions for synchronous requests
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (9 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 10/16] HID: wiimote: Add register/eeprom memory support David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 12/16] HID: wiimote: Add write-register helpers David Herrmann
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 7b59822..0181971 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -11,10 +11,12 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/input.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 {
@@ -116,6 +124,52 @@ static __u16 wiiproto_keymap[] = {
 #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)
+{
+	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)
 {
@@ -823,6 +877,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


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

* [PATCH 12/16] HID: wiimote: Add write-register helpers
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (10 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 11/16] HID: wiimote: Helper functions for synchronous requests David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 13/16] HID: wiimote: Add IR initializer David Herrmann
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 |   27 ++++++++++++++++++++++++++-
 1 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 0181971..c6b1d24 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 {
@@ -422,6 +425,24 @@ static void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
 	wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
+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;
+}
+
 #define wiifs_led_show_set(num)						\
 static ssize_t wiifs_led_show_##num(struct device *dev,			\
 			struct device_attribute *attr, char *buf)	\
@@ -664,9 +685,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


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

* [PATCH 13/16] HID: wiimote: Add IR initializer
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (11 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 12/16] HID: wiimote: Add write-register helpers David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 14/16] HID: wiimote: Allow userspace to control IR cam David Herrmann
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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 |  134 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 134 insertions(+), 0 deletions(-)

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index c6b1d24..bca46ba 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -77,8 +77,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,
@@ -363,6 +365,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))
 
@@ -443,6 +467,116 @@ 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 };
+
+	ret = wiimote_cmd_acquire(wdata);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+
+	if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
+		spin_unlock_irqrestore(&wdata->state.lock, flags);
+		goto unlock;
+	}
+
+	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);
+		goto unlock;
+	}
+
+	/* send PIXEL CLOCK ENABLE cmd first */
+	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 then */
+	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_req_drm(wdata, 0);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+unlock:
+	wiimote_cmd_release(wdata);
+	return ret;
+}
+
 #define wiifs_led_show_set(num)						\
 static ssize_t wiifs_led_show_##num(struct device *dev,			\
 			struct device_attribute *attr, char *buf)	\
-- 
1.7.6


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

* [PATCH 14/16] HID: wiimote: Allow userspace to control IR cam
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (12 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 13/16] HID: wiimote: Add IR initializer David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 15/16] HID: wiimote: Read wiimote battery charge level David Herrmann
  2011-07-28 16:08 ` [PATCH 16/16] HID: wiimote: Allow EEPROM debugfs access David Herrmann
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

This adds a new sysfs attribute to wiimotes which allows userspace to enable or
disable the IR cam and set it into the desired mode.

Disabling IR saves lots of energy on the wiimote, so it is not enabled by
default.

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

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index d8ccea8..4ec761d 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote
+++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
@@ -24,3 +24,13 @@ Contact:	David Herrmann <dh.herrmann@googlemail.com>
 Description:	Writing 1 to this file enables accelerometer data reporting of
 		the wiimote, 0 disables it. Reading from this file returns the
 		current value.
+
+What:		/sys/bus/hid/drivers/wiimote/<dev>/ir
+Date:		July 2011
+KernelVersion:	3.2
+Contact:	David Herrmann <dh.herrmann@googlemail.com>
+Description:	Reading this attribute returns the current status of the IR
+		cam of the wiimote. It can be one of: off, basic, extended or
+		full.
+		Writing one of these strings to the file tries to put the IR
+		cam into the desired state.
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index bca46ba..69a555a3 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -700,6 +700,75 @@ static ssize_t wiifs_accel_set(struct device *dev,
 static DEVICE_ATTR(accelerometer, S_IRUGO | S_IWUSR, wiifs_accel_show,
 							wiifs_accel_set);
 
+static ssize_t wiifs_ir_show(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	unsigned long flags;
+	const char *mode;
+	__u8 flag;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	flag = wdata->state.flags & WIIPROTO_FLAGS_IR;
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	switch (flag) {
+		case WIIPROTO_FLAG_IR_FULL:
+			mode = "full";
+			break;
+		case WIIPROTO_FLAG_IR_EXT:
+			mode = "extended";
+			break;
+		case WIIPROTO_FLAG_IR_BASIC:
+			mode = "basic";
+			break;
+		default:
+			mode = "off";
+			break;
+	}
+
+
+	return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t wiifs_ir_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct wiimote_data *wdata = dev_to_wii(dev);
+	int ret;
+	__u8 mode;
+
+	if (count == 0)
+		return -EINVAL;
+
+	if (!strncasecmp("basic", buf, 5))
+		mode = WIIPROTO_FLAG_IR_BASIC;
+	else if (!strncasecmp("extended", buf, 8))
+		mode = WIIPROTO_FLAG_IR_EXT;
+	else if (!strncasecmp("full", buf, 4))
+		mode = WIIPROTO_FLAG_IR_FULL;
+	else if (!strncasecmp("off", buf, 3))
+		mode = 0;
+	else
+		return -EINVAL;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+	/* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
+	smp_rmb();
+
+	ret = wiimote_init_ir(wdata, mode);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(ir, S_IRUGO | S_IWUSR, wiifs_ir_show, wiifs_ir_set);
+
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
 						unsigned int code, int value)
 {
@@ -1077,6 +1146,9 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 	ret = device_create_file(&hdev->dev, &dev_attr_accelerometer);
 	if (ret)
 		goto err;
+	ret = device_create_file(&hdev->dev, &dev_attr_ir);
+	if (ret)
+		goto err;
 
 	ret = hid_parse(hdev);
 	if (ret) {
@@ -1118,6 +1190,7 @@ err:
 	device_remove_file(&hdev->dev, &dev_attr_led4);
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
 	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
+	device_remove_file(&hdev->dev, &dev_attr_ir);
 	wiimote_destroy(wdata);
 	return ret;
 }
@@ -1134,6 +1207,7 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 	device_remove_file(&hdev->dev, &dev_attr_led4);
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
 	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
+	device_remove_file(&hdev->dev, &dev_attr_ir);
 
 	hid_hw_stop(hdev);
 	input_unregister_device(wdata->input);
-- 
1.7.6


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

* [PATCH 15/16] HID: wiimote: Read wiimote battery charge level
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (13 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 14/16] HID: wiimote: Allow userspace to control IR cam David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  2011-07-28 16:08 ` [PATCH 16/16] HID: wiimote: Allow EEPROM debugfs access David Herrmann
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.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.

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

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index 4ec761d..ab41561 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote
+++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
@@ -34,3 +34,11 @@ Description:	Reading this attribute returns the current status of the IR
 		full.
 		Writing one of these strings to the file tries to put the IR
 		cam into the desired state.
+
+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 69a555a3..64200e5 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;
 };
 
@@ -78,6 +79,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,
@@ -351,6 +353,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;
@@ -700,6 +713,39 @@ static ssize_t wiifs_accel_set(struct device *dev,
 static DEVICE_ATTR(accelerometer, S_IRUGO | S_IWUSR, wiifs_accel_show,
 							wiifs_accel_set);
 
+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;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+	/* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
+	smp_rmb();
+
+	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 ssize_t wiifs_ir_show(struct device *dev, struct device_attribute *attr,
 								char *buf)
 {
@@ -874,6 +920,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, 0);
+
+	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)
@@ -1149,6 +1200,9 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 	ret = device_create_file(&hdev->dev, &dev_attr_ir);
 	if (ret)
 		goto err;
+	ret = device_create_file(&hdev->dev, &dev_attr_battery);
+	if (ret)
+		goto err;
 
 	ret = hid_parse(hdev);
 	if (ret) {
@@ -1191,6 +1245,7 @@ err:
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
 	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
 	device_remove_file(&hdev->dev, &dev_attr_ir);
+	device_remove_file(&hdev->dev, &dev_attr_battery);
 	wiimote_destroy(wdata);
 	return ret;
 }
@@ -1208,6 +1263,7 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 	device_remove_file(&hdev->dev, &dev_attr_rumble);
 	device_remove_file(&hdev->dev, &dev_attr_accelerometer);
 	device_remove_file(&hdev->dev, &dev_attr_ir);
+	device_remove_file(&hdev->dev, &dev_attr_battery);
 
 	hid_hw_stop(hdev);
 	input_unregister_device(wdata->input);
-- 
1.7.6


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

* [PATCH 16/16] HID: wiimote: Allow EEPROM debugfs access
  2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
                   ` (14 preceding siblings ...)
  2011-07-28 16:08 ` [PATCH 15/16] HID: wiimote: Read wiimote battery charge level David Herrmann
@ 2011-07-28 16:08 ` David Herrmann
  15 siblings, 0 replies; 26+ messages in thread
From: David Herrmann @ 2011-07-28 16:08 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, padovan, dh.herrmann

Add "eeprom" file to debugfs for every wiimote. Reading from this file allows to
read the internal EEPROM of a wiimote. Writing to eeprom is currently not
allowed and eeprom memory hasn't been reverse-engineered, yet.

This file shall only be used for debugging. Reading large blocks from this file
may block other access to the wiimote, hence, each block has been limited to 16
bytes to avoid large memory transfers while holding the wiimote lock.

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

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 64200e5..56cdb3b 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -12,12 +12,14 @@
 
 #include <linux/atomic.h>
 #include <linux/completion.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/uaccess.h>
 #include "hid-ids.h"
 
 #define WIIMOTE_VERSION "0.1"
@@ -43,6 +45,8 @@ struct wiimote_state {
 	/* results of synchronous requests */
 	__u8 cmd_battery;
 	__u8 cmd_err;
+	__u8 *cmd_read_buf;
+	__u8 cmd_read_size;
 };
 
 struct wiimote_data {
@@ -57,6 +61,10 @@ struct wiimote_data {
 	struct work_struct worker;
 
 	struct wiimote_state state;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debug_eeprom;
+#endif
 };
 
 #define WIIPROTO_FLAG_LED1		0x01
@@ -815,6 +823,110 @@ static ssize_t wiifs_ir_set(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(ir, S_IRUGO | S_IWUSR, wiifs_ir_show, wiifs_ir_set);
 
+#ifdef CONFIG_DEBUG_FS
+
+static int wiifs_eeprom_open(struct inode *i, struct file *f)
+{
+	f->private_data = i->i_private;
+	return 0;
+}
+
+static ssize_t wiifs_eeprom_read(struct file *f, char __user *u, size_t s,
+								loff_t *off)
+{
+	struct wiimote_data *wdata = f->private_data;
+	unsigned long flags;
+	ssize_t ret;
+	char *buf;
+	__u16 size;
+
+	if (s == 0)
+		return -EINVAL;
+	if (*off > 0xffffff)
+		return 0;
+	if (s > 16)
+		s = 16;
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+	/* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
+	smp_rmb();
+
+	buf = kmalloc(s, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = wiimote_cmd_acquire(wdata);
+	if (ret)
+		goto error;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.cmd_read_size = s;
+	wdata->state.cmd_read_buf = buf;
+	wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, *off & 0xffff);
+	wiiproto_req_reeprom(wdata, *off, s);
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	ret = wiimote_cmd_wait(wdata);
+	if (!ret)
+		size = wdata->state.cmd_read_size;
+
+	spin_lock_irqsave(&wdata->state.lock, flags);
+	wdata->state.cmd_read_buf = NULL;
+	spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+	wiimote_cmd_release(wdata);
+
+	if (ret)
+		goto error;
+	if (size == 0) {
+		ret = -EIO;
+		goto error;
+	}
+	if (copy_to_user(u, buf, size)) {
+		ret = -EFAULT;
+		goto error;
+	}
+
+	*off += size;
+	ret = size;
+
+error:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations wiifs_eeprom_fops = {
+	.owner = THIS_MODULE,
+	.open = wiifs_eeprom_open,
+	.read = wiifs_eeprom_read,
+	.llseek = generic_file_llseek,
+};
+
+static void wiimote_debugfs_init(struct wiimote_data *wdata)
+{
+	wdata->debug_eeprom = debugfs_create_file("eeprom", S_IRUSR,
+			wdata->hdev->debug_dir, wdata, &wiifs_eeprom_fops);
+}
+
+static void wiimote_debugfs_deinit(struct wiimote_data *wdata)
+{
+	if (wdata->debug_eeprom)
+		debugfs_remove(wdata->debug_eeprom);
+}
+
+#else /* CONFIG_DEBUG_FS */
+
+static void wiimote_debugfs_init(void *s)
+{
+}
+
+static void wiimote_debugfs_deinit(void *s)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
 						unsigned int code, int value)
 {
@@ -929,7 +1041,23 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
 
 static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
 {
+	__u16 offset = payload[3] << 8 | payload[4];
+	__u8 size = (payload[2] >> 4) + 1;
+	__u8 err = payload[2] & 0x0f;
+
 	handler_keys(wdata, payload);
+
+	if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_RMEM, offset)) {
+		if (err)
+			size = 0;
+		else if (size > wdata->state.cmd_read_size)
+			size = wdata->state.cmd_read_size;
+
+		wdata->state.cmd_read_size = size;
+		if (wdata->state.cmd_read_buf)
+			memcpy(wdata->state.cmd_read_buf, &payload[5], size);
+		wiimote_cmd_complete(wdata);
+	}
 }
 
 static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
@@ -1222,6 +1350,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
 		goto err_stop;
 	}
 
+	wiimote_debugfs_init(wdata);
+
 	/* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
 	smp_wmb();
 	atomic_set(&wdata->ready, 1);
@@ -1256,6 +1386,7 @@ static void wiimote_hid_remove(struct hid_device *hdev)
 
 	hid_info(hdev, "Device removed\n");
 
+	wiimote_debugfs_deinit(wdata);
 	device_remove_file(&hdev->dev, &dev_attr_led1);
 	device_remove_file(&hdev->dev, &dev_attr_led2);
 	device_remove_file(&hdev->dev, &dev_attr_led3);
-- 
1.7.6


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

* Re: [PATCH 03/16] HID: wiimote: Add drm request
  2011-07-28 16:08 ` [PATCH 03/16] HID: wiimote: Add drm request David Herrmann
@ 2011-07-28 18:05   ` Oliver Neukum
  2011-07-28 18:41     ` David Herrmann
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Neukum @ 2011-07-28 18:05 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Donnerstag, 28. Juli 2011, 18:08:23 schrieb David Herrmann:
> +static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
> +{
> +       __u8 cmd[3];

Are you sure these buffers nned not be safe for DMA?

	Regards
		Oliver
-- 
- - - 
SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 16746 (AG Nürnberg) 
Maxfeldstraße 5                         
90409 Nürnberg 
Germany 
- - - 
--
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] 26+ messages in thread

* Re: [PATCH 06/16] HID: wiimote: Enable accelerometer on request
  2011-07-28 16:08 ` [PATCH 06/16] HID: wiimote: Enable accelerometer on request David Herrmann
@ 2011-07-28 18:08   ` Oliver Neukum
  2011-07-28 19:01     ` David Herrmann
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Neukum @ 2011-07-28 18:08 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Donnerstag, 28. Juli 2011, 18:08:26 schrieb David Herrmann:
> The wiimote has an internal accelerometer which can report data to the host.
> Userspace may now write to a new sysfs file to make the driver enable
> accelerometer reporting. This is not enabled by default to reduce power
> consumption of the wiimote. Accelerometer data is reported every few
> milliseconds and thus consumes much bluetooth bandwidth which costs much energy
> of the wiimote.
> By writing 0 to the sysfs file, accelerometer reporting is disabled again.

This is an odd interface. Why can't you request the accelerometer data when
a device file dedicated to the accelerometer is opened?

	Regards
		Oliver
-- 
- - - 
SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 16746 (AG Nürnberg) 
Maxfeldstraße 5                         
90409 Nürnberg 
Germany 
- - - 
--
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] 26+ messages in thread

* Re: [PATCH 07/16] HID: wiimote: Parse accelerometer data
  2011-07-28 16:08 ` [PATCH 07/16] HID: wiimote: Parse accelerometer data David Herrmann
@ 2011-07-28 18:12   ` Oliver Neukum
  2011-07-28 18:51     ` David Herrmann
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Neukum @ 2011-07-28 18:12 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Donnerstag, 28. Juli 2011, 18:08:27 schrieb David Herrmann:
> +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
> +        * Buttons data contains LSBs
> +        */
> +
> +       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;

Could you make the comments a bit clearer. Those last lines are impossible
to understand.

	Regards
		Oliver
-- 
- - - 
SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 16746 (AG Nürnberg) 
Maxfeldstraße 5                         
90409 Nürnberg 
Germany 
- - - 
--
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] 26+ messages in thread

* Re: [PATCH 03/16] HID: wiimote: Add drm request
  2011-07-28 18:05   ` Oliver Neukum
@ 2011-07-28 18:41     ` David Herrmann
  2011-07-28 18:47       ` Oliver Neukum
  0 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 18:41 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-input, jkosina, padovan

On Thu, Jul 28, 2011 at 8:05 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Donnerstag, 28. Juli 2011, 18:08:23 schrieb David Herrmann:
>> +static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
>> +{
>> +       __u8 cmd[3];
>
> Are you sure these buffers nned not be safe for DMA?

wiimote_queue() allocates a buffer for every request. This should be
fine for DMA then. All wiimote_req_*() functions work the same way.

>        Regards
>                Oliver

Regards
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] 26+ messages in thread

* Re: [PATCH 03/16] HID: wiimote: Add drm request
  2011-07-28 18:41     ` David Herrmann
@ 2011-07-28 18:47       ` Oliver Neukum
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Neukum @ 2011-07-28 18:47 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Donnerstag, 28. Juli 2011, 20:41:18 schrieb David Herrmann:
> On Thu, Jul 28, 2011 at 8:05 PM, Oliver Neukum <oneukum@suse.de> wrote:
> > Am Donnerstag, 28. Juli 2011, 18:08:23 schrieb David Herrmann:
> >> +static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
> >> +{
> >> +       __u8 cmd[3];
> >
> > Are you sure these buffers nned not be safe for DMA?
> 
> wiimote_queue() allocates a buffer for every request. This should be
> fine for DMA then. All wiimote_req_*() functions work the same way.
> 

Yes, that's safe.

	Regards
		Oliver

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

* Re: [PATCH 07/16] HID: wiimote: Parse accelerometer data
  2011-07-28 18:12   ` Oliver Neukum
@ 2011-07-28 18:51     ` David Herrmann
  2011-08-10 11:55       ` Jiri Kosina
  0 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 18:51 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-input, jkosina, padovan

On Thu, Jul 28, 2011 at 8:12 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Donnerstag, 28. Juli 2011, 18:08:27 schrieb David Herrmann:
>> +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
>> +        * Buttons data contains LSBs
>> +        */
>> +
>> +       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;
>
> Could you make the comments a bit clearer. Those last lines are impossible
> to understand.

The LSBs are encoded in the "BB BB" data and I am extracting them. I
have documented the whole protocol in a separated document but if it
is common practice to add those comments to the code, I will add it in
the next version.

X, Y and Z data of accelerometer have 10 bits of precision. The data
is reported as 5 bytes:
BB BB XX YY ZZ
The first two bytes also contain the button data but there are 5
additional bits in the BB BB data that contain the LSBs of the
accelerometer.
XX YY ZZ are the upper 8 bits of the three accelerometer values.

BB BB have 8 bits. Bit 6 and 7 of first byte are LSBs of X value.
Bit 6 of second byte is LSB of Y value. Bit 7 of second byte is LSB of
Z value. The 10th bit of Y and Z are no available and set to 0.
As a table:

1st byte BB
Bit: 1 2 3 4 5 6 7 8
     ---------------
     B B B B B X X B

2nd byte BB
Bit: 1 2 3 4 5 6 7 8
     ---------------
     B B B B B Y Z B

B is button data and ignored here. handler_keys() takes care of them.

>        Regards
>                Oliver

Thanks for your review.
Regards
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] 26+ messages in thread

* Re: [PATCH 06/16] HID: wiimote: Enable accelerometer on request
  2011-07-28 18:08   ` Oliver Neukum
@ 2011-07-28 19:01     ` David Herrmann
  2011-07-28 19:32       ` Oliver Neukum
  0 siblings, 1 reply; 26+ messages in thread
From: David Herrmann @ 2011-07-28 19:01 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-input, jkosina, padovan

On Thu, Jul 28, 2011 at 8:08 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Donnerstag, 28. Juli 2011, 18:08:26 schrieb David Herrmann:
>> The wiimote has an internal accelerometer which can report data to the host.
>> Userspace may now write to a new sysfs file to make the driver enable
>> accelerometer reporting. This is not enabled by default to reduce power
>> consumption of the wiimote. Accelerometer data is reported every few
>> milliseconds and thus consumes much bluetooth bandwidth which costs much energy
>> of the wiimote.
>> By writing 0 to the sysfs file, accelerometer reporting is disabled again.
>
> This is an odd interface. Why can't you request the accelerometer data when
> a device file dedicated to the accelerometer is opened?

The API consists of sysfs and an input device. There is no way to be
able to see when accelerometer data is requested. Of course, I could
use ->open() callback on the input-layer. However, many use cases do
not require accelerometer data and bluetooth traffic is increased
heavily when accelerometer reports are enabled.
For instance if you only need button-reports, then one package per
button press is transmitted. With accelerometer reports, every 5ms a
package is transmitted. And the battery of the wiimote is quite
small...

I could create multiple input interfaces, one for button data, one for
accelerometer, one for IR etc. however, how can userspace know which
one is for which interface BEFORE opening it? It could open all of
them and close the ones it doesn't need, but is that better than
having a sysfs attribute?

I can see the problem with my approach. If multiple applications use
the wiimote and one disables the accelerometer, then the other
application has it also disabled. However, what other API would be
more appropriate here?

A char-dev would make the interface very easy but I tried to avoid
cdevs and ioctl()s since I was told so.

>        Regards
>                Oliver

Regards
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] 26+ messages in thread

* Re: [PATCH 06/16] HID: wiimote: Enable accelerometer on request
  2011-07-28 19:01     ` David Herrmann
@ 2011-07-28 19:32       ` Oliver Neukum
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Neukum @ 2011-07-28 19:32 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina, padovan

Am Donnerstag, 28. Juli 2011, 21:01:34 schrieb David Herrmann:
> I can see the problem with my approach. If multiple applications use
> the wiimote and one disables the accelerometer, then the other
> application has it also disabled. However, what other API would be
> more appropriate here?

So arguments can be seen for both. I suggest you ask this question
specifically on the lists before you introduce an API here.

	Regards
		Oliver
-- 
- - - 
SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 16746 (AG Nürnberg) 
Maxfeldstraße 5                         
90409 Nürnberg 
Germany 
- - - 
--
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] 26+ messages in thread

* Re: [PATCH 07/16] HID: wiimote: Parse accelerometer data
  2011-07-28 18:51     ` David Herrmann
@ 2011-08-10 11:55       ` Jiri Kosina
  0 siblings, 0 replies; 26+ messages in thread
From: Jiri Kosina @ 2011-08-10 11:55 UTC (permalink / raw)
  To: David Herrmann; +Cc: Oliver Neukum, linux-input, padovan

On Thu, 28 Jul 2011, David Herrmann wrote:

> >> +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
> >> +        * Buttons data contains LSBs
> >> +        */
> >> +
> >> +       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;
> >
> > Could you make the comments a bit clearer. Those last lines are impossible
> > to understand.
> 
> The LSBs are encoded in the "BB BB" data and I am extracting them. I
> have documented the whole protocol in a separated document but if it
> is common practice to add those comments to the code, I will add it in
> the next version.

In some cases, the usual way is to put a brief description of the 
protocol/data structures mandated by hardware in the comments at the very 
beginning of the driver file.

The description below seems like a perfect fit for such purpose. If you 
have much more elaborate description, it should probably go into 
Documentation/.

Thanks,

-- 
Jiri Kosina
SUSE Labs
--
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] 26+ messages in thread

end of thread, other threads:[~2011-08-10 11:55 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-28 16:08 [PATCH 00/16] Extended wiimote support David Herrmann
2011-07-28 16:08 ` [PATCH 01/16] HID: wiimote: Support rumble device David Herrmann
2011-07-28 16:08 ` [PATCH 02/16] HID: wiimote: Add sysfs rumble attribute David Herrmann
2011-07-28 16:08 ` [PATCH 03/16] HID: wiimote: Add drm request David Herrmann
2011-07-28 18:05   ` Oliver Neukum
2011-07-28 18:41     ` David Herrmann
2011-07-28 18:47       ` Oliver Neukum
2011-07-28 16:08 ` [PATCH 04/16] HID: wiimote: Add status and return request handlers David Herrmann
2011-07-28 16:08 ` [PATCH 05/16] HID: wiimote: Reduce input syncs David Herrmann
2011-07-28 16:08 ` [PATCH 06/16] HID: wiimote: Enable accelerometer on request David Herrmann
2011-07-28 18:08   ` Oliver Neukum
2011-07-28 19:01     ` David Herrmann
2011-07-28 19:32       ` Oliver Neukum
2011-07-28 16:08 ` [PATCH 07/16] HID: wiimote: Parse accelerometer data David Herrmann
2011-07-28 18:12   ` Oliver Neukum
2011-07-28 18:51     ` David Herrmann
2011-08-10 11:55       ` Jiri Kosina
2011-07-28 16:08 ` [PATCH 08/16] HID: wiimote: Parse IR input and report to userspace David Herrmann
2011-07-28 16:08 ` [PATCH 09/16] HID: wiimote: Add missing extension DRM handlers David Herrmann
2011-07-28 16:08 ` [PATCH 10/16] HID: wiimote: Add register/eeprom memory support David Herrmann
2011-07-28 16:08 ` [PATCH 11/16] HID: wiimote: Helper functions for synchronous requests David Herrmann
2011-07-28 16:08 ` [PATCH 12/16] HID: wiimote: Add write-register helpers David Herrmann
2011-07-28 16:08 ` [PATCH 13/16] HID: wiimote: Add IR initializer David Herrmann
2011-07-28 16:08 ` [PATCH 14/16] HID: wiimote: Allow userspace to control IR cam David Herrmann
2011-07-28 16:08 ` [PATCH 15/16] HID: wiimote: Read wiimote battery charge level David Herrmann
2011-07-28 16:08 ` [PATCH 16/16] HID: wiimote: Allow EEPROM debugfs access 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.