[PATCH] HID: Add guitar controller extension support to hid-wiimote

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <matt@xxxxxxxxxx>
---
 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,
 };
 
-- 
2.16.2


--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux