Setting up a Bluetooth Controller for Linux Gaming

Linux

Setting up a Bluetooth Controller for Linux Gaming
Posted by LordDaveTheKind, 24 January 2019 at 9:34 pm UTC | Views: 10,611

Recently I solved an issue for setting up my Wireless (via Bluetooth) controller on Steam for Linux, and decided to elaborate a little better about my experience, and share my results and observations with you all.

The controller I have used as a reference for the procedures here below is the ASUS Gamepad TV500BG, whose specs are detailed here. Alternatively, I have verified that the same procedures apply with any other Bluetooth device.

The important thing I would like to highlight is that my approach was to find a procedure that could work in several scenarios, such as for both native games (with or without Steam) and games running via Wine or Proton/Steam Play.

According to the approach mentioned above, I discarded immediately the use of the x360ce driver, which it is largely used for games running on Wine but it represents a limited solution from an architectural point of view.

Using the Userspace driver xboxdrv

The xboxdrv driver is the Xbox/360 gamepad driver for Linux running on userspace. It is widely considered as a replacement of the linux kernel module xpad, and shows significant advantages on handling several types of devices, other than the Xbox-like gamepads.

The additional capability provided by the xboxdrv driver is to remap any of your controller button or axis, and tweak the default configuration for adding new functionalities to it. By using xboxdrv, the device will be recognised then by Steam as an Xbox controller.

The only inconvenience I noticed when using xboxdrv was that the driver was able to lock and consume the hardware resource just exactly 60 seconds after launching the xboxdrv executable from the command line. This is a very well known issue tracked in this bug. You’ll also see that there’s a workaround noted.

I started with a udev rule for linking the input/event* device of the hardware controller in an arbitrarily named symlink (so that it would be easier to identify). The device has few attributes that make easy to recognise it. They can be read by typing the following statement in a terminal emulator:

$ udevadm info -a /sys/class/input/event*

where you have to replace the * above with the device ID (the highest number you find as soon as you turn the device on might be the right one). The output might look similar to the following:

  looking at device '/devices/pci0000:40/0000:40:07.1/0000:42:00.3/usb7/7-1/7-1:1.0/bluetooth/hci0/hci0:11/0005:0B05:4500.000B/input/input30/event26':
    KERNEL=="event26"
    SUBSYSTEM=="input"
    DRIVER==""

  looking at parent device '/devices/pci0000:40/0000:40:07.1/0000:42:00.3/usb7/7-1/7-1:1.0/bluetooth/hci0/hci0:11/0005:0B05:4500.000B/input/input30':
    KERNELS=="input30"
    SUBSYSTEMS=="input"
    DRIVERS==""
    ATTRS{name}=="ASUS Gamepad"
    ATTRS{phys}=="5c:f3:70:8f:66:37"
    ATTRS{properties}=="0"
    ATTRS{uniq}=="38:2c:4a:8c:2e:87"

The lines above are telling that the device currently identified as “event26” has an attribute name (“ASUS Gamepad”) which we can use to easily identify it in the udev rules. We can then open the user-defined rules file, as shown here below:

$ sudo nano /etc/udev/rules.d/75-input-events.rules

and add the following line to it:

KERNEL=="event*" , SUBSYSTEM=="input", MODE="0666"
KERNEL=="event*", ATTRS{name}=="ASUS Gamepad", SYMLINK+="input/event-asus-gamepad"

By specifying the last keyword in the rule, the system will automatically create the symlink /dev/input/event-asus-gamepad (named like that in a totally arbitrary way) pointing to the controller device any time it is turned on, regardless of the device current ID in the current session.

Now that we have a way for identifying the controller event device, we can restart the udev rules with the following command:

$ sudo udevadm control --reload-rules && sudo udevadm trigger

and then call the xboxdrv driver with this command:

$ xboxdrv --evdev "/dev/input/event-asus-gamepad" --config xboxdrv.config --debug

The –evdev option enables xboxdrv to read any input coming from the event-asus-gamepad device and convert it into an Xbox controller input. The Xbox-converted input signals are sent by a different char device, which is specified in the command output:

Your Xbox/Xbox360 controller should now be available as:
  /dev/input/js1
  /dev/input/event27

The new devices js1 and event27 above replace the old one, and will be automatically recognised by Steam.

The –config option defines a configuration file where I’ve specified all the mapping between the Asus Gamepad controller axes and buttons into the conventional Xbox ones:

[xboxdrv]
detach-kernel-driver=true
silent=true

[axismap]
-Y1 = Y1
-Y2 = Y2

[evdev-absmap]
ABS_X=x1
ABS_Y=y1
ABS_Z=x2
ABS_RZ=y2
ABS_BRAKE=lt
ABS_GAS=rt
ABS_HAT0X=dpad_x
ABS_HAT0Y=dpad_y

[evdev-keymap]
BTN_SOUTH=a
BTN_EAST=b
BTN_NORTH=x
BTN_WEST=y
BTN_TL=lb
BTN_TR=rb
BTN_THUMBL=tl
BTN_THUMBR=tr
KEY_BACK=back
KEY_HOMEPAGE=start
BTN_MODE=guide

The content of the configuration above above might vary according to your local controller.

I can then launch Steam with the following script:

#!/bin/sh

if [ -h /dev/input/event-asus-gamepad ]
then
# remove any previous instance:
        killall -KILL xboxdrv

# start the new driver in userspace mode:
        xboxdrv --evdev "/dev/input/event-asus-gamepad" \
        --config xboxdrv.config &
fi

/usr/bin/steam %U

In the same way, we could define the additional logic for giving an arbitrary event symlink to the xboxdrv controller device as soon as the system loads the driver. We can maintain again the user-defined rules file, as shown here below:

$ sudo nano /etc/udev/rules.d/75-input-events.rules

and add the following new line at the bottom:

KERNEL=="event*", ATTRS{name}=="Xbox Gamepad (userspace driver)", SYMLINK+="input/event-xboxdrv-gamepad"

With the definition above, the system will automatically create the symlink /dev/input/event-xboxdrv-gamepad regardless of the device current ID in the current user session.

Some people might try to run the xboxdrv driver as a daemon (with the options: –daemon –detach). Unfortunately I didn’t get a working controller when I tried to do it.

Alternatively, you could try to start xboxdrv as soon as you turn on (or plug) your controller. You can implement it by adding a RUN keyword on the udev rule above (please refer to the udev documentation for further information on it).

Although this approach looks more direct, I prefer to follow the recommendation to run the driver at the same moment you run your game. This can be particularly useful if you need a different keys mapping for each game.

Some additional consideration would apply according to the specific game category.

Games running natively on Linux

Some best examples of very well-known games belonging to this category are Bioshock InfiniteTomb Raider (2013) and Borderlands 2 (but this is just a personal opinion).

You have nothing to do in this case. Some specific games might require a value for the SDL environment variable SDL_JOYSTICK_DEVICE as shown in the example here below:

SDL_JOYSTICK_DEVICE=/dev/input/event-xboxdrv-gamepad

Although Steam will automatically identify the virtual Xbox Controller for most of the games.

Additionally, you can configure Steam itself with the Xbox Controller support (configuration is available under the menu: Steam –> Settings –> Controller –> General Controller Settings) as shown in the picture here below. This will enable you to use the controller as a replacement for the mouse pointer in Steam:

Hopefully some of you find this useful.