Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preliminary support for Nintendo Switch Online controllers #35

Closed
wants to merge 6 commits into from
Closed

Preliminary support for Nintendo Switch Online controllers #35

wants to merge 6 commits into from

Conversation

emilyst
Copy link

@emilyst emilyst commented Mar 28, 2022

These changes should be considered a preliminary draft until they are acknowledged, approved, and merged.

Quoting from the second commit:

This change adds preliminary support to the hid-nintendo driver for the SNES, NES, and Sega Genesis controllers sold for Nintendo Switch Online:

In creating this commit, I made reference to earlier work by @nadiaholmquist, manually patching in these changes:

In addition, I implemented preliminary Sega Genesis controller support.

Known issues:

  • The Sega Genesis controller appears to work great over USB but not over Bluetooth. Instead, over Bluetooth, the controller reports its product ID as 0x2017 (the same as the SNES controller) instead of 0x201e (the unique product ID for the Genesis controller). It is unclear to me if this is a bug in the hardware or in my implementation.
  • I tried to use names for the devices which are consistent with Nintendo USA's website (slightly shortened). Unsure if this is confusing.
  • I made some minor formatting changes. Unclear if I have violated any kernel code style rules.
  • I don't have the N64 controller, and so I cannot implement it at this time.

This commit should be considered a preliminary draft for supporting these controllers. That said, this works well for me here (other than the Genesis Bluetooth issue noted above), and I have already begun using these changes locally.

Thanks again to @nadiaholmquist for her work on those previous NES/SNES changes.

I will comment inline where I believe input is still warranted.

emilyst added 2 commits March 28, 2022 15:04
This change adds product IDs for the following Nintendo Switch Online controllers:

* https://www.nintendo.com/store/products/sega-genesis-control-pad/
* https://www.nintendo.com/store/products/super-nintendo-entertainment-system-controller/

This allows the controllers to be detected by the `hid-nintendo` driver module.
This change adds preliminary support to the `hid-nintendo` driver for the SNES, NES, and Sega Genesis controllers sold for Nintendo Switch Online:

* https://www.nintendo.com/store/products/nintendo-entertainment-system-controllers/
* https://www.nintendo.com/store/products/super-nintendo-entertainment-system-controller/
* https://www.nintendo.com/store/products/sega-genesis-control-pad/

In creating this commit, I made reference to earlier work by @nadiaholmquist, manually patching in these changes:

* nadiaholmquist/linux@21a824e
* nadiaholmquist/linux@bdf4626

In addition, I implemented preliminary Sega Genesis controller support.

Known issues:

* The Sega Genesis controller appears to work great over USB but not over Bluetooth. Instead, over Bluetooth, the controller reports its product ID as `0x2017` (the same as the SNES controller) instead of `0x201e` (the unique product ID for the Genesis controller). It is unclear to me if this is a bug in the hardware or in my implementation.
* I tried to use names for the devices which are consistent with Nintendo USA's website (slightly shortened). Unsure if this is confusing.
* I made some minor formatting changes. Unclear if I have violated any kernel code style rules.
* I don't have the N64 controller, and so I cannot implement it at this time.

This commit should be considered a preliminary draft for supporting these controllers. That said, this works well for me here (other than the Genesis Bluetooth issue noted above), and I have already begun using these changes locally.

Thanks again to @nadiaholmquist for her work on those previous NES/SNES changes.
drivers/hid/hid-nintendo.c Outdated Show resolved Hide resolved
drivers/hid/hid-nintendo.c Outdated Show resolved Hide resolved
Comment on lines +1380 to +1382
if (jc_type_is_nescon(ctlr) || \
jc_type_is_snescon(ctlr) || \
jc_type_is_gencon(ctlr)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am undecided on if I should define a helper macro to the effect of jc_type_is_nso to include all the NSO controllers at once. That said, they share a few characteristics that would make such a helper macro reasonable (lack of motion and rumble, for example).

Happy to get input on this.

drivers/hid/hid-nintendo.c Outdated Show resolved Hide resolved
drivers/hid/hid-nintendo.c Outdated Show resolved Hide resolved
Comment on lines 1785 to 1800
if (jc_type_is_nescon(ctlr)) {
/* set up dpad hat */
input_set_abs_params(ctlr->input, ABS_HAT0X, -1, 1, 0, 0);
input_set_abs_params(ctlr->input, ABS_HAT0Y, -1, 1, 0, 0);

/* set up buttons */
for (i = 0; nescon_button_inputs[i] > 0; i++)
input_set_capability(ctlr->input, EV_KEY, nescon_button_inputs[i]);

/* register the device here, we don't need any more setup */
ret = input_register_device(ctlr->input);
if (ret)
return ret;

return 0;
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional block, along with the following two, are highly duplicative. I split out these conditions from the changes I adapted. It seemed to me that the existing abstraction was starting to strain.

However, I may try to fold these again into one conditional in a future commit. For now, this works.

drivers/hid/hid-nintendo.c Outdated Show resolved Hide resolved
Comment on lines 2294 to 2469
USB_DEVICE_ID_NINTENDO_PROCON) },
USB_DEVICE_ID_NINTENDO_PROCON) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_PROCON) },
USB_DEVICE_ID_NINTENDO_PROCON) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_CHRGGRIP) },
USB_DEVICE_ID_NINTENDO_CHRGGRIP) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_JOYCONL) },
USB_DEVICE_ID_NINTENDO_JOYCONL) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_JOYCONR) },
USB_DEVICE_ID_NINTENDO_JOYCONR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_SNESCON) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_SNESCON) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_GENCON) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_GENCON) },
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed some alignment here for consistency's sake. Unclear if this is okay.

