emilyst / hid-nx-dkms

Alternative Linux kernel HID driver for Nintendo Switch controllers
GNU General Public License v2.0
40 stars 6 forks source link

Retroarch misconfiguration (tested with N64 Controller) #16

Open mcpat-it opened 11 months ago

mcpat-it commented 11 months ago

Hi @emilyst I am using a rpi zero 2w (~rpi3) with latest raspian lite. Compiled retropi 4.8 which is working good.

I paired my controllers (N64 and MD), then in emulationstation I configured the N64 controller. It is working there, but in retroarch, it is not working. It seems the buttons must be +2 higher. I used this firstly and installed dkms-hid-nintendo and joycond. This was working, but not the MD controller, and the lights where rotating all the time at the N64 controller. So I switched to hid-nx-dkms. It seems others has this problem too.

Emulationstation has this es_input.cfg:

<?xml version="1.0"?>
<inputList>
  <inputAction type="onfinish">
    <command>/opt/retropie/supplementary/emulationstation/scripts/inputconfiguration.sh</command>
  </inputAction>
  <inputConfig type="joystick" deviceName="N64 Controller" deviceGUID="05001c5e7e0500001920000001800000">
    <input name="rightanalogdown" type="button" id="8" value="1"/>
    <input name="left" type="hat" id="0" value="8"/>
    <input name="rightanalogleft" type="button" id="9" value="1"/>
    <input name="right" type="hat" id="0" value="2"/>
    <input name="pagedown" type="button" id="4" value="1"/>
    <input name="down" type="hat" id="0" value="4"/>
    <input name="rightanalogup" type="button" id="7" value="1"/>
    <input name="pageup" type="button" id="3" value="1"/>
    <input name="rightanalogright" type="button" id="10" value="1"/>
    <input name="y" type="button" id="12" value="1"/>
    <input name="x" type="button" id="2" value="1"/>
    <input name="b" type="button" id="1" value="1"/>
    <input name="a" type="button" id="0" value="1"/>
    <input name="up" type="hat" id="0" value="1"/>
    <input name="select" type="button" id="5" value="1"/>
    <input name="start" type="button" id="6" value="1"/>
    <input name="leftanalogright" type="axis" id="0" value="1"/>
    <input name="leftanalogup" type="axis" id="1" value="-1"/>
    <input name="leftanalogdown" type="axis" id="1" value="1"/>
    <input name="leftanalogleft" type="axis" id="0" value="-1"/>
  </inputConfig>
  <inputConfig type="keyboard" deviceName="Keyboard" deviceGUID="-1">
    <input name="left" type="key" id="1073741904" value="1"/>
    <input name="right" type="key" id="1073741903" value="1"/>
    <input name="down" type="key" id="1073741905" value="1"/>
    <input name="y" type="key" id="118" value="1"/>
    <input name="x" type="key" id="99" value="1"/>
    <input name="b" type="key" id="120" value="1"/>
    <input name="a" type="key" id="122" value="1"/>
    <input name="up" type="key" id="1073741906" value="1"/>
    <input name="select" type="key" id="97" value="1"/>
    <input name="start" type="key" id="115" value="1"/>
  </inputConfig>
</inputList>

autoconfiguration of retroarch N64 controller N64 Controller.cfg:

input_device = "N64 Controller"
input_driver = "udev"
input_vendor_id = "1406"
input_product_id = "8217"
input_r_y_plus_btn = "8"
input_left_btn = "h0left"
input_left_btn_label = "D-Pad Left"
input_state_slot_decrease_btn = "h0left"
input_r_x_minus_btn = "9"
input_right_btn = "h0right"
input_right_btn_label = "D-Pad Right"
input_state_slot_increase_btn = "h0right"
input_r_btn = "4"
input_save_state_btn = "4"
input_down_btn = "h0down"
input_down_btn_label = "D-Pad Down"
input_r_y_minus_btn = "7"
input_l_btn = "3"
input_load_state_btn = "3"
input_r_x_plus_btn = "10"
input_y_btn = "12"
input_x_btn = "2"
input_menu_toggle_btn = "2"
input_b_btn = "1"
input_b_btn_label = "A"
input_reset_btn = "1"
input_a_btn = "0"
input_up_btn = "h0up"
input_up_btn_label = "D-Pad Up"
input_select_btn = "5"
input_start_btn = "6"
input_exit_emulator_btn = "6"
input_enable_hotkey_btn = "5"

