Open PaddyMac opened 3 years ago
I've tested a few Linux native games from my GoG collection under FreeBSD that run great under FreeBSD and have gamepad support but don't detect that a gamepad is present on FreeBSD.
Do you run them on top of stock linuxolator or use some extra shims like https://github.com/shkhln/linuxulator-steam-utils ?
I just realized you replied to my bug report. I've only tried a few Linux games so far on FreeBSD. Most of my games are from GOG. I don't really use Steam much, but I do have a few Steam games. One Linux game I have from GOG, so it doesn't use Steam, is Hollow Knight. It doesn't even detect that a controller is plugged in. I hadn't even tried using a controller with Steam until you asked about it, so I tested Yuppie Psycho. Now it does detect that a controller is attached, and it correctly identifies it as an Xbox 360 controller. However, the only controls that do anything are the left and right joysticks. None of the other buttons on the controller do anything. So I guess there is a partial success there, but it's not enough success to actually be useful. I will mention one possible change to my system since I reported this 11 days ago that could affect any results I have. I am using a patched version of SDL2 which isn't in the ports tree yet. So it might affect anything that uses SDL2, but I don't think either of the games I've tested or Steam uses SDL2. I haven't yet tried any Windows games with Steam yet, but I tried i386-wine-devel, and running "wine control" and checking the game controllers option shows that wine doesn't detect any attached controllers. However, I just tried installing wine-proton, and I ran "/usr/local/wine-proton/bin/wine64 control" and the Proton version of Wine does detect and properly recognize the Xbox 360 controller, and all the joysticks and buttons except for the big X button in the middle work when I use the test option. But wine-proton uses SDL2, so that's probably not particularly useful for this issue because SDL2 is likely handling the gamepad detection (I think SDL2 support is turned off by default in the other wine packages for FreeBSD which is probably why i386-wine-devel didn't see it).
Hollow Knight. It doesn't even detect that a controller is plugged in.
Do you know which interface it uses to communicate with game controller: evdev, input/js or hidraw? and which to enumerate devices? udev or just readdir or something else? For now FreeBSD supports evdev and hidraw as transport in kernel and input/js via webcamd. But enumeration through udev is not supported as it depends on some bits of sysfs which is not emulated for evdev. I have no plans to add sysfs support to evdev but it is possible to port libudev-devd to Linux and than replace linuxolator's libudev.so with ported binary. I have some distant plans to do such a port so may be it will help.
None of the other buttons on the controller do anything.
I have no idea what is happening here.
Does Xbox 360 controller works properly with Yuppie Psycho under Linux?
Which protocol it uses? fstat -p PID
can be useful here
SDL normally works with libudev, although it should be able use inotify (recent addition) or just straight polling: https://github.com/libsdl-org/SDL/blob/f1ad942a1175105e4ab7d1cd98b842f84b3bcb2b/src/joystick/linux/SDL_sysjoystick.c#L619-L641. The emphasis on should, because I don't think that polling fallback worked properly when I was testing it last year. SDL was simply bailing out on unsuccessful libudev initialization.
That's actually one of the reasons steam-utils contains a trivial libudev stub (the stub successfully initializes and does absolutely nothing). This is still not enough to force fallback to polling, so a kludge in the form of the SDL_JOYSTICK_DEVICE environment variable is required.
For what it's worth, I don't remember what SDL version that was and this code keeps constantly changing, so maybe now this is not an issue.
SDL2 support is turned off by default in the other wine packages for FreeBSD
FYI, the official excuse for that is "not enough demand". Same deal with Vulkan.
SDL normally works with libudev
I ported libudev-devd to Linux: https://github.com/wulf7/libudev-devd. At least it compiles on Fedora 32 and Ubuntu 20. I did not try LD_PRELOAD it before start of libinput or libSDL yet though, so I don't know if it works or not.
it should be able use inotify
inotify should be supported at kernel level. I do not realize how to access kqueue(2) under linuxolator to use shims like libinotify-kqueue.
This works as intended with a couple of caveats:
env CC=/compat/linux/opt/rh/devtoolset-7/root/usr/bin/gcc CFLAGS="--sysroot /compat/linux" meson <buildir>
. A few constants are somehow not there as well:
% git diff
diff --git a/udev-utils.c b/udev-utils.c
index 47ab373..74a272c 100644
--- a/udev-utils.c
+++ b/udev-utils.c
@@ -420,6 +420,10 @@ use_ioctl:
goto bail_out;
}
+#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_RIGHT 0x223 +#define BTN_SOUTH 0x130 +
2. On FreeBSD 13 /compat/linux/dev is a separate mount from /dev, as a consequence input devices there might have different owner/group/permissions. YMMV.
we need at least GCC 4.9 for stdatomic.h
I dropped atomics as systemd does not use them. Also I resurrected autotools configuration scripts to remove meson dependency. Now installation of linux-c7-devtools & linux-c7-make is enough to build libudev-devd in /compat/linux (CentOS 7) chroot.
+#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_RIGHT 0x223 +#define BTN_SOUTH 0x130
Committed, thanks! https://github.com/wulf7/libudev-devd repo is updated with aforementioned changes.
Finally, I was able to build it from my home directory using following sequence of commands:
$ ./autogen.sh
$ export CFLAGS=-nostdinc\ -I/compat/linux/usr/include\ -I/compat/linux/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include
$ /compat/linux/bin/bash ./configure
$ /compat/linux/bin/make
Is there a simpler way to omit FreeBSD includes at build time?
Simple bundled test program also works under linux emulation:
$ sudo /compat/linux/bin/bash udev-test
Device Node Path: /dev/input/event0
Device Node Path: /dev/input/event1
Device Node Path: /dev/input/event2
Device Node Path: /dev/input/event3
Device Node Path: /dev/input/event4
............................
select() says there should be data
Got Device
Node: /dev/input/event4
Subsystem: input
Action: remove
........
select() says there should be data
Got Device
Node: /dev/input/event4
Subsystem: input
Action: add
.....................^C
It successfully enumerated evdev devices and detected their reattachments.
I think getting rid of Meson is a bit of overreaction, it doesn't really interfere with our intended usage.
Is there a simpler way to omit FreeBSD includes at build time?
--sysroot /compat/linux
as mentioned above. (Add -m32
for 32-bit binaries.) In theory Linux gcc should work even without this, however by setting sysroot to /compat/linux we are avoiding the usual Linuxulator implicit /compat/linux/path -> path fallback behavior.
Also, as far as I can tell, there no difference in result between
/compat/linux/bin/env PATH=/compat/linux/bin CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure
/compat/linux/bin/make
and
env CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure
make
for libudev-devd. Using exclusively Linux tools does make sense in general, but not really necessary in this particular case.
I think getting rid of Meson is a bit of overreaction, it doesn't really interfere with our intended usage.
No one got rid of Meson configurator. It still exists. Autotools was resurrected to make things simpler on meson-less distributives like CentOS7 where otherwise you will have to install packages from 3-rd part repos (EPEL).
/compat/linux/bin/env PATH=/compat/linux/bin CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure /compat/linux/bin/make
It works! Thanks!
env CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure make
Unlike previous case it brokes test utility. Although build ends successfully, attempt to run resulting binary fails:
sudo /compat/linux/bin/bash udev-test
/home/wulf/dvp/libudev-devd/.libs/udev-test: error while loading shared libraries: /usr/local/lib/libudev.so.0: ELF file OS ABI invalid
Most probably, the culprit is shell wrapper rather then binary test utility or library itself.
It works! Thanks!
It looks like
env PATH=/compat/linux/bin CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure
make
works too. So PATH variable is important as well.
2 @PaddyMac:
I just added some notes how to build and use libudev-devd under Linuxolator. Just copy them here:
install devel/linux-c7-devtools, devel/autoconf and devel/automake than compile libudev.so library and install it somewhere under /compat/linux.
To build and install 64-bit library:
cd libudev-devd
./autogen.sh
env CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux" ./configure --libdir=/usr/lib64/shims
make
sudo make install-exec DESTDIR=/compat/linux
To build and install 32-bit library:
cd libudev-devd
./autogen.sh
env CC="/compat/linux/bin/gcc" CFLAGS="--sysroot /compat/linux -m32" ./configure --libdir=/usr/lib/shims
make
sudo make install-exec DESTDIR=/compat/linux
To run my_64bit_app or my_32bit_app with libudev overloaded with libudev-devd use
LD_PRELOAD=/usr/lib64/shims/libudev.so my_64bit_app
or
LD_PRELOAD=/usr/lib/shims/libudev.so my_32bit_app
P.S. I have never tested it with apps other then simple bundled test utility.
Chromium/CEF/Electron also require udev_set_log_fn and udev_set_log_priority. (Their presence is checked immediately after dlopen.) Should be called from here, although that doesn't seem to work at the moment… Might be worth investigating later.
I have added stubs for udev_set_log_fn and udev_set_log_priority to libudev-devd. I hope it will help.
FYI. I wrote simple library which exposes some FreeBSD syscalls to linuxolator: https://github.com/wulf7/linux-libbsd So it is now possible to run libudev-devd and libinotify under Linux emulation in real native mode. README is yet to be written though.
I finally had a chance to follow up and test out some things. I compiled both the 64 and 32 bit versions of libudev-devd with only one minor issue. I installed linux-c7-devtools, autoconf, and automake, but when running autogen.sh I got an error about libtool. So I had to install that as well. After that, everything worked fine.
So I tried running Hollow Knight as you suggested:
patrick@l875d-s7210:~/GOG Games/Hollow Knight $ LD_PRELOAD=/usr/lib64/shims/libudev.so ./start.sh ld-elf.so.1: Cannot open "/usr/lib64/shims/libudev.so"
So I tried :
patrick@l875d-s7210:~/GOG Games/Hollow Knight $ LD_PRELOAD=/compat/linux/usr/lib64/shims/libudev.so ./start.sh ld-elf.so.1: Shared object "libpthread.so.0" not found, required by "libudev.so"
I assumed it was looking for the Linux version of pthread.so.0, but that file exists at /compat/linux/usr/lib64/libpthread.so.0. So I tried making a symbolic link in /usr/lib with "ln -s libthr.so libpthread.so.0"
So I tried again:
patrick@l875d-s7210:~/GOG Games/Hollow Knight $ LD_PRELOAD=/compat/linux/usr/lib64/shims/libudev.so ./start.sh ld-elf.so.1: Shared object "libc.so.6" not found, required by "libudev.so"
If I'm not mistaken, libc.so.6 is provided by glibc which is the GNU C library. So I'm guessing it is in fact looking for the Linux libraries but has the path wrong and is looking in FreeBSD's directories for those libraries instead of in the /compat/linux prefix.
patrick@l875d-s7210:~/GOG Games/Hollow Knight $ LD_PRELOAD=/usr/lib64/shims/libudev.so ./start.sh ld-elf.so.1: Cannot open "/usr/lib64/shims/libudev.so"
That's because you are implicitly starting /usr/local/bin/bash (most likely). You need to either prefix that command with /compat/linux/bin/env or change the shebang string in the script to /compat/linux/bin/sh.
Another option you have are:
LD_PRELOAD=/usr/lib64/shims/libudev.so /compat/linux/bin/bash ./start.sh
LD_PRELOAD=/usr/lib64/shims/libudev.so
export LD_PRELOAD
It may happen that start.sh already defines LD_PRELOAD variable. In that case you should append :/usr/lib64/shims/libudev.so
to this string. Mind the colon as separator.
While we are at it, since libudev.so.0 is typically accessed through dlopen, LD_PRELOAD might be a bit tricky, it's better to add libudev's dir to LD_LIBRARY_PATH.
I have no idea what is happening here. Does Xbox 360 controller works properly with Yuppie Psycho under Linux? Which protocol it uses?
fstat -p PID
can be useful here
I first tried running fstat on my Gentoo installation, but fstat doesn't exist -- at least not by that name. In any case, the Xbox 360 controller works fine on Yuppie Psycho under Linux. So I ran Yuppie Psycho on FreeBSD and ran fstat -p. I'm not 100% sure I ran it on the right PID, but I think I did. The game uses Java, and so the name it runs as doesn't make it obvious. In any case, judging by the output I saw, it did reference /dev/input/event6 which is the evdev device for my gamepad. I'll attach the full output. Unfortunately I don't know how it enumerates devices. Maybe the fact that it uses Java could be a clue?
Also, I did try adding the LD_PRELOAD variable to the script, and now Hollow Knight detects and uses my gamepad under FreeBSD! This is absolutely amazing and a huge breakthrough! It didn't make any difference for Yuppie Psycho, but I guess that isn't surprising since it seems to already be accessing the gamepad -- even if imperfectly -- through some other means.
Maybe the fact that it uses Java could be a clue?
I added stubs for missing methods which java udev wrapper[1] requires to libudev. I doubt they will help, but it worth a try latest libudev-devd.
This is absolutely amazing and a huge breakthrough!
Great! I think that I have to submit linux-c7-libudev-devd
port after things got stabilized. :-)
This project appears to be doing a good job at getting game controller support working under FreeBSD with the Linux evdev interface. But right now, the actual usefulness is very limited. In real-world application, the most likely use case for this project is for Linux native games to run under FreeBSD's Linux emulation layer and be able to use gamepads just as if they were running under Linux. But right now, that isn't the case. I've tested a few Linux native games from my GoG collection under FreeBSD that run great under FreeBSD and have gamepad support but don't detect that a gamepad is present on FreeBSD.
I don't know the details of how controller detection works on Linux, but I'm assuming that there is still a piece missing. Is this some kind of functionality that needs to be added to FreeBSD's Linux emulation layer? Or does there need to be some kind of shim layer that allows proper communication between Linux games and the FreeBSD interface?