emilyst added 2 commits March 28, 2022 17:06
I revisited my the keys reported as inputs for the Sega Genesis controller and properly assigned those. This also makes Bluetooth work a bit better: the controller is still misrecognized, but the inputs match the SNES controller much more closely, so it's less noticeable.
Turns out this value isn't used for Bluetooth (or really anything right now), but for completeness' sake, I'm defining it here, with a value based on my debugging.
@emilyst
Copy link
Author

emilyst commented Mar 29, 2022

I suspect that the "controller type" field has taken on more important responsibilities since the time when it was reverse-engineered here a few years ago.

The values, as they exist in this pull request, are correct, based on my testing. Meanwhile, the product and vendor IDs seem to be misleading. It's puzzling that the Genesis controller is able to send different product IDs based on whether it's using USB or Bluetooth. I still don't know whether this is the fault of my specific device or just a design "decision."

In any case, before this set of changes is done (whether this is completed in this pull request or somewhere else), it's possible that it would be a good idea to rework the joycon_ctlr_type enumeration and its role in the HID probe.

Below, I'm pasting a few chunks of logs from the kernel which include some debugging information I added. Pay attention to the ctlr->hdev->product and the ctlr->ctlr_type values.

Attaching the NSO SNES controller via USB:

Mar 29 03:01:59.630586 aldebaran kernel: usb 3-1: new full-speed USB device number 5 using xhci_hcd
Mar 29 03:01:59.773869 aldebaran kernel: usb 3-1: New USB device found, idVendor=057e, idProduct=2017, bcdDevice= 2.10
Mar 29 03:01:59.774146 aldebaran kernel: usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Mar 29 03:01:59.774329 aldebaran kernel: usb 3-1: Product: SNES Controller
Mar 29 03:01:59.774447 aldebaran kernel: usb 3-1: Manufacturer: Nintendo Co., Ltd.
Mar 29 03:01:59.774555 aldebaran kernel: usb 3-1: SerialNumber: 000000000001
Mar 29 03:01:59.774660 aldebaran kernel: nintendo 0003:057E:2017.0005: hidraw0: USB HID v81.11 Joystick [Nintendo Co., Ltd. SNES Controller] on usb-0000:00:14.0-1/input0
Mar 29 03:02:00.640538 aldebaran kernel: nintendo 0003:057E:2017.0005: controller MAC = 48:A5:E7:08:36:37
Mar 29 03:02:00.640973 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->bus: 0x03
Mar 29 03:02:00.641162 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->group: 0x01
Mar 29 03:02:00.641320 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->vendor: 0x57E
Mar 29 03:02:00.641477 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->product: 0x2017
Mar 29 03:02:00.641641 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->version: 0x8111
Mar 29 03:02:00.641791 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->type: 0x02
Mar 29 03:02:00.641942 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->name: "Nintendo Co., Ltd. SNES Controller"
Mar 29 03:02:00.642091 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->phys: "usb-0000:00:14.0-1/input0"
Mar 29 03:02:00.642240 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->hdev->uniq: "000000000001"
Mar 29 03:02:00.642392 aldebaran kernel: nintendo 0003:057E:2017.0005: ctlr->ctlr_type: 0x0B
Mar 29 03:02:00.667243 aldebaran kernel: input: Super Nintendo Controller for Nintendo Switch Online as /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:057E:2017.0005/input/input23

Attaching the NSO SNES controller via Bluetooth:

