From patchwork Wed Jun 20 10:55:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Herrmann X-Patchwork-Id: 10476911 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 85A6A60230 for ; Wed, 20 Jun 2018 10:55:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7371A28E0C for ; Wed, 20 Jun 2018 10:55:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6272528E1D; Wed, 20 Jun 2018 10:55:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 42A6828E0C for ; Wed, 20 Jun 2018 10:55:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752829AbeFTKz1 (ORCPT ); Wed, 20 Jun 2018 06:55:27 -0400 Received: from mail-wr0-f196.google.com ([209.85.128.196]:46938 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751422AbeFTKz0 (ORCPT ); Wed, 20 Jun 2018 06:55:26 -0400 Received: by mail-wr0-f196.google.com with SMTP id v13-v6so2781977wrp.13 for ; Wed, 20 Jun 2018 03:55:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=+oAo50XMnhnUbE4JykCDzH5RHm4xGyFex1xbzIXFu/k=; b=mPFz/JIWmSbRzygAIfE0R3OKKQJtyGchBKNNdiFCRRfhXniMuHjHcKLpEI7GGEY++u qtQuPJrqcznqKgZl9xD20z/nFpBj4H8Pyku8+8p7Bw2yXXirfrG4zuehJJibID1fHNEA C1GpVxcTVPr3+35N3GI1zx5yXE3IQakHFDH2ImiO1UJmWsAaZuDZjO/QmkNGor82GQJ0 keds9PoJK5OD2P0O6quXxvVWxqNhPpTQeIqriMcc17zz2OOrfRwhung7voouW4KppCr0 83ouY7VQ6iOSEPtQuuhDJv/ymFcbrDcLhqfXULcuREdlD4FxRwcAxXScuFoBVaHNPPAK 7WPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=+oAo50XMnhnUbE4JykCDzH5RHm4xGyFex1xbzIXFu/k=; b=DrOLHXB2iU+fkiHgyi12ubQlyoZm+CLohFVm1C6oYUNBwFFvT2DMtlgCwa7n1f4FXj rSGmHEC8Ua5R5R96n56dCnWYJ1N4qEz6X4vy+zDQzLV0+O1n6Lu/bhK2YsB9KFL32759 RQsa6EPSzVWtx76ZAySO7UKNBM0ZAdUoomhjixBqTchlY8t+JfViskkTFhyjkkG3F7UQ IbBxgqBeVPjDX8vv1qiH3/isCvp2xtsJoZYoYqjcyaFwOtjuEIqqziSoIUA6mNDrg725 +K6CeZDK4MYaunSc1QPew6FKXnm1wq7NSAl7hd6DpnxVfgtNgDbNal2LZCWT6ODjfgyf OoHA== X-Gm-Message-State: APt69E38ZCFZ3Qqx0/fpM6Rypfl0covin5U/wZIzuhNxAbzEOCHXt7nI D7QaTuE2fae2PBBxbPfHNC2S9Q== X-Google-Smtp-Source: ADUXVKKyF39v3RbI1FAEibxUDXY2AQ0yqpM07NIBDyr2zPsqsl4uBSHV7Q4kFUvfPJrnQqLpi6+7fQ== X-Received: by 2002:adf:85ec:: with SMTP id 41-v6mr17396931wru.120.1529492124473; Wed, 20 Jun 2018 03:55:24 -0700 (PDT) Received: from david-x1.fritz.box (p200300C2A3C983002BAD6C38F23FB834.dip0.t-ipconnect.de. [2003:c2:a3c9:8300:2bad:6c38:f23f:b834]) by smtp.gmail.com with ESMTPSA id i1-v6sm76715wro.87.2018.06.20.03.55.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 20 Jun 2018 03:55:23 -0700 (PDT) From: David Herrmann To: linux-input@vger.kernel.org Cc: jikos@kernel.org, Benjamin Tissoires , Nicolas Adenis-Lamarre , David Herrmann Subject: [PATCH] HID: wiimote: add support for Guitar-Hero devices Date: Wed, 20 Jun 2018 12:55:15 +0200 Message-Id: <20180620105515.29836-1-dh.herrmann@gmail.com> X-Mailer: git-send-email 2.17.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Nicolas Adenis-Lamarre This adds the drums and guitar extensions for Wiimote devices. Devices are reported as "Nintendo Wii Remote Guitar/Drums". If I ever get my hands on "RockBand" guitars, I will try to report them via the same interface so user-space does not have to bother which device it deals with. This is a rebase of the original commits 8e22ecb603c8 and 73f8645db191. They were reverted several years ago, since they were dependent on the ABS_* rework of the input core. Sadly, this never worked out so these commits were never pushed into a release. This rebase now uses the ABS_HAT* event codes to report all pressure information. Signed-off-by: Nicolas.Adenis-Lamarre (Original commits by Nicolas, adapted to v4.18 by David) Signed-off-by: David Herrmann --- drivers/hid/hid-wiimote-core.c | 14 + drivers/hid/hid-wiimote-modules.c | 440 ++++++++++++++++++++++++++++++ drivers/hid/hid-wiimote.h | 3 + 3 files changed, 457 insertions(+) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 579884ebd94d..7780da4fe897 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -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; } @@ -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: @@ -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", }; /* @@ -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: diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c index c830ed39348f..aa72eb9a8e2f 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c @@ -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 @@ -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, }; diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 510ca77fe14e..3bf3d3cc1c38 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h @@ -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, }; @@ -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; };