and the working configuration is:

input_device = "N64 Controller"
input_driver = "udev"
input_vendor_id = "1406"
input_product_id = "8217"
input_r_y_plus_btn = "10"
input_left_btn = "h0left"
input_left_btn_label = "D-Pad Left"
input_state_slot_decrease_btn = "h0left"
input_r_x_minus_btn = "11"
input_right_btn = "h0right"
input_right_btn_label = "D-Pad Right"
input_state_slot_increase_btn = "h0right"
input_r_btn = "6"
input_save_state_btn = "4"
input_down_btn = "h0down"
input_down_btn_label = "D-Pad Down"
input_r_y_minus_btn = "9"
input_l_btn = "5"
input_load_state_btn = "3"
input_r_x_plus_btn = "12"
input_y_btn = "1"
input_x_btn = "4"
input_menu_toggle_btn = "2"
input_b_btn = "3"
input_b_btn_label = "A"
input_reset_btn = "1"
input_a_btn = "2"
input_up_btn = "h0up"
input_up_btn_label = "D-Pad Up"
input_select_btn = "7"
input_start_btn = "8"
input_exit_emulator_btn = "6"
input_enable_hotkey_btn = "7"

D-Pad was working, not working where the other buttons (if you compare, they are +2 higher as autoconfig).

Can you tell me the reason? Is something corrupted after changing from dkms-hid-nintendo to hid-nx? It seems acc. #10 there are "new" buttons BTN_0 and BTN_1 which explains the +2 higher. How to disable BTN_0 and BTN_1 if this is the reason?!

I think we could delete the two lines at hid-nx.c

        { BTN_0,        NX_CON_BTN_HOME,    },
    { BTN_1,        NX_CON_BTN_CAP,     },

Maybe also for the Megadrive controller the two lines at hid-nx.c

Thank you, Best regards Patrick

emilyst commented 11 months ago

Note that I haven't fully read your issue yet, and I won't have time until later, but skimming it, it looks like you're saying that my driver maps inputs to different buttons than Retroarch expects.

It's likely that Retroarch's automatic configuration for N64 is based on the inputs supplied by hid-generic (a driver that kicks in for HID devices that aren't otherwise "claimed" by a more specific driver). The hid-generic driver knows enough to see the N64 controller, give it a name, and map most of its buttons, but it does so in an order that is different than my driver's ordering. It makes sense that Retroarch would do this, given that most people are just using a mainline kernel.

In other words, switching to my driver means that the inputs may be slightly rearranged. (There's a note about this in the README, but I know it's not obvious because it uses blockquote formatting. I can definitely improve that.) I made this decision to accommodate the additional inputs I've configured. I didn't imagine so many people would end up using this driver, though. I figured the conflict would be minor.

I'm going to give this all some thought about what might be the best solution, and I'll come back and read this issue more thoroughly soon, too, to make sure I haven't misread it.

mcpat-it commented 11 months ago

Yes, different buttons than Retroarch can use! The layout is the same, but working only when I add +2 to the buttons.

Would it be possible to order in the same way like Retroarch expect it? I tried to delete the Buttons BTN_0 and BTN_1, but then I loose this two buttons, so I have to keep the lines.

I have a disussion in parallel in the retropie forum, maybe I can find there a clue.

BTW, I ordered a MD 6B controller, maybe we both make it useable. ;)

Regards Patrick

mcpat-it commented 11 months ago

I solved the problem. It was the mapping BTN_0 and BTN_1. If we change all this to buttons higher than the first "A" button, then it's working, here my two tests with MD/Gen and N64 controller

static const struct nx_con_button_mapping gencon_button_mappings[] = {
    { BTN_SOUTH,    NX_CON_BTN_A,       },
    { BTN_EAST, NX_CON_BTN_B,       },
    { BTN_WEST, NX_CON_BTN_R,       },
    { BTN_DPAD_LEFT,    NX_CON_BTN_X,       },
    { BTN_DPAD_UP,      NX_CON_BTN_Y,       },
    { BTN_DPAD_RIGHT,   NX_CON_BTN_L,       },
    { BTN_THUMBL,   NX_CON_BTN_ZR,      },
    { BTN_START,    NX_CON_BTN_PLUS,    },
    { BTN_SELECT,   NX_CON_BTN_HOME,    },
    { BTN_MODE, NX_CON_BTN_CAP,     },
    { /* sentinel */ },
};

