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
87 lines
3.9 KiB
C
87 lines
3.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#pragma once
|
|
|
|
// What the firmware and the buses said about this machine, kept so /sys can
|
|
// say it again. kernel/fs/sysfs.c is the reader; each producer is named
|
|
// beside its part.
|
|
//
|
|
// Read-only views, copied out under whatever lock the producer has, so a
|
|
// caller never holds a pointer into a table that may change under it.
|
|
|
|
// --- the memory map, as the loader handed it over (kernel/arch/x86_64/e820.c)
|
|
struct e820_rec {
|
|
uint64 base, len;
|
|
uint32 type; // E820: 1 RAM, 2 reserved, 3 ACPI, 4 NVS, 5 bad
|
|
};
|
|
int e820_nth(int i, struct e820_rec *out); // 0, or -1 past the end
|
|
// The RAM the page allocator was given, in bytes: MemTotal and sysinfo's
|
|
// totalram. Not PHYSTOP, which is an address and counts the PCI hole.
|
|
uint64 ram_total_bytes(void);
|
|
|
|
// --- ACPI tables (kernel/arch/x86_64/acpi.c)
|
|
//
|
|
// Every table the RSDT or XSDT lists, then the DSDT and FACS, which only the
|
|
// FADT points at. `sig` gets four characters, no terminator. 0 for a table,
|
|
// 1 for an empty slot (keep counting), -1 past the end.
|
|
int acpi_table_nth(int i, uint64 *pa, uint32 *len, char sig[4]);
|
|
|
|
// --- SMBIOS (kernel/dev/dmi.c)
|
|
void dmi_init(void);
|
|
// The entry point structure and the table it describes, both physical.
|
|
int dmi_entry(uint64 *pa, uint32 *len);
|
|
int dmi_table(uint64 *pa, uint32 *len);
|
|
// Bytes of physical memory, through the direct map or ioremap. 0 on failure.
|
|
void *phys_view(uint64 pa, uint64 len);
|
|
|
|
// The strings Linux publishes in /sys/class/dmi/id, under its names. Serial
|
|
// numbers and the UUID are left out on purpose: nothing here needs them, and a
|
|
// hardware report is meant to be handed to somebody else.
|
|
enum {
|
|
DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_BIOS_DATE, DMI_BIOS_RELEASE,
|
|
DMI_SYS_VENDOR, DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_PRODUCT_SKU,
|
|
DMI_PRODUCT_FAMILY,
|
|
DMI_BOARD_VENDOR, DMI_BOARD_NAME, DMI_BOARD_VERSION,
|
|
DMI_CHASSIS_VENDOR, DMI_CHASSIS_TYPE, DMI_CHASSIS_VERSION,
|
|
DMI_NFIELDS
|
|
};
|
|
extern const char *const dmi_field_names[DMI_NFIELDS];
|
|
// Length written (no terminator counted), or -1 if the machine does not say.
|
|
int dmi_field(int f, char *out, int cap);
|
|
|
|
// 1 if the UEFI loader booted this kernel.
|
|
int boot_is_efi(void);
|
|
|
|
// --- USB devices (kernel/drivers/usb/core/usb.c), one per addressed device
|
|
struct usb_info {
|
|
int bus, devnum, speed; // speed: USB_SPEED_*
|
|
uint16 vid, pid, bcd;
|
|
uint8 cls, subcls, proto; // the device descriptor's
|
|
uint8 nconf;
|
|
uint16 bcdusb; // the version the device speaks
|
|
uint8 maxp0; // bMaxPacketSize0
|
|
uint8 nif, confval, attrs; // the configuration descriptor's
|
|
uint16 maxpower; // in mA
|
|
char path[24]; // Linux's name: "1-3", "2-1.4"
|
|
char driver[16]; // the first interface's, or empty
|
|
};
|
|
int usb_info_nth(int i, struct usb_info *out);
|
|
// How many USB buses have shown a device so far; bus numbers run 1..this.
|
|
int usb_nbuses(void);
|
|
// Tell /sys and udev a USB device appeared ("add") or is about to go ("remove").
|
|
void sysfs_usb_uevent(const struct usb_info *u, const char *action);
|
|
void sysfs_usb_root_uevent(int bus, const char *action);
|
|
// A USB controller is up, at this PCI address; number its bus and announce its
|
|
// root hub.
|
|
void usb_bus_add(void *hc, int pci_bus, int pci_slot, int pci_func);
|
|
// The PCI address of the controller behind bus number `bus`; 0, or -1 if none.
|
|
int usb_bus_pci(int bus, int *pci_bus, int *pci_slot, int *pci_func);
|
|
|
|
// One interface of a configured USB device, in the order the configuration
|
|
// descriptor lists them (alternate setting 0 only).
|
|
struct usb_if_info {
|
|
uint8 num, cls, subcls, proto, nendp;
|
|
char driver[16]; // what is bound to it, or empty
|
|
};
|
|
int usb_if_nth(int bus, int devnum, int n, struct usb_if_info *out);
|
|
void sysfs_usb_if_uevent(const struct usb_info *u, const struct usb_if_info *i,
|
|
const char *action);
|