Bug 250724

Summary: USB gamepads are tagged as a mouse by udev
Product: Base System Reporter: Patrick McMunn <doctorwhoguy>
Component: usbAssignee: freebsd-usb (Nobody) <usb>
Status: New ---    
Severity: Affects Only Me CC: hselasky, iwtcex, swills, waitman, wulf
Priority: ---    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Patrick McMunn 2020-10-29 15:27:39 UTC
I have tested several USB gamecontrollers with FreeBSD, and there is something apparently wrong with either evdev or udev because the USB game controllers are being detected as mice instead of joysticks. I have tried both webcamd and iichid to get them working with FreeBSD. For this example, I'll use my Logitech Dual Action Controller.

If I plug it in, dmesg will show the device detected and attach it as a uhid device:

uhid0 on uhub2
uhid0: <Logitech Logitech Dual Action, class 0/0, rev 1.10/3.00, addr 3> on usbus3

If I load the iichid kernel module and plug in the controller, dmesg will show the following output showing that it has been attached as an hid device:

ugen3.3: <Logitech Logitech Dual Action> at usbus3
usbhid0 on uhub2
usbhid0: <Logitech Logitech Dual Action, class 0/0, rev 1.10/3.00, addr 3> on usbus3
hidbus0: <HID bus> on usbhid0
hgame0: <Logitech Logitech Dual Action Joystick> on hidbus0
hidraw0: <Logitech Logitech Dual Action Raw HID Device> on hidbus0

And /var/log/Xorg.0.log will show the following output:

[  1145.679] (II) config/udev: Adding input device Logitech Logitech Dual Action Joystick (/dev/input/event6)
[  1145.679] (**) Logitech Logitech Dual Action Joystick: Applying InputClass "evdev pointer catchall"
[  1145.679] (**) Logitech Logitech Dual Action Joystick: Applying InputClass "libinput pointer catchall"
[  1145.679] (II) Using input driver 'libinput' for 'Logitech Logitech Dual Action Joystick'
[  1145.679] (**) Logitech Logitech Dual Action Joystick: always reports core events
[  1145.679] (**) Option "Device" "/dev/input/event6"
[  1145.679] (**) Option "_source" "server/udev"
[  1145.682] (II) event6  - Logitech Logitech Dual Action Joystick: is tagged by udev as: Mouse
[  1145.683] (II) event6  - Logitech Logitech Dual Action Joystick: device is a pointer
[  1145.684] (II) event6  - Logitech Logitech Dual Action Joystick: device removed
[  1145.684] (**) Option "config_info" "udev:/dev/input/event6"
[  1145.685] (II) XINPUT: Adding extended input device "Logitech Logitech Dual Action Joystick" (type: MOUSE, id 12)
[  1145.691] (**) Option "AccelerationScheme" "none"
[  1145.695] (**) Logitech Logitech Dual Action Joystick: (accel) selected scheme none/0
[  1145.695] (**) Logitech Logitech Dual Action Joystick: (accel) acceleration factor: 2.000
[  1145.695] (**) Logitech Logitech Dual Action Joystick: (accel) acceleration threshold: 4
[  1145.698] (II) event6  - Logitech Logitech Dual Action Joystick: is tagged by udev as: Mouse
[  1145.699] (II) event6  - Logitech Logitech Dual Action Joystick: device is a pointer

