@@ -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);
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(-)