If you want to support me or accelerate the development of a special feature, consider a small donation :heart:
Just leave a message if your donation is for a specific use (like a new hardware or a specific function).
Advanced Linux Driver for Xbox One Wireless Gamepad
This is the first driver for the Xbox One Wireless Gamepad (which is shipped with the Xbox One S). I wrote it for a student project at fortiss GmbH and it is fully functional but does only support the connection via Bluetooth as yet - more will follow.
Many thanks to Kai Krakow who sponsored me a Xbox One Wireless Controller :video_game: (including Wireless Adapter) and a pack of mouthwatering guarana cacao :coffee:
Other Projects
- xow is a driver for the Xbox One S controllers, too, and supports the native dongles packaged with the controller. Kudos to @meduslaix for working together on finding some work aorunds for controller firmware bugs.
- xpad supports this and many other controllers in USB mode.
These other projects may not support some of the advanced features of xpadneo.
SDL2 Breaking Changes
As of SDL 2.0.12, SDL introduced a new HIDAPI which can read HID devices in raw mode, bypassing the drivers. Due to
the way SDL works, and because xpadneo exposes hidraw devices as user-readable, SDL may see wrong button mappings
because it may make wrong assumptions about the protocol mode of Xbox and compatible controllers. If you see wrong
button mappings / missing buttons in SDL applications, you may need to turn off this behavior by setting an
environment variable in your profile: SDL_JOYSTICK_HIDAPI=0
Advantages of this driver
- Supports Bluetooth
- Supports all Force Feedback/Rumble effects through Linux
ff-memlesseffect emulation - Supports Trigger Force Feedback in every game by applying a pressure-dependent effect intensity to the current rumble effect (not even supported in Windows)
- Supports disabling FF
- Supports multiple Gamepads at the same time (not even supported in Windows)
- Offers a consistent mapping, even if the Gamepad was paired to Windows/Xbox before, and independent of software layers (SDL2, Stadia via Chrome Gamepad API, etc)
- Working Select, Start, Mode buttons
- Correct Axis Range (signed, important for e.g. RPCS3)
- Supports Battery Level Indication (including the Play `n Charge Kit)

- Easy Installation
- Agile Support and Development
- Supports customization through profiles
- Optional high-precision mode for Wine/Proton users
Xbox One S Wireless controller
The driver emulates profile switching for this controller by pressing buttons A, B, X, or Y while holding down the Xbox logo button. However, the following caveats apply:
- Profiles currently behave all the same, and there is no support for configuring them.
- Full support will be available once the Xbox Elite Series 2 controller is fully supported.
Xbox Elite Series 2 Wireless controller
While basic support for the Xbox Elite Series 2 Wireless controller is present, the following features are missing:
- Profile support. All four profiles behave the same way currently, and there is no support for configuring them.
- The four paddles at the bottom are currently not supported.
8BitDo controllers
This driver respects the Nintendo layout of those controllers and exposes them correctly as button A, B, X, and Y as labelled on the device. This is swapped compared to the original Xbox controller layout. You can override that behavior with a quirk flag (by removing the Nintendo layout bit).
Breaking change: Users of previous versions of the driver may want to remove their custom SDL mappings. Full support has been added for these controllers and broken mapping of previously versions no longer needs to be applied. See also: SDL.
Getting started
Prerequisites
Make sure you have installed dkms, linux headers and a bluetooth implementation (e.g. bluez) and their dependencies.
- On Arch and Arch-based distros (like Antergos), try
sudo pacman -S dkms linux-headers bluez bluez-utils - On Debian based systems (like Ubuntu) you can install those packages by running
sudo apt-get install dkms linux-headers-`uname -r` - On Fedora, it is
sudo dnf install dkms make bluez bluez-tools kernel-devel-`uname -r` kernel-headers-`uname -r` - On Manjaro try
sudo pacman -S dkms linux-latest-headers bluez bluez-utils - On OSMC you will have to run the following commands
sudo apt-get install dkms rbp2-headers-`uname -r`sudo ln -s "/usr/src/rbp2-headers-`uname -r`" "/lib/modules/`uname -r`/build"(as a workaround) - On Raspbian, it is
sudo apt-get install dkms raspberrypi-kernel-headersIf you recently updated your firmware usingrpi-updatethe above package may not yet include the header files for your kernel. Please follow the steps described here in this case. - On generic distributions, it doesn’t need DKMS but requires a configured kernel source tree, then:
cd hid-xpadneo && make modules && sudo make modules_install
Please feel free to add other Distributions as well!
Installation
- Download the Repository to your local machine
git clone https://github.com/atar-axis/xpadneo.git cd xpadneo- If using DKMS, run
sudo ./install.sh - If not using DKMS, follow steps above (generic distribution)
- Done!
Connection
sudo bluetoothctl[bluetooth]# scan on- wait until all available devices are listed (otherwise it may be hard to identify which one is the gamepad)
- push the connect button on upper side of the gamepad, and hold it down until the light starts flashing fast
- wait for the gamepad to show up in bluetoothctl, remember the
address (e.g. `C8:3F:26:XX:XX:XX`) [bluetooth]# pair <MAC>[bluetooth]# trust <MAC>[bluetooth]# connect <MAC>- The
<MAC>parameter is optional if the command line already shows the controller name
You know that everything works fine when you feel the gamepad rumble ;)
Configuration
- If using DKMS: Use
sudo ./configure.shto configure the driver as you wish. The script will guide you through the available options.
Profile switching
The driver supports switching between different profiles on the Xbox One S controller by holding down the Xbox logo button while pressing button A, B, X, or Y to select one of four profiles. This switching can be done at any time even while in a game. The API for customizing each profile does not exist yet.
Update
In order to update xpadneo, do the following
- Update your cloned repo:
git pull - If using DKMS: Run
sudo ./update.sh - otherwise follow the steps above (generic distribution)
Uninstallation
- If using DKSM: Run
sudo ./uninstall.shto remove all installed versions of hid-xpadneo - otherwise follow the steps above (generic distribution)
Further information
For further information please visit the GitHub Page https://atar-axis.github.io/xpadneo/ which is generated
automatically from the content of the /docs folder.
You will find there e.g. the following sections
BT Dongles
Please report your Dongles and how they work here
Cambridge Silicon Radio
- Panda Bluetooth 4.0 USB Nano Adapter
- Chipset: CSR ???
ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)- Performance:
- Re-Connection Problems
- Reliable once connected
- Reported by @ugly95 here
- MIATONE Bluetooth Adapter Bluetooth CSR 4.0
- Chipset: CSR 8510
ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)- Performance:
- Re-Connection Problems
- Reliable once connected
- Reported by @ugly95 here
- CSL - Bluetooth 4.0 USB Adapter
- Sabrent USB Bluetooth 4.0 Micro Adapter for PC
- Chipset CSR ???
ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)- Performance:
- Re-Connection Problems
- Reliable once connected
- Reported by @ugly95 here
- Yizhet USB nano Bluetooth 4.0 Adapter
- Chipset CSR 8510 A10
ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)- Performance:
- Re-Connection Problems
- Reliable once connected
- Reported by @NoXPhasma here
Broadcom
- Plugable USB Bluetooth 4.0 Low Energy Micro Adapter
- Targus BT 4.0 USB adapter
- Chipset: BCM20702A0
ID 0a5c:21e8 Broadcom Corp. BCM20702A0 Bluetooth 4.0- Performance:
- Connection flawless
- Sometimes laggy while Gameplay
- Reported by Zowayix here
Qualcomm
- Unspecified model (https://github.com/atar-axis/xpadneo/issues/180):
btmonlogs showed very low input report rate and high input lag (300ms+)
Configuration
Alternatively to using the config-script, you can also do it by hand:
The driver can be reconfigured at runtime by accessing the following sysfs
files in /sys/module/hid_xpadneo/parameters:
disable_deadzones(default0)0enables standard behavior to be compatible withjoydevexpectations1enables raw passthrough of axis values without dead zones for high-precision use with modern Wine/Proton games
trigger_rumble_mode(default0)0rumbles triggers by pressure and current rumble effect1rumbles triggers by force direction (non-conformant)2disables trigger rumble
rumble_attenuation(default0,0)- Attenuation the strength of the force feedback
0(none, full rumble) to100(max, no rumble)- If one or two values are given, the first value is the overall attenuation
- If two values are given, the second value applies an extra attenuation to the triggers
- Example 1:
0,100turns trigger rumble off,100,0or100turn all rumble off - Example 2:
50,50makes 50% rumble overall, and 25% for the triggers (50% of 50% = 25%) - Example 3:
50makes 50% rumble overall (main and triggers) - Trigger-only rumble is not possible
quirks(default empty)- Let’s you adjust the quirk mode of your controller
- Comma separated list of
address:flagspairs - Specify your controller MAC address in the format
11:22:33:44:55:66 - Specify the flags as sum of the following:
1if your controller does not support pulse parameters (i.e., 8BitDo controllers)2if your controller does not support trigger rumble (most clones in compat-mode)4if your controller does not support individual motor programming (i.e., 8BitDo controllers)
Some settings may need to be changed at loading time of the module, take a look at the following example to see how that works:
Example
To disable trigger rumbling temporarily, run
echo 2 | sudo tee /sys/module/hid_xpadneo/parameters/trigger_rumble_mode
To make the setting permanent and applied at loading time, try
echo "options hid_xpadneo trigger_rumble_mode=2" | sudo tee /etc/modprobe.d/99-xpadneo-bluetooth.conf
Troubleshooting
Gamepad does not connect properly
Enhanced ReTransmission Mode is enabled
If your Gamepad is stuck in a Connected / Disconnected loop, then it may be caused by ERTM. Usually the driver does disable this incompatible mode automatically, but sometimes things go wrong.
Incompatible Bluetooth Chipset
Some chipsets, e.g. the CSR 85xx, do have problems when you try to reconnect the Gamepad.
Some chipsets may need additional driver firmware to work correctly. Try installing
linux-firmware from your distribution.
Secure Boot
Secure Boot may be enabled on your computer. On most Linux distribution, running mokutil --sb-state will tell you if
it is the case. When Secure Boot is enabled, unsigned kernel module cannot be loaded. Two options are available:
- Disable Secure Boot.
- Sign the module yourself.
Instructions for both of these options are available here. Secure Boot is not enabled and pairing still fails? See Debugging.
Gamepad is connected but did not rumble
If the gamepad does connect but it doesn’t rumble, then mosty probably the wrong driver is loaded, or the gamepad is quirky and doesn’t fully support the protocol.
Gamepad has quirks (i.e., wrong rumble behavior)
You may want to try serveral combinations of quirk flags added to the module paramters.
See Configuration and modinfo hid-xpadneo
for more information. You may also want to use the hidraw testing utility which bypasses the
driver and let’s you try different combination of parameters. The utility is located at
misc/examples/c_hidraw.
Gamepad axes are swapped, seemingly unresponsive or strange behavior
If you observe this problem with jstest, systemsettings joystick (KDE) or jstest-gtk, there’s usually nothing
to do as these test programs use the old joydev API while most (modern) games use the evdev API. Some emulators,
tho, use the joydev API and do not respect the axes naming from evdev. In this case, please run the following
command to correct the axes mapping for the js interface:
jscal -u 8,0,1,3,4,2,5,16,17,10,304,305,307,308,310,311,314,315,317,318 /dev/input/js0
Explanation: -u set the mapping for 8 axes to axes code 0,1,3,4,... and for 10 buttons to button codes
304,305,307,308,.... This only remaps the joydev API, not the evdev API. Making this change may have
unexpected consequences for applications using both APIs.
IMPORTANT: Now test all your axes to collect calibration data. You can then use the following command to store the settings permanently:
sudo jscal-store /dev/input/js0
If the gamepad does not restore the mapping after disconnecting and reconnecting it, i.e., your distribution doesn’t
ship a proper udev rule for that, you may want to add the this udev rule, then reboot (see also
/misc/examples/udev-rules/99-xpadneo-joydev.rules):
# /etc/udev/rules.d/99-xpadneo-joydev.rules
KERNEL=="js*", ACTION=="add", DRIVERS=="xpadneo", RUN+="/usr/bin/jscal-restore %E{DEVNAME}"
From now on, connecting the gamepad should restore the values from /var/lib/joystick/joystick.state. If you messed up, simply remove your gamepad from the file and start over.
Please check, if jscal-restore is really in /usr/bin, otherwise use the correct path, found by running:
type -p jscal-restore
IMPORTANT NOTE: The Chrome gamepad API (used for Stadia and other browser games) is a hybrid user of both the
joydev and the evdev API bit it uses a hard-coded axes mapping for each controller model. Thus, when you run the
above commands, the API will be confused and now shows the problem you initially tried to fix. To use the Chrome
gamepad API, you’d need to revert that settings. There is currently no known work-around.
Debugging
If you are asked to send debug info or want to fix bugs, follow the guide
displayed when opening a new bug report.
This has all the hints to get you started with debugging. You may also want
to increase the kernel debug level if your distribution sets it very low.
Otherwise, the driver reports most incidents, quirks, and fixes to dmesg.
Environment
Useful information can now be aquired with the commands:
dmesg: I advise you to rundmesg -wdHin a terminal while you connect your controller from a second terminal to get hardware information in realtime.modinfo hid_xpadneo: get information on xpadneo as a kernel module.- When your gamepad is connected, get the HID report descriptor:
xxd -c20 -g1 /sys/module/hid_xpadneo/drivers/hid:xpadneo/0005:045E:*/report_descriptor | tee >(cksum)
Generated Events
If you are asked to supply the events generated by xpadneo, please run the following command:
perl -0777 -l -ne 'print "/dev/input/$1\n" if /Name="Xbox Wireless Controller".*Handlers.*(event[0-9]+)/s' /proc/bus/input/devices | xargs evtest
Do whatever you think does not behave correctly (e.g. move the sticks from left to right if you think the range is wrong) and upload the output.
HID device descriptor (including checksum)
If we ask you to supply the device descriptor, please post the output of the following command:
xxd -c20 -g1 /sys/module/hid_xpadneo/drivers/hid:xpadneo/0005:045E:*/report_descriptor | tee >(cksum)
Bluetooth Connection
Some debugging needs a deeper low level look. You can do this by running btmon:
sudo btmon | tee xpadneo-btmon.txt
Then reproduce the problem you are observing.
We probably also need some information about the dongle:
- Run
lsusband pick the device number of your dongle. - Run
lsusb -v -s## | tee xpadneo-lsusb.txtwhere##is the device number picked in the previous step.
Working with Secure Boot
Secure Boot is a verification mechanism used when your computer loads your operating system. The boot process of a Linux distribution usually goes like this: UEFI -> UEFI Shim loader -> your distribution. Now back to our two options: disabling Secure Boot or signing xpadneo with your own key.
Disabling Secure Boot
In order for Secure Boot to be active, it must be enabled both at the UEFI level and at the shim level. Which means you should be able to disable Secure Boot:
- either in your firmware options. You can usually access them by pressing F1, F2 or F12 justa after turning on the computer.
- or in the shim. Run
sudo mokutil --disable-validation, and choose a password. Reboot your computer. You will be asked if you really want to disable Secure Boot. PressYesand enter the password. You can now safely forget the password.
After choosing either of these two options, Secure Boot should be disabled. You may therefore try to connect your Xbox One gamepad.
Signing xpadneo with your own keys
If you do not wish to disable Secure Boot, you will need to get the Shim to trust xpadneo. The process goes this way:
- generate a cryptographic key pair: a private key and a public key
- sign the module with your private key
- get the shim to trust your public key
Xpadneo will need to be re-signed every time it is updated, and every time the kernel is updated. To simplify this process, we provide scripts which will help you generate your keys and automatically sign xpadneo when needed.
cd xpadneo
# Xpadneo will be signed each time it is installed, you should therefore uninstall it now if needed!
sudo ./uninstall.sh
# Copy a directory containing three helper scripts in the /root directory
sudo cp -r misc/module-signing /root
# Generate the keys and ask the shim to trust them.
# They will be saved as /root/module-signing/MOK.der (public key) and /root/module-signing/MOK.priv (private key)
# You will be asked to choose a password. This password will only be needed one time, just after the reboot.
sudo /root/module-signing/one-time-setup
# READ THIS BEFORE REBOOTING:
# Just after rebooting, you will be prompted to press a key to enter the Shim. Press any key, then select the
# `Enroll key` option. You will get a chance to review the key that you are about to trust. To accept the key, select
# Yes then enter the password you chose previously.
# /!\ WARNING: The keyboard layout used to type the password will be QWERTY, no matter what keyboard you use.
# Choose `Continue` to boot into your operating system.
# Your public key is now trusted by the shim.
# Ask DKMS to sign Xpadneo when needed.
echo "POST_BUILD=../../../../../../root/module-signing/dkms-sign-module" | sudo tee "/etc/dkms/hid_xpadneo"
# Go back to the xpadneo folder and install the module. It will be signed automatically.
cd xpadneo
sudo ./install.sh
Notes:
-
if in the future you wish to remove your public key from the shim, run
sudo mokutil --delete "/root/module-signing/MOK.der"Reboot, and follow the procedure.
-
using theses scripts, your private key will be kept unencrypted in the
/rootdirectory. This may pose a security risk. If you wish to password protect your private keys, use these scripts, written by dop3j0e. Be warned that you will be asked for your password every time the kernel gets an update.
Third party Bugs
While developing this driver we recognized some bugs in KDE and linux itself, some of which are fixed now - others are not:
- Broken Battery Indicator in KDE fixed! https://www.kde.org/announcements/kde-frameworks-5.45.0.php
- L2CAP Layer does not handle ERTM requests
- workaround: disable ERTM
- unofficially fixed: see kernel_patches folder
- Binding of specialized drivers
- before kernel 4.16
- official way: Add driver to
hid_have_special_driveran recompilation of HIDcore - workaround: UDEV rule (see
src/etc-udev-rules.d)
- official way: Add driver to
- official way as from kernel 4.16: Specialized drivers are bound to the device automatically
- before kernel 4.16
- Cambridge Silicon Radio (CSR) chipsets do have problems while reconnecting (OUI 00:1A:7D)
- Qualcomm chipsets may have performance and lag problems (OUI 9C:B6:D0)
- Some Bluetooth dongles may need additional firmware for proper operation
- Possible solution: try installing
linux-firmwarefrom your distribution
- Possible solution: try installing
SDL Mapping
We fixed the following problem by pretending we are in Windows wireless mode
by faking the input device PID to 0x02E0. The original PID 0x02FD
triggeres several unwanted fixups at multiple layers, i.e. SDL or the HTML5
game controller API. The following paragraphs document the originally
wrong behaviour observed and we clearly don’t want our fixed mappings to be
“fixed” again by layers detected a seemingly wrong button mapping:
Since after libSDL2 2.0.8, SDL contains a fix for the wrong mapping introduced by the generic hid driver. Thus, you may experience wrong button mappings again.
Also, Wine since version 3.3 supports using SDL for xinput*.dll, and with
version 3.4 it includes a patch to detect the Xbox One S controller. Games
running in Wine and using xinput may thus also see wrong mappings.
The Steam client includes a correction for SDL based games since some version, not depending on the SDL version. It provides a custom SDL mapping the same way we are describing here.
To fix this and have both SDL-based software and software using the legacy joystick interface using correct button mapping, you need to export an environment variable which then overrides default behavior:
export SDL_GAMECONTROLLERCONFIG="\
050000005e040000fd02000003090000,Xbox One Wireless Controller,\
a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,\
guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,\
rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,\
start:b7,x:b2,y:b3,"
You need to set this before starting the software. To apply it globally, put this line into your logon scripts.
The id 050000005e040000fd02000003090000 is crafted from your device
id as four 32-bit words. It is, in LSB order, the bus number 5, the
vendor id 045e, the device id 02fd, and the interface version
or serial 0903 which is not a running number but firmware dependent.
This version number is not the same as shown in dmesg as the fourth
component.
You can find the values by looking at dmesg when xpadneo detects
your device. In dmesg, find the device path, then change to the
device path below /sys and look for the files in the id directory.
The name value after the id is purely cosmetical, you can name it whatever you like. It may show up in games as a visual identifier.
If running Wine games, to properly support xpadneo, ensure you have
removed any previous xinput hacks (which includes redirecting
xinput*.dll to native and placing a hacked xinput dll in the
game directory. Also ensure your Wine built comes with SDL support
compiled in.
If you do not want to apply this setting globally, you can instead
put the SDL mapping inside Steam config.vdf. You can find this
file in $STEAM_BASE/config/config.vdf. Find the line containing
"SDL_GamepadBind" and adjust or add your own controller (see
above). Ensure correct quoting, and Steam is not running
while editing the file. This may not work for Steam in Wine
because the Wine SDL layer comes first, you still need to export
the variable before running Wine. An example with multiple
controllers looks like this:
"SDL_GamepadBind" "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,
030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,
050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"
An alternative store location of user-defined mappings can be found here:
$HOME/.local/share/gamecontrollerdb.local.txt