/*
 * N64's C buttons get assigned to d-pad directions and registered as buttons.
 */
static const struct nx_con_button_mapping n64con_button_mappings[] = {
    { BTN_A,        NX_CON_BTN_A,       },
    { BTN_B,        NX_CON_BTN_B,       },
    { BTN_Z,        NX_CON_BTN_ZL,      },
    { BTN_TL,       NX_CON_BTN_L,       },
    { BTN_TR,       NX_CON_BTN_R,       },
    { BTN_TR2,      NX_CON_BTN_LSTICK,  },
    { BTN_START,        NX_CON_BTN_PLUS,    },
    { BTN_DPAD_UP,      NX_CON_BTN_Y,       },
    { BTN_DPAD_DOWN,    NX_CON_BTN_ZR,      },
    { BTN_DPAD_LEFT,    NX_CON_BTN_X,       },
    { BTN_DPAD_RIGHT,   NX_CON_BTN_MINUS,   },
    { BTN_THUMBL,       NX_CON_BTN_HOME,    },
    { BTN_MODE,     NX_CON_BTN_CAP,     },
    { /* sentinel */ },
};

I have both MD/Gen controller, the 3B and 6B. I can't see any difference, only had to implement the additional lines and both are working. The Problem, Retroarch cannot differ between both, because they have both the same name... How could we solve this?

nfp0 commented 10 months ago

@pwallner Does it have the same product id and device name as the 3B?

mcpat-it commented 10 months ago

@nfp0 See here, it seems so

emilyst commented 10 months ago

@pwallner Does it have the same product id and device name as the 3B?

Identifying the NSO Genesis controller is absolutely bananas. It reports its product ID differently based on whether it's plugged in via USB or used via Bluetooth.

On Bluetooth, it reports itself as the NSO SNES controller. On USB, it has its own product ID. One of the things I did when rewriting the driver was implement a way to identify the correct controller at runtime, because oof.

mcpat-it commented 10 months ago

@emilyst I will try tomorrow with usb. I saw it's reporting as snes controller via Bluetooth. Up to now I only connected via Bluetooth. But with the modification above I can use at least both with the same mapping. But retrospect cannot make any difference between them cause by the same name.

emilyst commented 10 months ago

With respect to RetroArch identifying NSO controllers:

Back when I looked into this before, I realized that RetroArch had made the choice to distinguish devices by the name they report and/or by the vendor/product ID. Unfortunately, Nintendo controllers cannot be reliably identified that way. They occasionally report different names and IDs based on how they're connected; they occasionally have conflicting product IDs; and/or they occasionally have conflicting names.

In order for me to distinguish them, I wrote code in the driver to use the reported type most of the time. This is a value that the device sends over USB or Bluetooth after connection. This information can be queried by RetroArch, but it does not do so. (It's reasonable for RetroArch to rely on vendor/product IDs to identify devices, but there are many cases where devices copy one another's IDs, such as when competitors release clones.)

Right now, the only real solution I can think of would be to report customized names for the devices, based on the driver's knowledge of the device types. This choice would break all autoconfiguration in RetroArch, so that would all need to be rewritten upstream (in RetroArch, RetroPie, etc.). Then we would need to hope it never changes in the future. (These devices still get occasional firmware updates.)

I'll have to think about it some more to see if something else comes to mind, but I doubt I will have time this weekend.

mcpat-it commented 10 months ago

I am not really sure how Retroarch and Retropie are working. Because without your kernel module the N64 controller was reportet as ProController, the Gen/MD controller was not working. With your module it became the right name and the functionality. So maybe it's enough to report the correct name for the 6B.

I just connected via usb, here the results

evtest:

