HID: wiimote: Parse IR data
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 6 Sep 2011 11:50:31 +0000 (13:50 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 7 Sep 2011 11:25:16 +0000 (13:25 +0200)
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>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-wiimote.c

index 4cdaaf6e0307c9e5fcf88b6abfc59ab82ffbe821..3a7dec0c9fe61f97795beb46da53be2e5a544b25 100644 (file)
@@ -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 },