Mar 29 03:02:11.887711 aldebaran kernel: nintendo 0005:057E:2017.0006: hidraw0: BLUETOOTH HID v80.01 Gamepad [SNES Controller] on 70:9c:d1:21:17:bc
Mar 29 03:02:13.970496 aldebaran kernel: nintendo 0005:057E:2017.0006: controller MAC = 48:A5:E7:08:36:37
Mar 29 03:02:13.970900 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->bus: 0x05
Mar 29 03:02:13.971069 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->group: 0x01
Mar 29 03:02:13.971217 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->vendor: 0x57E
Mar 29 03:02:13.971406 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->product: 0x2017
Mar 29 03:02:13.971547 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->version: 0x8001
Mar 29 03:02:13.971683 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->type: 0x00
Mar 29 03:02:13.971831 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->name: "SNES Controller"
Mar 29 03:02:13.971972 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->phys: "70:9c:d1:21:17:bc"
Mar 29 03:02:13.972109 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->hdev->uniq: "48:a5:e7:08:36:37"
Mar 29 03:02:13.972251 aldebaran kernel: nintendo 0005:057E:2017.0006: ctlr->ctlr_type: 0x0B
Mar 29 03:02:14.003872 aldebaran kernel: input: Super Nintendo Controller for Nintendo Switch Online as /devices/virtual/misc/uhid/0005:057E:2017.0006/input/input24

Attaching the NSO Genesis controller via USB:

Mar 29 03:02:40.730445 aldebaran kernel: usb 3-1: new full-speed USB device number 6 using xhci_hcd
Mar 29 03:02:40.870434 aldebaran kernel: usb 3-1: New USB device found, idVendor=057e, idProduct=201e, bcdDevice= 2.12
Mar 29 03:02:40.870859 aldebaran kernel: usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Mar 29 03:02:40.871030 aldebaran kernel: usb 3-1: Product: MD/Gen Control Pad
Mar 29 03:02:40.871178 aldebaran kernel: usb 3-1: Manufacturer: Nintendo Co., Ltd.
Mar 29 03:02:40.871308 aldebaran kernel: usb 3-1: SerialNumber: 000000000001
Mar 29 03:02:40.877226 aldebaran kernel: nintendo 0003:057E:201E.0007: hidraw1: USB HID v81.11 Joystick [Nintendo Co., Ltd. MD/Gen Control Pad] on usb-0000:00:14.0-1/input0
Mar 29 03:02:41.723913 aldebaran kernel: nintendo 0003:057E:201E.0007: controller MAC = 80:D2:E5:BE:64:D2
Mar 29 03:02:41.724335 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->bus: 0x03
Mar 29 03:02:41.724502 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->group: 0x01
Mar 29 03:02:41.724644 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->vendor: 0x57E
Mar 29 03:02:41.724786 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->product: 0x201E
Mar 29 03:02:41.724929 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->version: 0x8111
Mar 29 03:02:41.725065 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->type: 0x02
Mar 29 03:02:41.725207 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->name: "Nintendo Co., Ltd. MD/Gen Control Pad"
Mar 29 03:02:41.725347 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->phys: "usb-0000:00:14.0-1/input0"
Mar 29 03:02:41.725495 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->hdev->uniq: "000000000001"
Mar 29 03:02:41.725635 aldebaran kernel: nintendo 0003:057E:201E.0007: ctlr->ctlr_type: 0x0D
Mar 29 03:02:41.747184 aldebaran kernel: input: SEGA Genesis Control Pad for Nintendo Switch Online as /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:057E:201E.0007/input/input25

Attaching the NSO Genesis controller via Bluetooth:

Mar 29 03:03:00.590774 aldebaran kernel: nintendo 0005:057E:2017.0008: hidraw1: BLUETOOTH HID v80.01 Gamepad [MD/Gen Control Pad] on 70:9c:d1:21:17:bc
Mar 29 03:03:02.647194 aldebaran kernel: nintendo 0005:057E:2017.0008: controller MAC = 80:D2:E5:BE:64:D2
Mar 29 03:03:02.647572 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->bus: 0x05
Mar 29 03:03:02.647743 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->group: 0x01
Mar 29 03:03:02.647887 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->vendor: 0x57E
Mar 29 03:03:02.648031 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->product: 0x2017
Mar 29 03:03:02.648170 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->version: 0x8001
Mar 29 03:03:02.648309 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->type: 0x00
Mar 29 03:03:02.648450 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->name: "MD/Gen Control Pad"
Mar 29 03:03:02.648587 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->phys: "70:9c:d1:21:17:bc"
Mar 29 03:03:02.648729 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->hdev->uniq: "80:d2:e5:be:64:d2"
Mar 29 03:03:02.648868 aldebaran kernel: nintendo 0005:057E:2017.0008: ctlr->ctlr_type: 0x0D
Mar 29 03:03:02.703771 aldebaran kernel: input: Super Nintendo Controller for Nintendo Switch Online as /devices/virtual/misc/uhid/0005:057E:2017.0008/input/input26