No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      Nintendo Co., Ltd. MD/Gen Control Pad
/dev/input/event1:      Rotary Encoder Volume
Select the device event number [0-1]: 0
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x57e product 0x201e version 0x8111
Input device name: "Nintendo Co., Ltd. MD/Gen Control Pad"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 304 (BTN_SOUTH)
    Event code 305 (BTN_EAST)
    Event code 308 (BTN_WEST)
    Event code 314 (BTN_SELECT)
    Event code 315 (BTN_START)
    Event code 316 (BTN_MODE)
    Event code 317 (BTN_THUMBL)
    Event code 544 (BTN_DPAD_UP)
    Event code 546 (BTN_DPAD_LEFT)
    Event code 547 (BTN_DPAD_RIGHT)
  Event type 3 (EV_ABS)
    Event code 16 (ABS_HAT0X)
      Value      0
      Min       -1
      Max        1
    Event code 17 (ABS_HAT0Y)
      Value      0
      Min       -1
      Max        1
Properties:
Testing ... (interrupt to exit)

dmesg:

[  336.167019] usb 1-1: new full-speed USB device number 2 using dwc_otg
[  336.167497] Indeed it is in host mode hprt0 = 00021501
[  336.408308] usb 1-1: New USB device found, idVendor=057e, idProduct=201e, bcd         Device= 2.12
[  336.408335] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  336.408344] usb 1-1: Product: MD/Gen Control Pad
[  336.408352] usb 1-1: Manufacturer: Nintendo Co., Ltd.
[  336.408359] usb 1-1: SerialNumber: 000000000001
[  336.413262] input: Nintendo Co., Ltd. MD/Gen Control Pad as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1:1.0/0003:057E:201E.0001/input/input0
[  336.414377] hid-generic 0003:057E:201E.0001: input,hidraw0: USB HID v1.11 Joystick [Nintendo Co., Ltd. MD/Gen Control Pad] on usb-3f980000.usb-1/input0
[  336.581696] hid_nx: loading out-of-tree module taints kernel.
[  336.638753] nx 0003:057E:201E.0001: hidraw0: USB HID v81.11 Joystick [Nintendo Co., Ltd. MD/Gen Control Pad] on usb-3f980000.usb-1/input0
[  337.268690] nx 0003:057E:201E.0001: controller MAC = 80:D2:E5:BE:B6:8D
[  337.301572] input: Nintendo Co., Ltd. MD/Gen Control Pad as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1:1.0/0003:057E:201E.0001/input/input1

and jstest

root@rpizerosm:~jstest /dev/input/js0
Driver version is 2.1.0.
Joystick (Nintendo Co., Ltd. MD/Gen Control Pad) has 2 axes (Hat0X, Hat0Y)
and 10 buttons (BtnA, BtnB, BtnY, BtnSelect, BtnStart, BtnMode, BtnThumbL, (null), (null), (null)).
Testing ... (interrupt to exit)
Axes:  0:     0  1:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:of

Do you need more infos?

nfp0 commented 10 months ago

Right now, the only real solution I can think of would be to report customized names for the devices, based on the driver's knowledge of the device types. This choice would break all autoconfiguration in RetroArch, so that would all need to be rewritten upstream (in RetroArch, RetroPie, etc.). Then we would need to hope it never changes in the future. (These devices still get occasional firmware updates.)

@emilyst This sounds like a good solution to me. If you would do this change, I can take care of fixing the RetroArch autoconfigs. In fact, I believe it's possible to have the new autoconfigs together with the old autoconfigs there, differentiated by the controller names. This way, no breakage would occur to anyone. We would treat your new system as if it were a new set of controllers added to the autoconfig repository and leave the old autoconfigs there as legacy for people on older kernels/not using your driver.

There's also the possibility to limit breakage by applying your solution just to the MD/Gen joypad and leaving the other ones as they are. But this might not be necessary for the above reasons.

Am I making sense?

EDIT: I think I've never seen a Nintendo firmware update change button mappings, so I think that's safe.

mcpat-it commented 10 months ago

I am not asked, but I agree, only MD controllers are affected. And would it be possible to check 3 or 6B? Then it would be possible to see the difference if everything else is same reported (what I think happens now, can't see any difference between 3 and 6)

nfp0 commented 10 months ago

In order for me to distinguish them, I wrote code in the driver to use the reported type most of the time. This is a value that the device sends over USB or Bluetooth after connection.

@emilyst Is this the reason why my MD 3btn controller gets detected as a SNES controller on RetroArch? I noticed this just now. I also noticed the Home and Screenshot buttons are not detected at all.

nfp0 commented 7 months ago

Please disregard my previous post. I only now realized I had the hid-nintendo-nso-dkms driver installed and not this one.