Plug-and-Play HOWTO: devices, drivers, udev and firmware on Linux
On a current Linux system, plug-and-play just happens: the kernel finds the device, udev loads the matching driver module, the driver loads its firmware, and a device node appears. This page explains that chain and shows how to inspect it, change a driver's options, stop a driver from loading, and write your own udev rule.
The classic Plug-and-Play-HOWTO (last revised in 2007) is kept by the Linux Documentation Project at tldp.org. It deals with ISA cards, isapnp and hand-assigned IRQs and I/O addresses. On PCI Express, USB and ACPI hardware, the firmware and the kernel assign those resources, and you almost never touch them.
From plug-in to working device
- A bus driver (PCI, USB, ACPI, platform) detects the device and the kernel sends a uevent. Most uevents carry a
MODALIASstring built from the device's IDs, for examplepci:v00008086d...orusb:v0BDAp8153.... - systemd-udevd receives the event and runs its rules. One of the default rules (
80-drivers.rules) says: if the event has a MODALIAS, run the built-inkmod load. kmod looks the alias up in the index thatdepmodbuilt from each module's ID table, and loads the match. - The driver probes the device and binds to it. Many drivers then request a firmware file.
- Other udev rules create the device node in
/dev, set its owner, group and mode, and add stable symlinks such as/dev/disk/by-id/and/dev/serial/by-id/.
The same happens at boot: udev replays ("triggers") events for every device that already exists.
See what is there and who drives it
lspci -nnk # PCI devices, [vendor:device] IDs, driver in use, possible modules
lsusb # USB devices
lsusb -t # USB tree, with the driver bound to each interface
lsmod # loaded modules and who uses them
modinfo e1000e # a module's file, firmware, parameters and aliases
cat /sys/bus/pci/devices/0000:00:1f.6/modalias
udevadm info /dev/sda # udev properties of a device
udevadm info --tree # sysfs tree (systemd 251 or later)
lspci -k shows "Kernel driver in use" and "Kernel modules" for each device. A device with modules listed but no driver in use is the usual sign of a failed probe or missing firmware; the kernel log says which:
sudo dmesg -w # watch live while you plug the device in
journalctl -k -b # this boot's kernel messages
To watch the events themselves, run udevadm monitor --kernel --udev --property and plug in the device. You see the kernel uevent, then the udev event after rules ran, with all properties.
Load, unload and configure modules
sudo modprobe btusb # load, with its dependencies
sudo modprobe -r btusb # unload (fails if in use)
modprobe -n -v btusb # dry run: show what would happen
modprobe --show-depends btusb
sudo modprobe dummy numdummies=2 # with a parameter, this time only
Use modprobe, not insmod: it resolves dependencies and applies the configuration files. To make a setting permanent, put it in a .conf file in /etc/modprobe.d/ (files there override files of the same name in /run/modprobe.d/ and /lib/modprobe.d/ or /usr/lib/modprobe.d/):
# /etc/modprobe.d/iwlwifi.conf
options iwlwifi power_save=1
The current values of a loaded module's parameters are under /sys/module/<name>/parameters/. If the module is loaded from the initramfs (storage and early graphics drivers often are), rebuild it after changing modprobe.d: sudo update-initramfs -u on Debian and Ubuntu, sudo dracut -f on Fedora and RHEL, sudo mkinitcpio -P on Arch.
Stop a driver from loading
# /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
install nouveau /bin/false
blacklist tells modprobe to ignore the module's aliases, which is what stops automatic loading by udev. It does not stop modprobe nouveau typed by hand, or loading as a dependency of another module. The install line closes that gap: modprobe runs the given command instead of loading the module, and /bin/false does nothing. Rebuild the initramfs afterwards. For a one-off test, the kernel parameter modprobe.blacklist=nouveau does the same for a single boot (see the BootPrompt HOWTO).
softdep lines handle the other common case, a module that must load before or after another: softdep mydriver pre: crc32c.
Write your own udev rule
Typical reasons: a stable name for one of several identical USB serial adapters, permissions for a device your user should access, or running a script on plug-in. Rules go in /etc/udev/rules.d/, must end in .rules, and are read in lexical order together with the packaged rules in /usr/lib/udev/rules.d/; a file in /etc overrides a packaged file of the same name.
First find attributes to match on. udevadm info -a walks up from the device through its parents and prints every attribute:
udevadm info -a /dev/ttyUSB0 | grep -E 'idVendor|idProduct|serial' | head
Then write the rule. Keys with == match, keys with = or += assign. ATTR matches the device itself, ATTRS may match any parent, but all ATTRS in one rule must come from the same parent:
# /etc/udev/rules.d/70-gps.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", ATTRS{serial}=="A1B2C3", SYMLINK+="gps0", GROUP="dialout", MODE="0660"
Use your own IDs and serial number; the ones above are only an example. Check, load and apply:
sudo udevadm verify /etc/udev/rules.d/70-gps.rules # systemd 254 or later
sudo udevadm control --reload
sudo udevadm trigger --action=add --subsystem-match=tty
ls -l /dev/gps0
Reloading alone does not change devices that are already present, hence the trigger (or unplug and replug). sudo udevadm test $(udevadm info -q path /dev/ttyUSB0) shows which rules match without changing anything.
No long-running programs in RUN. udev kills processes started by RUN{program} once event handling is over, and starting daemons from rules is not allowed. To start a service on plug-in, tag the device with TAG+="systemd", ENV{SYSTEMD_WANTS}="myservice.service" and let systemd run it.
Firmware
Many devices (Wi-Fi, Bluetooth, GPUs, some network cards) need a firmware file that the driver loads at probe time. The kernel looks in /lib/firmware/updates/<kernel version>/, /lib/firmware/updates/, /lib/firmware/<kernel version>/ and /lib/firmware/, in that order, plus any path given with the firmware_class.path= parameter. Kernels built with compression support also try the same name with .zst or .xz added. When a file is missing, the log says so:
sudo dmesg | grep -i firmware
# ... Direct firmware load for iwlwifi-....ucode failed with error -2
Error -2 means "file not found". Install your distribution's firmware package: linux-firmware on Fedora, RHEL, Arch and Ubuntu; on Debian the firmware-* packages from the non-free-firmware component (for example firmware-iwlwifi, firmware-realtek, firmware-amd-graphics). Then reload the driver or reboot. Device firmware that lives in flash on the device itself (docks, SSDs, system firmware) is a different thing, updated with fwupd; see the Hardware HOWTO.
What happened to IRQs and I/O ports?
They still exist, and you can look at them in /proc/interrupts, /proc/ioports and /proc/iomem. But on PCI Express devices, interrupts are mostly MSI or MSI-X messages rather than shared lines, and the firmware and kernel assign address ranges. Manual resource settings now matter only for old ISA hardware and some embedded boards; for talking to hardware registers from a program, see the I/O port programming mini-HOWTO.
Sources
- udev(7), man7.org
- udevadm(8), man7.org
- 80-drivers.rules (kmod load on MODALIAS), systemd
- modprobe(8), man7.org
- modprobe.d(5), man7.org
- lspci(8), man7.org
- Firmware search paths, Linux kernel documentation
- Firmware loader source (compressed firmware, error message), Linux kernel
- Plug-and-Play-HOWTO (classic), Linux Documentation Project