udev: PCI bridges as parents, USB interfaces, the controller's own address, and the attributes lsusb reads
PCI devices now nest under the bridge they sit behind (from each bridge's secondary..subordinate window), so a controller behind a root port is where Linux would put it. USB interfaces (1-5:1.0) are directories with class, number, a driver link and a uevent with INTERFACE= and a MODALIAS, announced after the drivers have been offered the device and removed before it. The xHCI driver tells the USB core its PCI address when it comes up, replacing the guess that bus N was the Nth controller. Devices and root hubs carry version, bMaxPacketSize0, bNumInterfaces, bmAttributes and the rest; lsusb -t from Alpine's usbutils now draws the tree. Checked on q35 with an xHCI behind a pcie-root-port and a USB keyboard on each controller. Plain lsusb still fails: libusb wants usbfs, and refuses a kernel that calls itself 0.1.0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
parent
2aef583aad
commit
d650ff433b
6 changed files with 461 additions and 42 deletions
|
|
@ -39,13 +39,22 @@ kernel announce the device again. PCI and USB devices announce the same way:
|
|||
`MODALIAS`, `PCI_ID`, `PCI_CLASS`, `PCI_SLOT_NAME` for a PCI device, `PRODUCT`,
|
||||
`TYPE`, `BUSNUM`, `DEVNUM` for a USB one.
|
||||
|
||||
**PCI devices** are flat under `pci0000:00` however the bridges are wired: the
|
||||
kernel keeps no bridge tree, so a device behind a bridge is not nested inside
|
||||
it. **USB devices** sit under the xHCI controller that carries their bus, below
|
||||
that bus's root hub `usbN`; a hub's children are its siblings, not its
|
||||
children. The bus-to-controller mapping is a convention (bus N is the Nth xHCI
|
||||
in PCI order), since the USB core numbers a bus without recording which
|
||||
controller it came from.
|
||||
**PCI devices** are nested under the PCI-to-PCI bridge they sit behind: a
|
||||
device's parent is the bridge whose secondary..subordinate bus range holds its
|
||||
bus (the innermost if several do), read from the bridge's config space, so an
|
||||
xHCI behind a root port is `pci0000:00/0000:00:04.0/0000:01:00.0`. **USB
|
||||
devices** sit under the xHCI controller that carries their bus, below that
|
||||
bus's root hub `usbN`; the controller tells the USB core its own PCI address
|
||||
when it comes up, so the link is recorded, not guessed. A hub's children are
|
||||
its siblings, not its children.
|
||||
|
||||
**USB interfaces** (`1-5:1.0`) are directories below their device, with
|
||||
`bInterfaceClass`, `bInterfaceNumber`, a `driver` link when one is bound, and a
|
||||
`uevent` carrying `DEVTYPE=usb_interface`, `INTERFACE=` and a `MODALIAS=usb:...`
|
||||
that names the interface's class. They are announced after the drivers have
|
||||
been offered the device, so the event says which interface was taken, and
|
||||
removed before the device. Devices also carry what `lsusb -t` and libusb read:
|
||||
`version`, `bMaxPacketSize0`, `bNumInterfaces`, `bmAttributes`, `bMaxPower`.
|
||||
|
||||
**Hot-plug is real**: the USB core announces `add` when a device is attached
|
||||
and `remove` as it detaches, and `usbN` is announced when its controller comes
|
||||
|
|
@ -108,9 +117,13 @@ Getting there found two kernel bugs, both in descriptor passing:
|
|||
|
||||
## What is not there
|
||||
|
||||
- USB interfaces (`1-3:1.0`), `/dev/bus/usb` nodes, and PCI bridges as parents.
|
||||
A USB keyboard works because every keyboard is `event0`; udev now knows the
|
||||
device arrived but not which interface became the keyboard.
|
||||
- `/dev/bus/usb` nodes (usbfs). `lsusb -t` works because it reads sysfs; plain
|
||||
`lsusb` goes through libusb, which also refuses to start while `uname -r`
|
||||
says `0.1.0` (it wants Linux 2.6.32 or newer) and wants usbfs to open devices.
|
||||
- A hub's port count (`maxchild` reads 0), and string descriptors
|
||||
(`manufacturer`, `product`, `serial`).
|
||||
- A USB keyboard works because every keyboard is `event0`; udev knows the
|
||||
interface arrived but the input device does not hang below it.
|
||||
- `hwdb` (`/etc/udev/hwdb.bin`): `udevadm hwdb --update` has not been run in the
|
||||
image, so `60-input-id` logs "returned non-zero" for the hwdb import. The
|
||||
properties that matter come from `input_id`.
|
||||
|
|
|
|||
Loading…
Reference in a new issue