emilyst added 2 commits March 28, 2022 23:02
The Genesis controller doesn't even have triggers, so this is redundant.
I accidentally added some extra whitespace while merging changes. This change removes it.
@emilyst
Copy link
Author

emilyst commented Mar 29, 2022

I don't know how long it's going to be before I can get in contact with Daniel, so this might sit for a little while in the meantime. Before I leave it for a while, I wanted to jot out tentative ideas for future improvements I might like to incorporate into my set of changes.

  • Differentiate controller types by the ctlr->ctlr_type field reported by the device itself, where possible, instead of the product ID.

    As I alluded to above, the ctlr->ctlr_type field seems to be a better way to differentiate devices than the product ID. It's already necessary to differentiate Joy-Con sides (and NES Joy-Con sides as well). It also appears to be necessary for the Genesis controller over Bluetooth. I would want to confirm the values on my devices match the expectations of the driver as written. I would also want to fall back to using the product ID if the ctlr->ctlr_type value is unexpectedly different.

  • Create a few new helper macros to simplify some of the conditionals.

    The NSO devices particularly seem to have common characteristics, like lacking IMU and rumble. They also map their inputs similarly.

    A few other helpers could possibly be split out, combined, or otherwise simplified.

  • Possibly change the namespacing of functions/types from jc_ to something more general.

    If my changes were merged in, my feeling is that it would take the driver further along the journey it's been on from just accepting Joy-Con devices. At this point it would seem to be supporting most Nintendo Switch controllers. It would make sense, in my mind, to generalize references to Joy-Cons so that it's less confusing for future readers. My belief is that these are module-internal details which are safe to change.

    I'm not certain what I would choose. Possibly:

    • nintendo_ (matching the name of the driver)

    • switch_ (matching the name of the console)

    • ns_ or nx_ (for "Nintendo Switch")

    • sc_, nsc_, or nxc_ (for "(Nintendo) Switch Controller")

    • ns_ctlr, nx_ctlr, or switch_ctlr (again, for "(Nintendo) Switch Controller")

    I think I'm personally partial to nx_ctlr, but this is really subjective decision and not even entirely necessary.

  • Possibly map the Capture and Home buttons to something, so they can be mapped to functions inside of games.

    Candidates in my mind are the unused numerical buttons, like BTN_0 and BTN_1.

  • Maybe some other reformatting and refactoring here and there.

    For example, adding comments to the controllers' inputs arrays (e.g., joycon_button_inputs_l) to show how they map to the constants defined for the Joy-Cons' inputs. Similar to what I've proposed already in my changes, but using the constant names. With other helper macros, I could reorganize some of the duplication I've added here as well.

That's all I have for now, but if I think of something else, I'll add it to this list.

emilyst added a commit to emilyst/hid-nx-dkms that referenced this pull request Apr 1, 2022
This commit adds support to the `hid-nintendo` driver for the Nintendo
Switch Online controllers for the NES, SNES, and Genesis. These changes
were first implemented in:

* DanielOgorchock/linux#35

The changes have been adapted here for the latest version of the
`hid-nintendo` driver as of Linux kernel version 5.16.0 (see previous
commit).

For more about the controllers, see:

* https://www.nintendo.com/store/products/nintendo-entertainment-system-controllers/
* https://www.nintendo.com/store/products/super-nintendo-entertainment-system-controller/
* https://www.nintendo.com/store/products/sega-genesis-control-pad/

Much of these changes make reference to work by Nadia Holmquist
Pedersen, adapted from these commits and ported forward to the latest
version of the `hid-nintendo` driver:

* nadiaholmquist/linux@21a824e
* nadiaholmquist/linux@bdf4626

In addition, I implemented Sega Genesis controller support. At this
point, Bluetooth support for this controller is preliminary and
incomplete.

I have relicensed these changes under the GPL-2.0 in this repository,
using the same licenses as the original.

Signed-off-by: Emily Strickland <linux@emily.st>
@emilyst
Copy link
Author

emilyst commented Apr 1, 2022

Since I've gotten no response, I'm going to close this pull request for now. Feel free to reopen it if you'd like to continue the conversation about it here.

I've decided to release these changes (ported to the latest version of the driver in the kernel tree) as a DKMS module located here: https://github.com/emilyst/hid-nintendo/. If anybody wants to use these changes, please see there.

@emilyst emilyst closed this Apr 1, 2022
@emilyst emilyst deleted the nso-controller-support branch April 2, 2022 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant