On Mon, Dec 28, 2020 at 05:03:14PM -0700, Thomas Frohwein wrote: > Hi, > > This is a diff to propose a new device type for USB gamecontrollers, > 'ujoy'. > > Rationale > --------- > > Since the tightening of security around USB devices, USB > gamecontrollers that generally attach to the kitchen-sink uhid device > don't work out of the box anymore since read permissions are absent. As > a consequence, USB gamecontrollers don't work out of the box anymore; > requiring a root user to find what uhid device the controller is > attached to and chmod +r that one. This poses a barrier to using those > devices, as well as in my opinion a security risk by enticing users to > indiscriminately do '# chmod +r /dev/uhid*' in order to not have to > re-apply permissions on different uhid devices multiple times. > > The proposed solution is inspired by the implementation of fido(4) [1]; > a similarly narrow use case for a certain type of USB devices. It > creates a device for gamecontrollers that has the minimum required > permissions, but won't require chmod(1)'ing device files to get the > controller working. > > Implementation in this Diff > --------------------------- > > This diff is largely based on reyk's commit for the fido(4) device from > December 2019 [1]. It creates a ujoy device and attaches USB devices > identified as HUG_JOYSTICK or HUG_GAME_PAD. > > ujoyopen() is set up such that it only allows read-only access. If it is > opened with write permissions, it should error with EPERM. Only a > subset of ioctls is allowed in ujoyioctl(), based on what I could find > that is used in devel/sdl2 (USB_GET_DEVICEINFO,USB_GET_REPORT, > USB_GET_REPORT_DESC,USB_GET_REPORT_ID), as well as FIONBIO and > FIOASYNC. > > This contains conf.c and MAKEDEV.md bits for the same architectures as > fido(4). A small man page, as well as updates to other pertinent man > pages (usb(4), uhidev(4)) are included, again following the example of > the commits for the fido(4) device. > > Credit to brynet@ who helped me extensively with this diff. > > Testing > ------- > > A simple way to test this without needing to do a full release is > building a kernel with the diff and booting into it, then creating the > updated MAKEDEV script with: > > $ cd /usr/src/etc/etc.amd64/ > $ make # this will create MAKEDEV in etc.amd64 > $ cd /dev > # sh /usr/src/etc/etc.amd64/MAKEDEV ujoy > > This creates 2 device ujoy/0 and ujoy/1 by default. The device is > read-only by default (444). > > Plug in your USB gamecontroller and check in dmesg that it attaches as > ujoy, not uhid. > > The simplest way to test is with usbhidctl(1): > > $ usbhidctl -f /dev/ujoy/0 -l > > This will loop through printing the state of buttons, sticks etc. until > exited with Crtl-C. > > Another way to test is with games/sdl-jstest. As the SDL backends use > /dev/uhid* to find gamecontrollers, the way I tested this is by > repurposing /dev/uhid0 with mknod(8) (note major 100 is for amd64): > > $ cd /dev > # rm uhid0 > # mknod -m 444 uhid0 c 100 0 > > I put the diff through a release(8) without xenocara on amd64, and it > built base without problems and /dev/MAKEDEV and the /dev/ujoy directory > all look correct. > > I have tested usbhidctl and sdl-jstest with an XBox 360 gamepad and the > Logitech F310 gamepad, the latter both in DInput and XInput mode. All > of those work as expected. > > Issues/Follow-up Tasks > ---------------------- > > As ujoy devices don't attach to /dev/uhid* anymore, ports that use > gamecontrollers will need to be patched. This seems to be mostly (if > not exclusively) sdl/sdl2-based ports, so I anticipate that patching > these 2 ports will take care of the bulk of the use cases. > > On other OS's, writing to gamecontrollers is used at times for the > "rumble" functionality of the controller, or setting LEDs (like the > circle LED on XBox 360 controllers that can reflect what player number > the gamepad is for). Those have to my knowledge never worked on OpenBSD > and are not of any immediate interest as far as I can tell. > > ok? comments?
The implementation as such looks fine to me. But I quickly gave the diff a spin before on amd64 using my PS controller, and the result is not what I would expect. With uhid, I can access the controller on /dev/uhid6. The attach looks like this: imac /bsd: uaudio0 at uhub4 port 4 configuration 1 interface 1 "Sony Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6 imac /bsd: uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec, 4 ctls imac /bsd: audio1 at uaudio0 imac /bsd: uhidev6 at uhub4 port 4 configuration 1 interface 3 "Sony Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6 imac /bsd: uhidev6: iclass 3/0, 180 report ids imac /bsd: uhid6 at uhidev6 reportid 1: input=63, output=0, feature=0 imac /bsd: uhid7 at uhidev6 reportid 2: input=0, output=0, feature=36 imac /bsd: uhid8 at uhidev6 reportid 4: input=0, output=0, feature=36 imac /bsd: uhid9 at uhidev6 reportid 5: input=0, output=31, feature=0 imac /bsd: uhid10 at uhidev6 reportid 8: input=0, output=0, feature=3 imac /bsd: uhid11 at uhidev6 reportid 16: input=0, output=0, feature=4 imac /bsd: uhid12 at uhidev6 reportid 17: input=0, output=0, feature=2 imac /bsd: uhid13 at uhidev6 reportid 18: input=0, output=0, feature=15 imac /bsd: uhid14 at uhidev6 reportid 19: input=0, output=0, feature=22 imac /bsd: uhid15 at uhidev6 reportid 20: input=0, output=0, feature=16 imac /bsd: uhid16 at uhidev6 reportid 21: input=0, output=0, feature=44 imac /bsd: uhid17 at uhidev6 reportid 128: input=0, output=0, feature=6 imac /bsd: uhid18 at uhidev6 reportid 129: input=0, output=0, feature=6 imac /bsd: uhid19 at uhidev6 reportid 130: input=0, output=0, feature=5 imac /bsd: uhid20 at uhidev6 reportid 131: input=0, output=0, feature=1 imac /bsd: uhid21 at uhidev6 reportid 132: input=0, output=0, feature=4 imac /bsd: uhid22 at uhidev6 reportid 133: input=0, output=0, feature=6 imac /bsd: uhid23 at uhidev6 reportid 134: input=0, output=0, feature=6 imac /bsd: uhid24 at uhidev6 reportid 135: input=0, output=0, feature=35 imac /bsd: uhid25 at uhidev6 reportid 136: input=0, output=0, feature=34 imac /bsd: uhid26 at uhidev6 reportid 137: input=0, output=0, feature=2 imac /bsd: uhid27 at uhidev6 reportid 144: input=0, output=0, feature=5 imac /bsd: uhid28 at uhidev6 reportid 145: input=0, output=0, feature=3 imac /bsd: uhid29 at uhidev6 reportid 146: input=0, output=0, feature=3 imac /bsd: uhid30 at uhidev6 reportid 147: input=0, output=0, feature=12 imac /bsd: uhid31 at uhidev6 reportid 160: input=0, output=0, feature=6 imac /bsd: uhid32 at uhidev6 reportid 161: input=0, output=0, feature=1 imac /bsd: uhid33 at uhidev6 reportid 162: input=0, output=0, feature=1 imac /bsd: uhid34 at uhidev6 reportid 163: input=0, output=0, feature=48 imac /bsd: uhid35 at uhidev6 reportid 164: input=0, output=0, feature=13 imac /bsd: uhid36 at uhidev6 reportid 165: input=0, output=0, feature=21 imac /bsd: uhid37 at uhidev6 reportid 166: input=0, output=0, feature=21 imac /bsd: uhid38 at uhidev6 reportid 167: input=0, output=0, feature=1 imac /bsd: uhid39 at uhidev6 reportid 168: input=0, output=0, feature=1 imac /bsd: uhid40 at uhidev6 reportid 169: input=0, output=0, feature=8 imac /bsd: uhid41 at uhidev6 reportid 170: input=0, output=0, feature=1 imac /bsd: uhid42 at uhidev6 reportid 171: input=0, output=0, feature=57 imac /bsd: uhid43 at uhidev6 reportid 172: input=0, output=0, feature=57 imac /bsd: uhid44 at uhidev6 reportid 173: input=0, output=0, feature=11 imac /bsd: uhid45 at uhidev6 reportid 174: input=0, output=0, feature=1 imac /bsd: uhid46 at uhidev6 reportid 175: input=0, output=0, feature=2 imac /bsd: uhid47 at uhidev6 reportid 176: input=0, output=0, feature=63 imac /bsd: uhid48 at uhidev6 reportid 177: input=0, output=0, feature=2 imac /bsd: uhid49 at uhidev6 reportid 178: input=0, output=0, feature=2 imac /bsd: uhid50 at uhidev6 reportid 179: input=0, output=0, feature=63 imac /bsd: uhid51 at uhidev6 reportid 180: input=0, output=0, feature=63 ujoy instead attached to previous uhid51, and there it is of no use obviously. I still can access the controller through uhid6. The attach with ujoy looks like this: imac /bsd: uaudio0 at uhub4 port 4 configuration 1 interface 1 "Sony Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6 imac /bsd: uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec, 4 ctls imac /bsd: audio1 at uaudio0 imac /bsd: uhidev6 at uhub4 port 4 configuration 1 interface 3 "Sony Interactive Entertainment Wireless Controller" rev 2.00/1.00 addr 6 imac /bsd: uhidev6: iclass 3/0, 180 report ids imac /bsd: uhid6 at uhidev6 reportid 1: input=63, output=0, feature=0 imac /bsd: uhid7 at uhidev6 reportid 2: input=0, output=0, feature=36 imac /bsd: uhid8 at uhidev6 reportid 4: input=0, output=0, feature=36 imac /bsd: uhid9 at uhidev6 reportid 5: input=0, output=31, feature=0 imac /bsd: uhid10 at uhidev6 reportid 8: input=0, output=0, feature=3 imac /bsd: uhid11 at uhidev6 reportid 16: input=0, output=0, feature=4 imac /bsd: uhid12 at uhidev6 reportid 17: input=0, output=0, feature=2 imac /bsd: uhid13 at uhidev6 reportid 18: input=0, output=0, feature=15 imac /bsd: uhid14 at uhidev6 reportid 19: input=0, output=0, feature=22 imac /bsd: uhid15 at uhidev6 reportid 20: input=0, output=0, feature=16 imac /bsd: uhid16 at uhidev6 reportid 21: input=0, output=0, feature=44 imac /bsd: uhid17 at uhidev6 reportid 128: input=0, output=0, feature=6 imac /bsd: uhid18 at uhidev6 reportid 129: input=0, output=0, feature=6 imac /bsd: uhid19 at uhidev6 reportid 130: input=0, output=0, feature=5 imac /bsd: uhid20 at uhidev6 reportid 131: input=0, output=0, feature=1 imac /bsd: uhid21 at uhidev6 reportid 132: input=0, output=0, feature=4 imac /bsd: uhid22 at uhidev6 reportid 133: input=0, output=0, feature=6 imac /bsd: uhid23 at uhidev6 reportid 134: input=0, output=0, feature=6 imac /bsd: uhid24 at uhidev6 reportid 135: input=0, output=0, feature=35 imac /bsd: uhid25 at uhidev6 reportid 136: input=0, output=0, feature=34 imac /bsd: uhid26 at uhidev6 reportid 137: input=0, output=0, feature=2 imac /bsd: uhid27 at uhidev6 reportid 144: input=0, output=0, feature=5 imac /bsd: uhid28 at uhidev6 reportid 145: input=0, output=0, feature=3 imac /bsd: uhid29 at uhidev6 reportid 146: input=0, output=0, feature=3 imac /bsd: uhid30 at uhidev6 reportid 147: input=0, output=0, feature=12 imac /bsd: uhid31 at uhidev6 reportid 160: input=0, output=0, feature=6 imac /bsd: uhid32 at uhidev6 reportid 161: input=0, output=0, feature=1 imac /bsd: uhid33 at uhidev6 reportid 162: input=0, output=0, feature=1 imac /bsd: uhid34 at uhidev6 reportid 163: input=0, output=0, feature=48 imac /bsd: uhid35 at uhidev6 reportid 164: input=0, output=0, feature=13 imac /bsd: uhid36 at uhidev6 reportid 165: input=0, output=0, feature=21 imac /bsd: uhid37 at uhidev6 reportid 166: input=0, output=0, feature=21 imac /bsd: uhid38 at uhidev6 reportid 167: input=0, output=0, feature=1 imac /bsd: uhid39 at uhidev6 reportid 168: input=0, output=0, feature=1 imac /bsd: uhid40 at uhidev6 reportid 169: input=0, output=0, feature=8 imac /bsd: uhid41 at uhidev6 reportid 170: input=0, output=0, feature=1 imac /bsd: uhid42 at uhidev6 reportid 171: input=0, output=0, feature=57 imac /bsd: uhid43 at uhidev6 reportid 172: input=0, output=0, feature=57 imac /bsd: uhid44 at uhidev6 reportid 173: input=0, output=0, feature=11 imac /bsd: uhid45 at uhidev6 reportid 174: input=0, output=0, feature=1 imac /bsd: uhid46 at uhidev6 reportid 175: input=0, output=0, feature=2 imac /bsd: uhid47 at uhidev6 reportid 176: input=0, output=0, feature=63 imac /bsd: uhid48 at uhidev6 reportid 177: input=0, output=0, feature=2 imac /bsd: uhid49 at uhidev6 reportid 178: input=0, output=0, feature=2 imac /bsd: uhid50 at uhidev6 reportid 179: input=0, output=0, feature=63 imac /bsd: ujoy0 at uhidev6 reportid 180: input=0, output=0, feature=63 I haven't analyzed yet what happens in the code. I can provide an lsusb of the controller if it's more obvious to you.