USB Hotpluging and Wireless Xbox 360 Controller

I am having a very difficult time resolving this issue and hoping to get some help. The USB Incus/Lxd hot plugging device I believe works great as far as I can tell. I think I have narrowed down the problem based on cat of /proc/bus/input/devices which I did after installing steam natively in debian 12. You can see that my Xbox controller gets a physical and virtual xbox controller on the native install. However, in my container I am only getting the physical device. Without the virtual device, the controller is not being recognized in games.

It looks like Steam has some custom udev rules that may be needed to create the virtual device 28de Product (see below). I have been mainly been using the unix-hotplug and uinput devices (see below). I have also played around with adding hidraw0, hidraw1 and hidraw2 devices, but nothing seems to work.

What is needed to create the virtual device in my container? Do I somehow need to incorporate the udev rules into my container?

Thanks. I very much appreciate your support.

************************************** Container Config files I added
gid: “1000”
mode: “0777”
productid: “0719”
type: unix-hotplug
uid: “1000”
vendorid: 045e

gid: “1000”
mode: “0777”
path: /dev/uinput
type: unix-char
uid: “1000”

**********************************Steam Custom Udev rules related to Product 28DE

This rule is necessary for gamepad emulation; make sure you replace ‘pgriffais’ with a group that the user that runs Steam belongs to

KERNEL==“uinput”, MODE=“0660”, GROUP=“pgriffais”, OPTIONS+=“static_node=uinput”

Valve HID devices over USB hidraw

KERNEL==“hidraw*”, ATTRS{idVendor}==“28de”, MODE=“0666”

Valve HID devices over bluetooth hidraw

KERNEL==“hidraw*”, KERNELS==“28DE:”, MODE=“0666”

***********************************cat /proc/bus/input/devices from native install on Steam on host

: Bus=0003 Vendor=045e Product=02a1 Version=0100
N: Name=“Xbox 360 Wireless Receiver”
P: Phys=usb-0000:00:14.0-7/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/input/input14
U: Uniq=
H: Handlers=event14 js0
B: EV=20000b
B: KEY=f 0 0 0 0 0 0 7cdb000000000000 0 0 0 0
B: ABS=3003f
B: FF=107030000 0

I: Bus=0003 Vendor=28de Product=11ff Version=0001
N: Name=“Microsoft X-Box 360 pad 0”
P: Phys=
S: Sysfs=/devices/virtual/input/input16
U: Uniq=
H: Handlers=event15 js1
B: EV=20000b
B: KEY=7cdb000000000000 0 0 0 0
B: ABS=3003f

I have done more testing and it looks like the Steam Client is responsible for creating a virtual controller from the physical device (JS0 and event*). After the Steam Client is started, I see a new device under /dev/input call Js1 and a new event*. The problem is in the container I only see the virtual event (in the this case event17). While I see the Js1 device on the host, I do not see it in the container. However, it looks like Steam has already been configured to use the physical device under Js0 and the physical event. I believe this is causing my controller issues in games. I believe Steam relies heavily on the virtual device.

Anyway to config LXC to see the virtual device (Js1 and event*) when the Steam client is started?

Anyway to just mount the entire /dev/input into the container so the host and container will always be in sync?


You could try passing /dev/input over, though by default the cgroup configuration will prevent access to the individual devices so you’ll need to use raw.lxc: lxc.cgroup.devices.allow entries to get around that.

Thanks Stephane for your reply as I know you must be busy with Incus. I think the whole topic of device management is a lot more complex then I imaged and has gotten a lot of discussion in the flatpak github.

Apparently there is not one standard for accessing game controllers and that is why in many instances it looks like flathub users grant the permission to: devices=all to the steam container. I believe this give entire access to /dev. I believe the key things Steam needs access to are:

/dev/hidraw*, /dev/uinput and /dev/input and not sure about /dev/bus/usb…

I believe I gave access to hidraw0, hidraw1, hidraw2 (using unix-char device) and gave access to /dev/uinput (using unix-char device) and gave access to /dev/input (using hot-plugin).

I did run python in the container and was able to create a virtual device in /dev/input using the evdev API.

I am not sure if giving full access to the host’s /dev/input folder using raw/lxc instead of using the lxc hotplug device would help.

Maybe a better approach at least for testing would be to give full access to /dev which I assume would be the same as flatpak devices=all.

Is there a way to give full access to /dev with raw.Lxc?

At least I could test if that resolves the issue with Steam being able to create a virtual device.

Thanks for your time.

Possibly, you’d need to add a disk device for /dev on the host to /mnt/dev or something in the instance. You’d then need a raw.lxc entry for lxc.cgroup2.devices.allow or similar so it can allow write to the device types you want (or all of them).

Allowing all of /dev is naturally extremely risky as that would also allow the container to directly write to any of your disks for example.

Stephane- I still have not given up yet and appreciate your responses. The last two posts, I wanted to give access to all /dev or /dev/input.

It seems /dev/input would be easier to give a try. I have done the following:

  1. removed all the usb/hotplug devices from the container which results no /dev/input node in the container.

  2. Added a disk device: lxc config device add steam myinput disk source=/dev/input path=/dev/input
    Is this the same as using a raw.lxc bind mount command which I have seen some examples? I just want to make sure I do not need a raw.lxc bind mount command here.

In the container I can see the folder /dev/input and it is owned by root/input which is the same as the host.

  1. I tried to give it access to all devices using:

lxc config set steam raw.lxc=“lxc.cgroup.devices.allow = c : m” (I typed asterisk:asterisk but not showing correctly)

also tried

lxc config set steam raw.lxc=“lxc.cgroup.devices.allow = c : rwm” (I typed asterisk:asterisk, but not showing correctly)

I know this does not work because in the container the /dev/input/evtest command does not find any devices.

Most of the online examples I could find were for a device nodes and not an entire directory.

How should the command be structured? Do I need to add/edit anything in the common.conf file


CGroup whitelist

lxc.cgroup.devices.deny = a

Allow any mknod (but not reading/writing the node)

lxc.cgroup.devices.allow = c : m (I typed :, but not showing asterisk:asterisk, but not showing correctly)
lxc.cgroup.devices.allow = b : m (I typed :, but not showing asterisk:asterisk, but not showing correctly)