Skip to the content.


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).

Build Status Average time to resolve an issue Packaging status Discord

Advanced Linux Driver for Xbox One Wireless Gamepad

xpadneo Logo

Quote from @atar-axis (Florian Dollinger), creator of the initial driver:

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

These other projects may not support some of the advanced features of xpadneo.

Breaking Changes

Kernel 4.18 or newer required

As of xpadneo v0.10, we require kernel 4.18 or later to utilize HID_QUIRK_INPUT_PER_APP which splits the gamepad into multiple sub-devices to fix problems and incompatibilities at several layers.

SDL2 2.28 Compatibility

Thanks to @slouken from SDL2, xpadneo mappings are now auto-detected in the upcoming SDL2 2.28 release. This will fix long-standing problems with Steam Input and SDL2 games. With this release, we will also have full paddle support.

If you still see problems, ensure that you didn’t create custom controllerdb entries. See also:

Known issues:

Quirks by Design

With BLE firmware, all models switched to a unified HID report descriptor, only the XBE2 controller identifies with PID 0x0B22 while the other models identify with PID 0x0B13. This has some known consequences:

Advantages of this Driver

Unavailable Features

Across all models, xpadneo won’t support audio features of the controllers because the firmware doesn’t support audio in Bluetooth mode. In the future, xpadneo may support audio when USB and dongle support will be added.

Xbox One S Wireless Controller

This is the initial controller supported from the first version of xpadneo. All features are fully supported. This controller uses emulated profile switching support (see below).

Xbox Elite Series 2 Wireless Controller

Basic support for the Xbox Elite Series 2 Wireless controller is present, covering all the features of the driver. The following features are missing:

This controller uses native profile switching support (see below).

Xbox Series X|S Wireless Controller

Full support for the Xbox Series X|S controller is present including the share button. This is currently statically mapped to keyboard event KEY_F12 to take screenshots with Steam. It will be configurable in the future. This controller uses emulated profile switching support (see below).

This controller uses BLE (Bluetooth low energy) and can only be supported if your Bluetooth dongle also supports BLE.

Known problems: The controller may not properly set its connection parameters, resulting in laggy and choppy input experience. See also: Troubleshooting.

8BitDo Controllers

This driver supports the Nintendo layout of those controllers to 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. However, this feature is not enabled by default. If you want to use this feature, you have to add a quirk flag to the module options:

# /etc/modprobe.conf
options hid_xpadneo quirks=E4:17:D8:xx:xx:xx+32

where you replace xx:xx:xx with the values from your controller MAC (as shown in dmesg). The value 32 enables Nintendo layout. If you’ll want to add other quirk flags, simply add the values, e.g. 32 + 7 (default quirks for 8BitDo) = 39. After changing this, reload the driver or reboot.

This controller uses emulated profile switching support (see below).

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.

GuliKit KingKong Controller Family

This driver supports the GuliKit King Kong controller family, the driver was tested with model NS09 (using firmware v2.0) and NS39 (aka KK3 MAX, firmware v3.6) but should work just fine for the older models, too. If in doubt, follow the firmware upgrade guides on the GuliKit home page to receive the latest firmware. Both the Android mode and the X-Input mode are supported but it may depend on your Bluetooth stack which mode works better for you (Android mode didn’t pair for me).

This driver supports the Nintendo layout of those controllers to 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. However, this feature is not enabled by default. If you want to use this feature, you have to add a quirk flag to the module options:

# /etc/modprobe.conf
options hid_xpadneo quirks=98:B6:EA:xx:xx:xx+32

where you replace xx:xx:xx with the values from your controller MAC (as shown in dmesg). The value 32 enables Nintendo layout. If you’ll want to add other quirk flags, simply add the values, e.g. 32 + 131 (default quirks for GuliKit) = 163. After changing this, reload the driver or reboot.

However, alternatively the controller supports swapping the buttons on the fly, too: Just press and hold the settings button, the click the plus button. Thus, the quirks flag is just a matter of setting the defaults.

This controller uses emulated profile switching support (see below).

GameSir T4 Cyclone Family

This driver supports the GameSir T4 Cyclone controller family, tested by the community. The Pro-models also support trigger rumble but since we cannot distinguish both models by the Bluetooth MAC OUI, we simply enable the trigger rumble protocol for both variants. This should not introduce any problems but if it does, and your model does not have trigger rumble support, you can explicitly tell the driver to not use the trigger rumble motors by adding a quirk flag:

# /etc/modprobe.conf
options hid_xpadneo quirks=A0:5A:5D:xx:xx:xx+2

This controller uses emulated profile switching support (see below).

Profile Switching

The driver supports switching between different profiles, either through emulation or by using the hardware switch that comes with some models. This switching can be done at any time even while in a game. The API for customizing each profile does not exist yet.

Native Profile Switching Support

The driver support native profile switching for the Xbox Elite Series 2 controller. However, the feature is not finalized yet:

Emulated Profile Switching Support

The driver emulates profile switching for controllers without a hardware profile switch by pressing buttons A, B, X, or Y while holding down the Xbox logo button. However, the following caveats apply:

