Loading drivers/hid/hid-wiimote-core.c +14 −0 Original line number Diff line number Diff line Loading @@ -455,6 +455,12 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem) return WIIMOTE_EXT_BALANCE_BOARD; if (rmem[4] == 0x01 && rmem[5] == 0x20) return WIIMOTE_EXT_PRO_CONTROLLER; if (rmem[0] == 0x01 && rmem[1] == 0x00 && rmem[4] == 0x01 && rmem[5] == 0x03) return WIIMOTE_EXT_DRUMS; if (rmem[0] == 0x00 && rmem[1] == 0x00 && rmem[4] == 0x01 && rmem[5] == 0x03) return WIIMOTE_EXT_GUITAR; return WIIMOTE_EXT_UNKNOWN; } Loading Loading @@ -488,6 +494,8 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype) /* map MP with correct pass-through mode */ switch (exttype) { case WIIMOTE_EXT_CLASSIC_CONTROLLER: case WIIMOTE_EXT_DRUMS: case WIIMOTE_EXT_GUITAR: wmem = 0x07; break; case WIIMOTE_EXT_NUNCHUK: Loading Loading @@ -1075,6 +1083,8 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller", [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board", [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller", [WIIMOTE_EXT_DRUMS] = "Nintendo Wii Drums", [WIIMOTE_EXT_GUITAR] = "Nintendo Wii Guitar", }; /* Loading Loading @@ -1660,6 +1670,10 @@ static ssize_t wiimote_ext_show(struct device *dev, return sprintf(buf, "balanceboard\n"); case WIIMOTE_EXT_PRO_CONTROLLER: return sprintf(buf, "procontroller\n"); case WIIMOTE_EXT_DRUMS: return sprintf(buf, "drums\n"); case WIIMOTE_EXT_GUITAR: return sprintf(buf, "guitar\n"); case WIIMOTE_EXT_UNKNOWN: /* fallthrough */ default: Loading drivers/hid/hid-wiimote-modules.c +440 −0 Original line number Diff line number Diff line Loading @@ -1949,6 +1949,444 @@ static const struct wiimod_ops wiimod_pro = { .in_ext = wiimod_pro_in_ext, }; /* * Drums * Guitar-Hero, Rock-Band and other games came bundled with drums which can * be plugged as extension to a Wiimote. Drum-reports are still not entirely * figured out, but the most important information is known. * We create a separate device for drums and report all information via this * input device. */ static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata, __u8 none, __u8 which, __u8 pressure, __u8 onoff, __u8 *store, __u16 code, __u8 which_code) { static const __u8 default_pressure = 3; if (!none && which == which_code) { *store = pressure; input_report_abs(wdata->extension.input, code, *store); } else if (onoff != !!*store) { *store = onoff ? default_pressure : 0; input_report_abs(wdata->extension.input, code, *store); } } static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext) { __u8 pressure, which, none, hhp, sx, sy; __u8 o, r, y, g, b, bass, bm, bp; /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:0> | * 2 | 0 | 0 | SY <5:0> | * -----+-----+-----+-----------------------------+-----+ * 3 | HPP | NON | WHICH <5:1> | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | O | R | Y | G | B | BSS | 1 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * All buttons are 0 if pressed * * With Motion+ enabled, the following bits will get invalid: * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:1> |XXXXX| * 2 | 0 | 0 | SY <5:1> |XXXXX| * -----+-----+-----+-----------------------------+-----+ * 3 | HPP | NON | WHICH <5:1> | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ */ pressure = 7 - (ext[3] >> 5); which = (ext[2] >> 1) & 0x1f; none = !!(ext[2] & 0x40); hhp = !(ext[2] & 0x80); sx = ext[0] & 0x3f; sy = ext[1] & 0x3f; o = !(ext[5] & 0x80); r = !(ext[5] & 0x40); y = !(ext[5] & 0x20); g = !(ext[5] & 0x10); b = !(ext[5] & 0x08); bass = !(ext[5] & 0x04); bm = !(ext[4] & 0x10); bp = !(ext[4] & 0x04); if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { sx &= 0x3e; sy &= 0x3e; } wiimod_drums_report_pressure(wdata, none, which, pressure, o, &wdata->state.pressure_drums[0], ABS_HAT2Y, 0x0e); wiimod_drums_report_pressure(wdata, none, which, pressure, r, &wdata->state.pressure_drums[1], ABS_HAT0X, 0x19); wiimod_drums_report_pressure(wdata, none, which, pressure, y, &wdata->state.pressure_drums[2], ABS_HAT2X, 0x11); wiimod_drums_report_pressure(wdata, none, which, pressure, g, &wdata->state.pressure_drums[3], ABS_HAT1X, 0x12); wiimod_drums_report_pressure(wdata, none, which, pressure, b, &wdata->state.pressure_drums[4], ABS_HAT0Y, 0x0f); /* Bass shares pressure with hi-hat (set via hhp) */ wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure, bass, &wdata->state.pressure_drums[5], ABS_HAT3X, 0x1b); /* Hi-hat has no on/off values, just pressure. Force to off/0. */ wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure, 0, &wdata->state.pressure_drums[6], ABS_HAT3Y, 0x0e); input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); input_report_key(wdata->extension.input, BTN_START, bp); input_report_key(wdata->extension.input, BTN_SELECT, bm); input_sync(wdata->extension.input); } static int wiimod_drums_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimod_drums_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); } static int wiimod_drums_probe(const struct wiimod_ops *ops, struct wiimote_data *wdata) { int ret; wdata->extension.input = input_allocate_device(); if (!wdata->extension.input) return -ENOMEM; input_set_drvdata(wdata->extension.input, wdata); wdata->extension.input->open = wiimod_drums_open; wdata->extension.input->close = wiimod_drums_close; wdata->extension.input->dev.parent = &wdata->hdev->dev; wdata->extension.input->id.bustype = wdata->hdev->bus; wdata->extension.input->id.vendor = wdata->hdev->vendor; wdata->extension.input->id.product = wdata->hdev->product; wdata->extension.input->id.version = wdata->hdev->version; wdata->extension.input->name = WIIMOTE_NAME " Drums"; set_bit(EV_KEY, wdata->extension.input->evbit); set_bit(BTN_START, wdata->extension.input->keybit); set_bit(BTN_SELECT, wdata->extension.input->keybit); set_bit(EV_ABS, wdata->extension.input->evbit); set_bit(ABS_X, wdata->extension.input->absbit); set_bit(ABS_Y, wdata->extension.input->absbit); set_bit(ABS_HAT0X, wdata->extension.input->absbit); set_bit(ABS_HAT0Y, wdata->extension.input->absbit); set_bit(ABS_HAT1X, wdata->extension.input->absbit); set_bit(ABS_HAT2X, wdata->extension.input->absbit); set_bit(ABS_HAT2Y, wdata->extension.input->absbit); set_bit(ABS_HAT3X, wdata->extension.input->absbit); set_bit(ABS_HAT3Y, wdata->extension.input->absbit); input_set_abs_params(wdata->extension.input, ABS_X, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_Y, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT0X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT0Y, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT1X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT2X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT2Y, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT3X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT3Y, 0, 7, 0, 0); ret = input_register_device(wdata->extension.input); if (ret) goto err_free; return 0; err_free: input_free_device(wdata->extension.input); wdata->extension.input = NULL; return ret; } static void wiimod_drums_remove(const struct wiimod_ops *ops, struct wiimote_data *wdata) { if (!wdata->extension.input) return; input_unregister_device(wdata->extension.input); wdata->extension.input = NULL; } static const struct wiimod_ops wiimod_drums = { .flags = 0, .arg = 0, .probe = wiimod_drums_probe, .remove = wiimod_drums_remove, .in_ext = wiimod_drums_in_ext, }; /* * Guitar * Guitar-Hero, Rock-Band and other games came bundled with guitars which can * be plugged as extension to a Wiimote. * We create a separate device for guitars and report all information via this * input device. */ enum wiimod_guitar_keys { WIIMOD_GUITAR_KEY_G, WIIMOD_GUITAR_KEY_R, WIIMOD_GUITAR_KEY_Y, WIIMOD_GUITAR_KEY_B, WIIMOD_GUITAR_KEY_O, WIIMOD_GUITAR_KEY_UP, WIIMOD_GUITAR_KEY_DOWN, WIIMOD_GUITAR_KEY_PLUS, WIIMOD_GUITAR_KEY_MINUS, WIIMOD_GUITAR_KEY_NUM, }; static const __u16 wiimod_guitar_map[] = { BTN_1, /* WIIMOD_GUITAR_KEY_G */ BTN_2, /* WIIMOD_GUITAR_KEY_R */ BTN_3, /* WIIMOD_GUITAR_KEY_Y */ BTN_4, /* WIIMOD_GUITAR_KEY_B */ BTN_5, /* WIIMOD_GUITAR_KEY_O */ BTN_DPAD_UP, /* WIIMOD_GUITAR_KEY_UP */ BTN_DPAD_DOWN, /* WIIMOD_GUITAR_KEY_DOWN */ BTN_START, /* WIIMOD_GUITAR_KEY_PLUS */ BTN_SELECT, /* WIIMOD_GUITAR_KEY_MINUS */ }; static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext) { __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu; /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:0> | * 2 | 0 | 0 | SY <5:0> | * -----+-----+-----+-----+-----------------------------+ * 3 | 0 | 0 | 0 | TB <4:0> | * -----+-----+-----+-----+-----------------------------+ * 4 | 0 | 0 | 0 | WB <4:0> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BO | BR | BB | BG | BY | 1 | 1 | BU | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * All buttons are 0 if pressed * * With Motion+ enabled, it will look like this: * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:1> | BU | * 2 | 0 | 0 | SY <5:1> | 1 | * -----+-----+-----+-----+-----------------------+-----+ * 3 | 0 | 0 | 0 | TB <4:0> | * -----+-----+-----+-----+-----------------------------+ * 4 | 0 | 0 | 0 | WB <4:0> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ */ sx = ext[0] & 0x3f; sy = ext[1] & 0x3f; tb = ext[2] & 0x1f; wb = ext[3] & 0x1f; bd = !(ext[4] & 0x40); bm = !(ext[4] & 0x10); bp = !(ext[4] & 0x04); bo = !(ext[5] & 0x80); br = !(ext[5] & 0x40); bb = !(ext[5] & 0x20); bg = !(ext[5] & 0x10); by = !(ext[5] & 0x08); bu = !(ext[5] & 0x01); if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { bu = !(ext[0] & 0x01); sx &= 0x3e; sy &= 0x3e; } input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); input_report_abs(wdata->extension.input, ABS_HAT0X, tb); input_report_abs(wdata->extension.input, ABS_HAT1X, wb - 0x10); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], bg); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], br); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], by); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], bb); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], bo); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], bu); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], bd); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], bp); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], bm); input_sync(wdata->extension.input); } static int wiimod_guitar_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimod_guitar_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); } static int wiimod_guitar_probe(const struct wiimod_ops *ops, struct wiimote_data *wdata) { int ret, i; wdata->extension.input = input_allocate_device(); if (!wdata->extension.input) return -ENOMEM; input_set_drvdata(wdata->extension.input, wdata); wdata->extension.input->open = wiimod_guitar_open; wdata->extension.input->close = wiimod_guitar_close; wdata->extension.input->dev.parent = &wdata->hdev->dev; wdata->extension.input->id.bustype = wdata->hdev->bus; wdata->extension.input->id.vendor = wdata->hdev->vendor; wdata->extension.input->id.product = wdata->hdev->product; wdata->extension.input->id.version = wdata->hdev->version; wdata->extension.input->name = WIIMOTE_NAME " Guitar"; set_bit(EV_KEY, wdata->extension.input->evbit); for (i = 0; i < WIIMOD_GUITAR_KEY_NUM; ++i) set_bit(wiimod_guitar_map[i], wdata->extension.input->keybit); set_bit(EV_ABS, wdata->extension.input->evbit); set_bit(ABS_X, wdata->extension.input->absbit); set_bit(ABS_Y, wdata->extension.input->absbit); set_bit(ABS_HAT0X, wdata->extension.input->absbit); set_bit(ABS_HAT1X, wdata->extension.input->absbit); input_set_abs_params(wdata->extension.input, ABS_X, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_Y, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT0X, 0, 0x1f, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT1X, 0, 0x0f, 1, 1); ret = input_register_device(wdata->extension.input); if (ret) goto err_free; return 0; err_free: input_free_device(wdata->extension.input); wdata->extension.input = NULL; return ret; } static void wiimod_guitar_remove(const struct wiimod_ops *ops, struct wiimote_data *wdata) { if (!wdata->extension.input) return; input_unregister_device(wdata->extension.input); wdata->extension.input = NULL; } static const struct wiimod_ops wiimod_guitar = { .flags = 0, .arg = 0, .probe = wiimod_guitar_probe, .remove = wiimod_guitar_remove, .in_ext = wiimod_guitar_in_ext, }; /* * Builtin Motion Plus * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which Loading Loading @@ -2201,4 +2639,6 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic, [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro, [WIIMOTE_EXT_DRUMS] = &wiimod_drums, [WIIMOTE_EXT_GUITAR] = &wiimod_guitar, }; drivers/hid/hid-wiimote.h +3 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ enum wiimote_exttype { WIIMOTE_EXT_CLASSIC_CONTROLLER, WIIMOTE_EXT_BALANCE_BOARD, WIIMOTE_EXT_PRO_CONTROLLER, WIIMOTE_EXT_DRUMS, WIIMOTE_EXT_GUITAR, WIIMOTE_EXT_NUM, }; Loading Loading @@ -137,6 +139,7 @@ struct wiimote_state { /* calibration/cache data */ __u16 calib_bboard[4][3]; __s16 calib_pro_sticks[4]; __u8 pressure_drums[7]; __u8 cache_rumble; }; Loading Loading
drivers/hid/hid-wiimote-core.c +14 −0 Original line number Diff line number Diff line Loading @@ -455,6 +455,12 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem) return WIIMOTE_EXT_BALANCE_BOARD; if (rmem[4] == 0x01 && rmem[5] == 0x20) return WIIMOTE_EXT_PRO_CONTROLLER; if (rmem[0] == 0x01 && rmem[1] == 0x00 && rmem[4] == 0x01 && rmem[5] == 0x03) return WIIMOTE_EXT_DRUMS; if (rmem[0] == 0x00 && rmem[1] == 0x00 && rmem[4] == 0x01 && rmem[5] == 0x03) return WIIMOTE_EXT_GUITAR; return WIIMOTE_EXT_UNKNOWN; } Loading Loading @@ -488,6 +494,8 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype) /* map MP with correct pass-through mode */ switch (exttype) { case WIIMOTE_EXT_CLASSIC_CONTROLLER: case WIIMOTE_EXT_DRUMS: case WIIMOTE_EXT_GUITAR: wmem = 0x07; break; case WIIMOTE_EXT_NUNCHUK: Loading Loading @@ -1075,6 +1083,8 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller", [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board", [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller", [WIIMOTE_EXT_DRUMS] = "Nintendo Wii Drums", [WIIMOTE_EXT_GUITAR] = "Nintendo Wii Guitar", }; /* Loading Loading @@ -1660,6 +1670,10 @@ static ssize_t wiimote_ext_show(struct device *dev, return sprintf(buf, "balanceboard\n"); case WIIMOTE_EXT_PRO_CONTROLLER: return sprintf(buf, "procontroller\n"); case WIIMOTE_EXT_DRUMS: return sprintf(buf, "drums\n"); case WIIMOTE_EXT_GUITAR: return sprintf(buf, "guitar\n"); case WIIMOTE_EXT_UNKNOWN: /* fallthrough */ default: Loading
drivers/hid/hid-wiimote-modules.c +440 −0 Original line number Diff line number Diff line Loading @@ -1949,6 +1949,444 @@ static const struct wiimod_ops wiimod_pro = { .in_ext = wiimod_pro_in_ext, }; /* * Drums * Guitar-Hero, Rock-Band and other games came bundled with drums which can * be plugged as extension to a Wiimote. Drum-reports are still not entirely * figured out, but the most important information is known. * We create a separate device for drums and report all information via this * input device. */ static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata, __u8 none, __u8 which, __u8 pressure, __u8 onoff, __u8 *store, __u16 code, __u8 which_code) { static const __u8 default_pressure = 3; if (!none && which == which_code) { *store = pressure; input_report_abs(wdata->extension.input, code, *store); } else if (onoff != !!*store) { *store = onoff ? default_pressure : 0; input_report_abs(wdata->extension.input, code, *store); } } static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext) { __u8 pressure, which, none, hhp, sx, sy; __u8 o, r, y, g, b, bass, bm, bp; /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:0> | * 2 | 0 | 0 | SY <5:0> | * -----+-----+-----+-----------------------------+-----+ * 3 | HPP | NON | WHICH <5:1> | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | O | R | Y | G | B | BSS | 1 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * All buttons are 0 if pressed * * With Motion+ enabled, the following bits will get invalid: * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:1> |XXXXX| * 2 | 0 | 0 | SY <5:1> |XXXXX| * -----+-----+-----+-----------------------------+-----+ * 3 | HPP | NON | WHICH <5:1> | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ */ pressure = 7 - (ext[3] >> 5); which = (ext[2] >> 1) & 0x1f; none = !!(ext[2] & 0x40); hhp = !(ext[2] & 0x80); sx = ext[0] & 0x3f; sy = ext[1] & 0x3f; o = !(ext[5] & 0x80); r = !(ext[5] & 0x40); y = !(ext[5] & 0x20); g = !(ext[5] & 0x10); b = !(ext[5] & 0x08); bass = !(ext[5] & 0x04); bm = !(ext[4] & 0x10); bp = !(ext[4] & 0x04); if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { sx &= 0x3e; sy &= 0x3e; } wiimod_drums_report_pressure(wdata, none, which, pressure, o, &wdata->state.pressure_drums[0], ABS_HAT2Y, 0x0e); wiimod_drums_report_pressure(wdata, none, which, pressure, r, &wdata->state.pressure_drums[1], ABS_HAT0X, 0x19); wiimod_drums_report_pressure(wdata, none, which, pressure, y, &wdata->state.pressure_drums[2], ABS_HAT2X, 0x11); wiimod_drums_report_pressure(wdata, none, which, pressure, g, &wdata->state.pressure_drums[3], ABS_HAT1X, 0x12); wiimod_drums_report_pressure(wdata, none, which, pressure, b, &wdata->state.pressure_drums[4], ABS_HAT0Y, 0x0f); /* Bass shares pressure with hi-hat (set via hhp) */ wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure, bass, &wdata->state.pressure_drums[5], ABS_HAT3X, 0x1b); /* Hi-hat has no on/off values, just pressure. Force to off/0. */ wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure, 0, &wdata->state.pressure_drums[6], ABS_HAT3Y, 0x0e); input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); input_report_key(wdata->extension.input, BTN_START, bp); input_report_key(wdata->extension.input, BTN_SELECT, bm); input_sync(wdata->extension.input); } static int wiimod_drums_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimod_drums_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); } static int wiimod_drums_probe(const struct wiimod_ops *ops, struct wiimote_data *wdata) { int ret; wdata->extension.input = input_allocate_device(); if (!wdata->extension.input) return -ENOMEM; input_set_drvdata(wdata->extension.input, wdata); wdata->extension.input->open = wiimod_drums_open; wdata->extension.input->close = wiimod_drums_close; wdata->extension.input->dev.parent = &wdata->hdev->dev; wdata->extension.input->id.bustype = wdata->hdev->bus; wdata->extension.input->id.vendor = wdata->hdev->vendor; wdata->extension.input->id.product = wdata->hdev->product; wdata->extension.input->id.version = wdata->hdev->version; wdata->extension.input->name = WIIMOTE_NAME " Drums"; set_bit(EV_KEY, wdata->extension.input->evbit); set_bit(BTN_START, wdata->extension.input->keybit); set_bit(BTN_SELECT, wdata->extension.input->keybit); set_bit(EV_ABS, wdata->extension.input->evbit); set_bit(ABS_X, wdata->extension.input->absbit); set_bit(ABS_Y, wdata->extension.input->absbit); set_bit(ABS_HAT0X, wdata->extension.input->absbit); set_bit(ABS_HAT0Y, wdata->extension.input->absbit); set_bit(ABS_HAT1X, wdata->extension.input->absbit); set_bit(ABS_HAT2X, wdata->extension.input->absbit); set_bit(ABS_HAT2Y, wdata->extension.input->absbit); set_bit(ABS_HAT3X, wdata->extension.input->absbit); set_bit(ABS_HAT3Y, wdata->extension.input->absbit); input_set_abs_params(wdata->extension.input, ABS_X, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_Y, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT0X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT0Y, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT1X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT2X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT2Y, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT3X, 0, 7, 0, 0); input_set_abs_params(wdata->extension.input, ABS_HAT3Y, 0, 7, 0, 0); ret = input_register_device(wdata->extension.input); if (ret) goto err_free; return 0; err_free: input_free_device(wdata->extension.input); wdata->extension.input = NULL; return ret; } static void wiimod_drums_remove(const struct wiimod_ops *ops, struct wiimote_data *wdata) { if (!wdata->extension.input) return; input_unregister_device(wdata->extension.input); wdata->extension.input = NULL; } static const struct wiimod_ops wiimod_drums = { .flags = 0, .arg = 0, .probe = wiimod_drums_probe, .remove = wiimod_drums_remove, .in_ext = wiimod_drums_in_ext, }; /* * Guitar * Guitar-Hero, Rock-Band and other games came bundled with guitars which can * be plugged as extension to a Wiimote. * We create a separate device for guitars and report all information via this * input device. */ enum wiimod_guitar_keys { WIIMOD_GUITAR_KEY_G, WIIMOD_GUITAR_KEY_R, WIIMOD_GUITAR_KEY_Y, WIIMOD_GUITAR_KEY_B, WIIMOD_GUITAR_KEY_O, WIIMOD_GUITAR_KEY_UP, WIIMOD_GUITAR_KEY_DOWN, WIIMOD_GUITAR_KEY_PLUS, WIIMOD_GUITAR_KEY_MINUS, WIIMOD_GUITAR_KEY_NUM, }; static const __u16 wiimod_guitar_map[] = { BTN_1, /* WIIMOD_GUITAR_KEY_G */ BTN_2, /* WIIMOD_GUITAR_KEY_R */ BTN_3, /* WIIMOD_GUITAR_KEY_Y */ BTN_4, /* WIIMOD_GUITAR_KEY_B */ BTN_5, /* WIIMOD_GUITAR_KEY_O */ BTN_DPAD_UP, /* WIIMOD_GUITAR_KEY_UP */ BTN_DPAD_DOWN, /* WIIMOD_GUITAR_KEY_DOWN */ BTN_START, /* WIIMOD_GUITAR_KEY_PLUS */ BTN_SELECT, /* WIIMOD_GUITAR_KEY_MINUS */ }; static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext) { __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu; /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:0> | * 2 | 0 | 0 | SY <5:0> | * -----+-----+-----+-----+-----------------------------+ * 3 | 0 | 0 | 0 | TB <4:0> | * -----+-----+-----+-----+-----------------------------+ * 4 | 0 | 0 | 0 | WB <4:0> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BO | BR | BB | BG | BY | 1 | 1 | BU | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * All buttons are 0 if pressed * * With Motion+ enabled, it will look like this: * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 1 | 0 | 0 | SX <5:1> | BU | * 2 | 0 | 0 | SY <5:1> | 1 | * -----+-----+-----+-----+-----------------------+-----+ * 3 | 0 | 0 | 0 | TB <4:0> | * -----+-----+-----+-----+-----------------------------+ * 4 | 0 | 0 | 0 | WB <4:0> | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ * 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX| * -----+-----+-----+-----+-----+-----+-----+-----+-----+ */ sx = ext[0] & 0x3f; sy = ext[1] & 0x3f; tb = ext[2] & 0x1f; wb = ext[3] & 0x1f; bd = !(ext[4] & 0x40); bm = !(ext[4] & 0x10); bp = !(ext[4] & 0x04); bo = !(ext[5] & 0x80); br = !(ext[5] & 0x40); bb = !(ext[5] & 0x20); bg = !(ext[5] & 0x10); by = !(ext[5] & 0x08); bu = !(ext[5] & 0x01); if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { bu = !(ext[0] & 0x01); sx &= 0x3e; sy &= 0x3e; } input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); input_report_abs(wdata->extension.input, ABS_HAT0X, tb); input_report_abs(wdata->extension.input, ABS_HAT1X, wb - 0x10); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], bg); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], br); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], by); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], bb); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], bo); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], bu); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], bd); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], bp); input_report_key(wdata->extension.input, wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], bm); input_sync(wdata->extension.input); } static int wiimod_guitar_open(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; } static void wiimod_guitar_close(struct input_dev *dev) { struct wiimote_data *wdata = input_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&wdata->state.lock, flags); wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); spin_unlock_irqrestore(&wdata->state.lock, flags); } static int wiimod_guitar_probe(const struct wiimod_ops *ops, struct wiimote_data *wdata) { int ret, i; wdata->extension.input = input_allocate_device(); if (!wdata->extension.input) return -ENOMEM; input_set_drvdata(wdata->extension.input, wdata); wdata->extension.input->open = wiimod_guitar_open; wdata->extension.input->close = wiimod_guitar_close; wdata->extension.input->dev.parent = &wdata->hdev->dev; wdata->extension.input->id.bustype = wdata->hdev->bus; wdata->extension.input->id.vendor = wdata->hdev->vendor; wdata->extension.input->id.product = wdata->hdev->product; wdata->extension.input->id.version = wdata->hdev->version; wdata->extension.input->name = WIIMOTE_NAME " Guitar"; set_bit(EV_KEY, wdata->extension.input->evbit); for (i = 0; i < WIIMOD_GUITAR_KEY_NUM; ++i) set_bit(wiimod_guitar_map[i], wdata->extension.input->keybit); set_bit(EV_ABS, wdata->extension.input->evbit); set_bit(ABS_X, wdata->extension.input->absbit); set_bit(ABS_Y, wdata->extension.input->absbit); set_bit(ABS_HAT0X, wdata->extension.input->absbit); set_bit(ABS_HAT1X, wdata->extension.input->absbit); input_set_abs_params(wdata->extension.input, ABS_X, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_Y, -32, 31, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT0X, 0, 0x1f, 1, 1); input_set_abs_params(wdata->extension.input, ABS_HAT1X, 0, 0x0f, 1, 1); ret = input_register_device(wdata->extension.input); if (ret) goto err_free; return 0; err_free: input_free_device(wdata->extension.input); wdata->extension.input = NULL; return ret; } static void wiimod_guitar_remove(const struct wiimod_ops *ops, struct wiimote_data *wdata) { if (!wdata->extension.input) return; input_unregister_device(wdata->extension.input); wdata->extension.input = NULL; } static const struct wiimod_ops wiimod_guitar = { .flags = 0, .arg = 0, .probe = wiimod_guitar_probe, .remove = wiimod_guitar_remove, .in_ext = wiimod_guitar_in_ext, }; /* * Builtin Motion Plus * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which Loading Loading @@ -2201,4 +2639,6 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic, [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro, [WIIMOTE_EXT_DRUMS] = &wiimod_drums, [WIIMOTE_EXT_GUITAR] = &wiimod_guitar, };
drivers/hid/hid-wiimote.h +3 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ enum wiimote_exttype { WIIMOTE_EXT_CLASSIC_CONTROLLER, WIIMOTE_EXT_BALANCE_BOARD, WIIMOTE_EXT_PRO_CONTROLLER, WIIMOTE_EXT_DRUMS, WIIMOTE_EXT_GUITAR, WIIMOTE_EXT_NUM, }; Loading Loading @@ -137,6 +139,7 @@ struct wiimote_state { /* calibration/cache data */ __u16 calib_bboard[4][3]; __s16 calib_pro_sticks[4]; __u8 pressure_drums[7]; __u8 cache_rumble; }; Loading