Skip to content

Device Access on Linux

codingncaffeine edited this page Sep 8, 2026 · 1 revision

Device Access on Linux

By default the panel's hidraw node is root:root 0600, so nothing can open it unprivileged. The fix is one udev rule — and one detail about that rule which is extremely easy to get wrong.

The rule

# /etc/udev/rules.d/70-icue-nexus.rules
KERNEL=="hidraw*", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="1b8e", TAG+="uaccess"
sudo udevadm control --reload-rules
sudo udevadm trigger --action=add --subsystem-match=hidraw

The packages install this for you and reload udev in their post-install step. If the panel was already plugged in when you installed, replug it or reboot so the ACL is actually applied.

⛔ The rule must sort below 73

This is the trap. A rule numbered 99- looks perfectly correct, applies the tag without error, and grants nothing at all.

TAG+="uaccess" is not itself a permission. It is a marker consumed by /usr/lib/udev/rules.d/73-seat-late.rules, which is what actually calls RUN{builtin}+="uaccess" and writes the ACL. udev evaluates rule files in lexical order, so a rule numbered above 73 applies its tag after the consumer has already run. The tag is present; nobody ever looks at it again.

Number it 70.

The tag being present is not evidence

The failure mode is nasty because every intermediate check passes:

udevadm info /dev/hidrawN | grep TAGS      # shows uaccess — proves nothing

The only thing that settles it is the ACL itself:

getfacl /dev/hidrawN                       # look for user:<you>:rw-
ls -l  /dev/hidrawN                        # crw-rw----+ — the + is the ACL

If there is no + and no user: entry, the rule ran and granted nothing.

Why uaccess rather than MODE="0666"

uaccess grants an ACL to the active local seat's user only, and revokes it when they log out. MODE="0666" grants the device to every process on the machine, permanently. For a device that is a display on your keyboard the difference is small in practice, but there is no reason to take the wider option.

Finding the right node

Two hidraw nodes appear for this device and only one is real (see Reverse Engineering the NEXUS). To identify them:

for h in /sys/class/hidraw/hidraw*; do
    echo "$(basename "$h")  $(grep HID_ID "$h/device/uevent")"
done | grep -i 1B8E

Interface 0 is the one with the vendor usage page. Opening interface 1 succeeds and then does nothing, which is a confusing way to spend an afternoon.

Only one writer at a time

Two processes writing the same hidraw node do not get an error. HID output reports from two handles simply interleave, and the panel flickers between two different pictures. Nothing fails, nothing is logged.

Anything that owns this device needs a single-instance guard, decided before the device is opened. This project arbitrates with an exclusive FileShare.None lock file — flock() under the hood — because that is atomic against two simultaneous launches in a way that checking for a pid file or a socket is not, and because the kernel releases it however the process dies, so a crash cannot leave the application permanently unstartable.

A second launch then talks to the first over a Unix socket and asks it to raise its window, which is what the user wanted by launching again in the first place. One caveat learned the hard way: a bound socket whose owner has stopped accepting still lets connect and send succeed, so "sent" is not evidence of anything. Wait for the holder to acknowledge.

Clone this wiki locally