Important: Emulated profile switching won’t work if you disabled the shift-mode of the Xbox logo button (module parameter disable_shift_mode).

Getting Started

Distribution Packages

If your distribution has a maintained package, you can just use that and do not need to follow the manual install instructions below:

Packaging status

Notes for Package Maintainers

To properly support module signing and UEFI secure boot, openssl and mokutil are required additionally to the prerequisites below. The DKMS readme has more instructions.


Make sure you have installed dkms, linux headers and a bluetooth implementation (e.g. bluez) and their dependencies.

Kernel maintainers should also include the uhid module (CONFIG_UHID) because otherwise Bluetooth LE devices (all models with firmware 5.x or higher) cannot create the HID input device which is handled in user-space by the bluez daemon.

Please feel free to add other distributions as well!



You know that everything works fine when you feel the gamepad rumble ;)



In order to update xpadneo, do the following


Further Information

For further information please visit the GitHub Page 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

Bluetooth Low Energy

Some newer controller may work in Bluetooth low energy mode (BLE). One of those controllers is the XBOX Series X|S controller.

If your distribution supports the command, run btmgmt info and look for le in supported and current settings, example:

# btmgmt info
Index list with 1 item
hci0:   Primary controller
        addr 00:1A:7D:XX:XX:XX version 6 manufacturer 10 class 0x100104
        supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr hs le advertising secure-conn debug-keys privacy static-addr phy-configuration
        current settings: powered ssp br/edr le secure-conn
        name jupiter
        short name

Cambridge Silicon Radio






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:

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:


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


Gamepad Does Not Connect Properly

High Latency or Lost Button Events with Bluetooth LE

Affected models: Xbox controllers using Bluetooth LE (Xbox Series X|S or later)

While using new Xbox Series X|S controller, you may experience laggy or choppy input, also button presses may be lost or delayed. This problem only affects Bluetooth LE controllers, the older models are not affected by these settings even if you think you may see such a problem.

A proper solution is still missing but we isolated it to the Bluetooth LE connection parameters for latency and intervals. The bluez developers say that the connected device should suggest the best settings, the bluez daemon only ships sensible default settings. It looks like the new Xbox controllers do not properly suggest their preferred connection parameters, some BLE mice show the same problem. You can work around it by changing the bluez defaults instead. This change is not recommended by the bluez developers but as long as you only use a very specific set of BLE devices, this change should be fine.

The controller uses 100 Hz internally for its protocol, so we decided to use intervals of 8.75..11.25ms. Each tick is 1.25ms, so we end up with MinConnectionInterval=7 and MaxConnectionInterval=9. If you already use a similar work-around for other devices, you may need to adjust your settings to the proper bounds, i.e. do not increase the min value, do not lower the max value.

Edit the following file and restart the Bluetooth service or reboot:

# /etc/bluetooth/main.conf


Incompatible Bluetooth Chipset

Some chipsets, e.g. the CSR 85xx or Intel AX200 (and variants like 3xxx), 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.

See below, if this happens since a firmware upgrade of the controller.

Gamepad Connects and Immediately Disconnects since Firmware Upgrade

After upgrading the controller firmware, it is essential to fully remove/forget the device from your Bluetooth device list, then reboot to ensure a clean state, then re-pair the controller.


Gamepad Asks for a PIN During Pairing

A user found that with genuine Xbox controllers, the fix is often to use an external USB dongle instead of the internal chipset for pairing the controller (recommended to try first).

If it still asks for a PIN, try 0000 to connect the controller. It should happen just once.

Some third-party controllers and clones will still show the issue on later connects. The issue should be reported to the Bluez project to fix it, we only provide a work-around here.

To work around the issue, this solution was found. It may affect other devices and reduces security, use at your own risk:

# /etc/bluetooth/input.conf



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. Your kernel may also be missing the uhid module which is needed by all Bluetooth LE devices for input capabilities because the bluez daemon will handle HID data in user-space. Most distributions include uhid but if in doubt, ask your distribution kernel maintainers.

Check the output of zgrep UHID /proc/config.gz to check whether your kernel has uhid support. This is only required for Xbox controllers with firmware 5.x or higher.

Check the output of the dmesg command to see whether xpadneo was loaded and logged your gamepad.

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 Does not Connect at All, Runs A Reconnect Loop, or Immediately Disconnects

Check whether ERTM was disabled (see above). Also, some newer models use a different Bluetooth protocol “Bluetooth low energe” (BLE) which you may accidentally have disabled. Check the following settings in /etc/bluetooth/main.conf:

ControllerMode = dual
JustWorksRepairing = confirm

Xbox Wireless Controller

The newest wireless controllers from Microsoft (Xbox One and Xbox Series X|S) are known to cause a reconnect loop and not pairing with Bluez. There are some specific workarounds:

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.


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.


Useful information can now be aquired with the commands:

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:

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:

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:

  050000005e040000fd02000003090000,Xbox One Wireless Controller,\

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: