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

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

 



Hi

On Thu, Mar 8, 2018 at 1:09 AM, Matt Votava <matt@xxxxxxxxxx> wrote:
> 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;

I would skip rmem[2] and rmem[3]. I think they simply encode the
extension address. This should be enough:

+       if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
+           rmem[4] == 0x01 && rmem[5] == 0x03)
        ...

>         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;

I think using 0x07 here is easier. That is, use the CLASSIC_CONTROLLER
pass-through, rather than the nunchuk one. But see below..

>                 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",

Is that the official name? I always used "Nintendo Wii Guitar Hero
Guitar" to follow the style of the other ones. However, I never owned
such a device, so no clue what they report as name. I am also unsure
whether Nintendo actually produced them, or whether they're just
licensed.

>  };
>
>  /*
> @@ -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 */

This mapping looks ok to me.

> +};
> +
> +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

You lack MP+ handling here. If you use the passthrough, some bits are
moved. I am not entirely sure whether there are actually devices with
MP and guitars, but I'd prefer being on the safe side. Have a look at
commit 8e22ecb603c8 in the official kernel tree. This contains details
on how to handle the mapping (which used the 0x07 pass-through as
described above). Note that this commit got reverted some years ago.

> +        */
> +
> +       bx = ext[0];
> +       by = ext[1];
> +       bx -= 224;
> +       by -= 224;

Err, this looks bogus. The upper bits of bx and by are not necessarily
1. They might be 0 for some devices (I think the "World Tour" ones).
Hence, I think you need to clear the 6th and 7th bit and then use '32'
as center-point, rather than 224.

If you can, have a look at the old guitar-support (as I mentioned:
8e22ecb603c8). I would like to have the MP+ handling in there.

Otherwise, this looks really good! Thanks a lot for picking it up!
Please remember to keep Jiri in CC, otherwise he will not pick up HID
patches.

Thanks
David

> +
> +       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