From patchwork Thu Mar 8 00:09:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Votava X-Patchwork-Id: 10267175 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 B92956016D for ; Thu, 8 Mar 2018 08:09:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A8F63297FB for ; Thu, 8 Mar 2018 08:09:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9D63C297FE; Thu, 8 Mar 2018 08:09:25 +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=-5.5 required=2.0 tests=BAYES_00, DATE_IN_PAST_06_12, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI 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 B7A0B297FB for ; Thu, 8 Mar 2018 08:09:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935348AbeCHIJX (ORCPT ); Thu, 8 Mar 2018 03:09:23 -0500 Received: from sender-of-o52.zoho.com ([135.84.80.217]:21394 "EHLO sender-of-o52.zoho.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935333AbeCHIJW (ORCPT ); Thu, 8 Mar 2018 03:09:22 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1520496558; s=zoho; d=votava.net; i=matt@votava.net; h=Date:From:To:Subject:Message-ID:MIME-Version:Content-Type; l=9260; bh=fYxkSF4kTaCFI/pMBzc2eJ0PNPTBan8FDJ/lQni9X/k=; b=RmzCN/bdsxTQhDLjtqHQKNj8uVRJrqehQsmHD5wHpzt1Z/lv3A4aF82Y4D95ZtUe dAtJlYjDCp7Cab/1mu1NRcPsS55d288r0CROuodmUErFlKQsgpuuZVky1eJEN7nkYB8 sxWUURVd/ByU3Huqi/XfMZXj+nafbH6VnBB/eGJ0= DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=zoho; d=votava.net; h=date:from:to:subject:message-id:mime-version:content-type:user-agent; b=P7MBwLioDzG1CsIPKacZiqrfda/1B2Vdkrw/xyZOeQguLS+okOdisSrd9+bIjiRphMIfKMpt/qD7 /7AGqsGXPBq4xWcM4ws148dV6CcPl4y00k9Lw2pyA5dRG6O6OVupv7UaohldXE9NsT7HR6Xn496+ +BtLqMNsF1oSSfXFC8o= Received: from localhost (50.35.12.21 [50.35.12.21]) by mx.zohomail.com with SMTPS id 1520496558687395.25186441027347; Thu, 8 Mar 2018 00:09:18 -0800 (PST) Date: Wed, 7 Mar 2018 16:09:27 -0800 From: Matt Votava To: dh.herrmann@googlemail.com, linux-input@vger.kernel.org Subject: [PATCH] HID: Add guitar controller extension support to hid-wiimote Message-ID: <20180308000927.GA2977@zen.votava> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.4 (2018-02-28) X-ZohoMailClient: External X-ZohoMail: Z_38084385 SPT_1 Z_38087406 SPT_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 Some wii games come with a guitar controller extension that plugs into the wii remote controller. This patch adds support for the les paul style guitar that comes with Guitar Hero 3 to hid-wiimote. Signed-off-by: Matt Votava --- drivers/hid/hid-wiimote-core.c | 7 ++ drivers/hid/hid-wiimote-modules.c | 200 ++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-wiimote.h | 1 + 3 files changed, 208 insertions(+) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 579884ebd94d..8b18d104934f 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -449,6 +449,9 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem) if (rmem[4] == 0x00 && rmem[5] == 0x00) return WIIMOTE_EXT_NUNCHUK; + if (rmem[0] == 0x00 && rmem[1] == 0x00 && rmem[2] == 0xa4 && + rmem[3] == 0x20 && rmem[4] == 0x01 && rmem[5] == 0x03) + return WIIMOTE_EXT_GUITAR; if (rmem[4] == 0x01 && rmem[5] == 0x01) return WIIMOTE_EXT_CLASSIC_CONTROLLER; if (rmem[4] == 0x04 && rmem[5] == 0x02) @@ -491,6 +494,7 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype) wmem = 0x07; break; case WIIMOTE_EXT_NUNCHUK: + case WIIMOTE_EXT_GUITAR: wmem = 0x05; break; default: @@ -1075,6 +1079,7 @@ 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_GUITAR] = "Guitar Hero 3 Les Paul Controller", }; /* @@ -1660,6 +1665,8 @@ 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_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..129f67ef7bd9 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c @@ -2176,6 +2176,205 @@ const struct wiimod_ops wiimod_mp = { .in_mp = wiimod_mp_in_mp, }; +/* + * Guitar Hero 3 Gibson Les Paul Controller + * The Les Paul Guitar Controller is used by Guitar Hero 3 and is + * compatible with later Guitar Hero Wii games and Rockband games + * as well. The controller has 5 fret keys, strum up and down, an + * analog whammy bar, analog stick, and plus and minus keys. + */ + +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) +{ + __s16 bx, by, bt, bw; + + /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * -----+----+----+----+----+----+----+----+----+ + * 0 | | Button X | + * 1 | | Button Y | + * -----+---------+----+------------------------+ + * 2 | | Button TB | + * 3 | | Button WB | + * -----+----+----+----+----+----+----+---------+ + * 4 | | BD | | B- | | B+ | | + * -----+----+----+----+----+----+----+----+----+ + * 5 | BO | BR | BB | BG | BY | | BU | + * -----+----+----+----+----+----+---------+----+ + * Button X/Y is the analog stick. Button TB, WB is the touch bar + * on the neck of guitars supporting this feature, and the whammy bar. + * + * BD and BU are strum button down and strum button up. + * B- and B+ are the minus and plus button at the base of the neck. + * + * BG, BR, BY, BB, BO are buttons green, red, yellow, blue, and orange. + * All buttons are low active + */ + + bx = ext[0]; + by = ext[1]; + bx -= 224; + by -= 224; + + bt = ext[2]; + bw = ext[3]; + bw &= 0x1f; + + bw -= 15; + + input_report_abs(wdata->extension.input, ABS_X, bx); + input_report_abs(wdata->extension.input, ABS_Y, by); + + input_report_abs(wdata->extension.input, ABS_HAT0X, bt); + input_report_abs(wdata->extension.input, ABS_HAT1X, bw); + + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], + !(ext[5] & 0x10)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], + !(ext[5] & 0x40)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], + !(ext[5] & 0x08)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], + !(ext[5] & 0x20)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], + !(ext[5] & 0x80)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], + !(ext[5] & 0x01)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], + !(ext[4] & 0x40)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], + !(ext[4] & 0x04)); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], + !(ext[4] & 0x10)); + + 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, -30, 30, 2, 4); + input_set_abs_params(wdata->extension.input, + ABS_Y, -30, 30, 2, 4); + input_set_abs_params(wdata->extension.input, + ABS_HAT0X, -120, 120, 2, 4); + input_set_abs_params(wdata->extension.input, + ABS_HAT1X, 0, 12, 2, 4); + + 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, +}; + /* module table */ static const struct wiimod_ops wiimod_dummy; @@ -2201,4 +2400,5 @@ 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_GUITAR] = &wiimod_guitar, }; diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 510ca77fe14e..c55c034281f0 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h @@ -89,6 +89,7 @@ enum wiimote_exttype { WIIMOTE_EXT_CLASSIC_CONTROLLER, WIIMOTE_EXT_BALANCE_BOARD, WIIMOTE_EXT_PRO_CONTROLLER, + WIIMOTE_EXT_GUITAR, WIIMOTE_EXT_NUM, };