If I unload iichid and run "webcamd -N Logitech-Logitech-Dual-Action -S unknown -M 0", it will also show the same output in Xorg.0.log. Udev is capable of tagging devices specifically as joysticks, but USB game controllers are being tagged as mice instead. As a result, the only functionality from the controller is that the left joystick moves the mouse cursor. So I don't know if FreeBSD's evdev support lacks support for joysticks or if maybe there's just a problem with correctly detecting these devices and giving them the proper tag.
Comment 1 Steve Wills freebsd_committer freebsd_triage 2020-10-29 15:31:36 UTC
FWIW, FreeBSD doesn't have "udev" proper, it has libudev-devd ("libudev-compatible interface for devd") and libgudev ("GObject bindings for libudev").
Comment 2 Alex S 2020-10-29 15:41:20 UTC
(In reply to Patrick McMunn from comment #0)

> Logitech Logitech Dual Action Joystick: device is a pointer

Is this different from Linux?

> So I don't know if FreeBSD's evdev support lacks support for joysticks or if maybe there's just a problem with correctly detecting these devices and giving them the proper tag.

X11 itself lacks any support for joysticks, it only knows (and able to present to applications) keyboard and pointer devices.
Comment 3 Vladimir Kondratyev freebsd_committer freebsd_triage 2020-10-29 18:24:35 UTC
(In reply to Alex S from comment #2)
> X11 itself lacks any support for joysticks,
> it only knows (and able to present to applications)
> keyboard and pointer devices.
Actually, X11 does know of joystick presence. See udev autoconfiguration backend sources: https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/config/udev.c#L254

But... FreeBSD does not have sysfs and most likely will never have, so libudev is a shim which uses libmagic-alike heuristics taken from xf86-input-evdev to detect device type and type tag based on device's evdev descriptor: 
https://github.com/FreeBSDDesktop/libudev-devd/blob/master/udev-utils.c#L410

It is highly likely that this logic was not ever tested and just does not work in joystick part. So we can try to fix it or e.g. steal from alternative udev-shim library: https://github.com/jiixyj/libudev-fbsd/blob/master/src/libudev.c#L245
Comment 4 Alex S 2020-10-29 18:37:10 UTC
(In reply to Vladimir Kondratyev from comment #3)

> Actually, X11 does know of joystick presence. See udev autoconfiguration backend sources: https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/config/udev.c#L254

This is a bit misleading. How do I get values controller axes through xlib/xcb? All six of them, of course.
Comment 5 Alex S 2020-10-29 18:37:27 UTC
(In reply to Alex S from comment #4)

* for
Comment 6 Vladimir Kondratyev freebsd_committer freebsd_triage 2020-10-29 19:07:32 UTC
(In reply to Alex S from comment #4)
> This is a bit misleading. How do I get values controller
> axes through xlib/xcb? All six of them, of course.

I don't know. I never tried to use joysticks/gamepads as game controller neither with Linux nor with FreeBSD and do not know what I can do with them. Although touchpad part of PS4's gamepad works for me as touchpad.
Comment 7 waitman 2020-10-29 19:39:44 UTC
I have used a joystick on FreeBSD. webcamd takes the device.

ugen0.5: <HJC Game GAME FOR WINDOWS> at usbus0
uhid2 on uhub1
uhid2: <HJC Game GAME FOR WINDOWS, rev 2.00/1.70, addr 6> on usbus0
uhid2: at uhub1, port 2, addr 6 (disconnected)
uhid2: detached

# usbinfo

ugen0.5: <HJC Game GAME FOR WINDOWS> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (500mA)


# ls -l /dev/input/*
crw-------  1 root     wheel     0xd Oct 29 15:06 /dev/input/event0
crw-------  1 root     wheel    0x2a Oct 27 23:56 /dev/input/event1
crw-rw----  1 webcamd  webcamd  0xee Oct 29 14:52 /dev/input/event10
crw-------  1 root     wheel    0x47 Oct 27 23:56 /dev/input/event2
crw-------  1 root     wheel    0x48 Oct 29 15:06 /dev/input/event3
crw-------  1 root     wheel    0x49 Oct 29 15:06 /dev/input/event4
crw-------  1 root     wheel    0x4a Oct 29 15:06 /dev/input/event5
crw-------  1 root     wheel    0x4f Oct 27 23:56 /dev/input/event6
crw-------  1 root     wheel    0xa3 Oct 29 15:06 /dev/input/event7
crw-------  1 root     wheel    0xf9 Oct 29 15:06 /dev/input/event8
crw-------  1 root     wheel    0x8e Oct 27 23:56 /dev/input/event9
crw-rw----  1 webcamd  webcamd  0xf0 Oct 29 14:52 /dev/input/js0

you can set up rules to give your regular used access, or I think it's just as easy to add your user to the webcamd group.

so, you can read the device. a game engine that works on FreeBSD such as SDL2 has the code to read it.

Here's a simple example: using libevdev.h.

(defines in /usr/local/include/linux/input-event-codes.h)

int nbuttons = 0;
fd = open("/dev/input/event10", O_RDONLY | O_NONBLOCK);
rc = libevdev_new_from_fd(fd, &dev);
for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
	if (libevdev_has_event_code(dev, EV_KEY, i)) {
		printf("%d - Joystick has button: 0x%x - %s\n", nbuttons, i,
			libevdev_event_code_get_name(EV_KEY, i));
			++nbuttons;
	}
}

0 - Joystick has button: 0x130 - BTN_SOUTH
1 - Joystick has button: 0x131 - BTN_EAST
2 - Joystick has button: 0x133 - BTN_NORTH
3 - Joystick has button: 0x134 - BTN_WEST
4 - Joystick has button: 0x136 - BTN_TL
5 - Joystick has button: 0x137 - BTN_TR
6 - Joystick has button: 0x13a - BTN_SELECT
7 - Joystick has button: 0x13b - BTN_START
8 - Joystick has button: 0x13c - BTN_MODE
9 - Joystick has button: 0x13d - BTN_THUMBL
10 - Joystick has button: 0x13e - BTN_THUMBR
Comment 8 Patrick McMunn 2020-10-31 00:19:38 UTC
I've been tinkering with things a bit to try to provide more information. I did notice that I had some tiny modicum of success when I used an Xbox 360 controller with webcamd. Xorg.0.log shows

[    60.941] (II) config/udev: Adding input device Microsoft X-Box 360 pad (/dev/input/event6)
[    60.941] (II) No input driver specified, ignoring this device.
[    60.941] (II) This device may have been added with another device file.

which is consistent with what I see in Xorg.0.log under Linux. Maybe it's because the Xbox 360 controller has a FreeBSD kernel driver? But I'm not sure why that should make a difference. Doesn't webcamd provide and use the Linux drivers for input devices? On a single occasion, pcsxr detected the Xbox 360 controller as an evdev device, but I haven't been able to repeat that. jstest-gtk can detect gamepads as /dev/input/js0, but that's the old Linux joystick API and not evdev, and I haven't found anything other than than jstest-gtk on FreeBSD which will use that.
Comment 9 Alex S 2020-10-31 01:42:30 UTC
(In reply to Patrick McMunn from comment #8)

If you want to use your gamepad with an emulator you need to build SDL with evdev support, see bug 249874.
Comment 10 Patrick McMunn 2021-04-06 03:02:56 UTC
I brought this issue up with a developer on Github. I tested a fix he made to libudev-devd, and it worked. He's already made a pull request with the changes. Assuming the changes are accepted, this bug should be fixed once an updated version of libudev-devd is available.