AxlUsb — USB device enumeration + descriptor reads
USB device enumeration via EFI_USB_IO_PROTOCOL.
Header: <axl/axl-usb.h>. Lazy on first call: AxlUsb walks the
firmware-installed USB I/O protocol handles, derives stable
(bus, addr, intf) ordinals from each handle’s device path, and
caches the result. On platforms without a USB stack (rare; some
constrained BMC firmware) every axl_usb_* call returns -1 / NULL
cleanly.
Cursor-style enumeration matches axl_pci_next and
axl_smbios_find_next:
AxlUsbAddr *u = NULL;
while ((u = axl_usb_next(u)) != NULL) {
uint16_t vid, pid;
if (axl_usb_get_vid_pid(*u, &vid, &pid) == 0) {
axl_printf("Bus %03u Device %03u If %u %04x:%04x\n",
u->bus, u->addr, u->intf, vid, pid);
}
}
axl_usb_next emits one entry per EFI_USB_IO_PROTOCOL handle —
i.e. one per USB interface. A composite device with N interfaces
returns N entries that share (bus, addr) and differ only in
intf. A consumer that wants one row per physical device should
dedupe on (bus, addr) (mirrors what Linux lsusb does in its
default short form; see tools/lsusb.c for the reference renderer).
Address tuple
typedef struct {
uint8_t bus; ///< host-controller ordinal (1-based)
uint8_t addr; ///< device ordinal within bus (1-based)
uint8_t intf; ///< interface number from interface descriptor
} AxlUsbAddr;
bus and addr are synthesized — UEFI doesn’t expose USB topology
the way Linux does, so AxlUsb derives ordinals from each handle’s
device path: bus numbers each unique host controller in
device-path order; addr numbers each unique physical device within
a bus. They’re stable within a single boot but may shift across
boots if the firmware enumerates handles in a different order.
Consumers needing a persistent identity should hash the device
descriptor (vid:pid:serial) instead.
intf IS the real bInterfaceNumber from the interface descriptor.
Per-device introspection
uint16_t vid, pid;
axl_usb_get_vid_pid(addr, &vid, &pid);
uint8_t cls, sub, prot;
axl_usb_get_class(addr, &cls, &sub, &prot); // any out param may be NULL
char buf[AXL_USB_STRING_MAX];
axl_usb_get_manufacturer(addr, buf, sizeof(buf));
axl_usb_get_product (addr, buf, sizeof(buf));
axl_usb_get_serial (addr, buf, sizeof(buf));
axl_usb_get_vid_pid reads the device descriptor’s idVendor /
idProduct (so all interfaces of one physical device return the
same pair). axl_usb_get_class reads the interface’s class
triplet — composite devices set bDeviceClass = 0 and drive their
identity per interface, so this is the right granularity for the
“one row per interface” walk lsusb does in -vv mode.
axl_usb_get_manufacturer / _product / _serial are convenience
wrappers around axl_usb_get_string(addr, idx, buf, buflen) that
read the device descriptor’s iManufacturer / iProduct /
iSerialNumber index byte first. They return -1 when the device
declares no string at that slot (index == 0). Each one lazily
probes the device’s supported-language table on first use and
caches the first language ID per interface.
Class triplet decode
char buf[AXL_USB_CLASS_NAME_MAX];
axl_usb_class_string_fmt(0x03, 0x01, 0x02, AXL_USB_CLASS_FMT_FULL,
buf, sizeof(buf));
// → "Human Interface Device / Boot Interface / Mouse"
AxlUsbClassFmt selects the output shape — same posture as
AxlPciClassFmt:
FMT_FULL—"<base> / <sub> / <prot>"(default; verbose tools)FMT_SUBCLASS—"<sub>"(collapses to<base>when sub unknown, then numeric — Linux lsusb shape)FMT_BASE—"<base>"(collapses to numeric when unknown)
Tiers with no spec-defined name are omitted rather than rendered as
<unknown> placeholders; wholly-unknown class falls back to
"Class XXXXXX" numeric. Compiled-in tables in src/usb/axl-usb-class.c
cover the USB-IF Defined Class Codes
(https://www.usb.org/defined-class-codes) — base classes, common
subclasses (HID Boot, Mass Storage SCSI, CDC variants, …), and the
most-used protocol bytes (HID Mouse / Keyboard, BBB, UAS). No
sidecar overlay yet (AxlPci has one — pci-class.json5 — but the
USB compiled-in set covers what we ship today).
Topology walk
static int print_node(AxlUsbAddr a, unsigned depth, void *ctx) {
(void)ctx;
for (unsigned i = 0; i < depth; i++) axl_print(" ");
axl_printf("Bus %03u Dev %03u If %u\n", a.bus, a.addr, a.intf);
return 0;
}
axl_usb_tree_for_each(print_node, NULL);
axl_usb_tree_for_each walks every interface in (bus, port_chain, intf) ascending order — guaranteeing parents arrive before
children, so a renderer can emit indentation directly from depth
without lookahead. depth is the USB hub depth: 0 = directly
attached to the host controller’s root hub, 1 = behind one hub, etc.
AXL_USB_TREE_MAX_DEPTH = 8 caps the recorded chain (USB spec
real-world maximum is 5 hubs / 6 USB nodes).
The walker is built from each handle’s EFI device path — the chain
of consecutive MSG_USB_DP nodes encodes the full hub-port path —
and the existing dev-key sort guarantees parents-before-children
(parent dev_keys are byte prefixes of children’s). tools/lsusb.c’s
-t mode is the reference consumer.
Vendor / device name database
axl_usb_ids_load(override_path) loads a curated JSON5 sidecar
(usb-ids.json5). When override_path is non-NULL it is used
authoritatively (no fallback — explicit means explicit). When it is
NULL the loader autodiscovers in this order: companion to the
running .efi, then current working directory. axl-sdk ships a
starter set in share/usb-ids.json5 covering common HID, NIC, hub,
and storage vendors; bulk-extract from canonical usb.ids via
scripts/usb-ids-to-json5.py.
if (axl_usb_ids_load(NULL) == AXL_SIDECAR_OK) {
const char *vendor = axl_usb_vendor_name(0x046D);
const char *device = axl_usb_device_name(0x046D, 0xC52B);
/* both NULL-safe; consumers fall back to numeric IDs */
}
axl_usb_ids_load returns:
AXL_SIDECAR_OKon success (idempotent on subsequent calls)AXL_SIDECAR_FILE_MISSINGif no candidate file existsAXL_SIDECAR_PARSE_ERRORif a candidate was found but failed to parse
The split lets tools log differently — “no database shipped” is a
deployment problem (numeric fallback is fine), while “parse error”
is an authoring problem worth being loud about. See
<axl/axl-sidecar.h> for the shared status enum.
Schema 1 is the only supported layout — hierarchical from the start (vendors with nested devices). USB has no subsystem dimension that motivated AxlPciIds’s v1 (flat) → v2 (hierarchical) split.
{
schema: 1,
vendors: [
{ id: 0x046D, name: 'Logitech, Inc.',
devices: [
{ pid: 0xC52B, name: 'Unifying Receiver' },
],
},
],
}
Composed-name helper
axl_usb_format_name(vid, pid, buf, buflen) centralizes the
“vendor + device + numeric tail” rendering convention so every
consumer prints the same string for the same (vid, pid) pair:
char buf[AXL_USB_NAME_COMPOSED_MAX];
axl_usb_format_name(0x046D, 0xC52B, buf, sizeof(buf));
// → "Logitech, Inc. Unifying Receiver"
Vendor-known + device-unknown produces "<vendor> Device <pid hex>";
vendor-unknown short-circuits to "<vid>:<pid>" regardless of
whether a device entry happens to exist (without a verified vendor
the device hit is ambiguous provenance).
Layered databases (handle API)
Same shape as AxlPciIds. Consumers that ship a private OEM sheet on top of the public set load two handles and query in priority order:
AxlUsbIds *pub = NULL;
AxlUsbIds *priv = NULL;
axl_usb_ids_open("usb-ids.json5", &pub);
axl_usb_ids_open("private-usb-ids.json5", &priv);
const char *d = axl_usb_ids_device_name(priv, vid, pid);
if (d == NULL) d = axl_usb_ids_device_name(pub, vid, pid);
axl_usb_ids_close(priv);
axl_usb_ids_close(pub);
axl_usb_ids_format_name(handle, vid, pid, buf, buflen) is the
handle-aware equivalent of axl_usb_format_name. For “show me
everything in this overlay” use axl_usb_ids_foreach_vendor /
_foreach_device.
Per-name length contracts
AXL_USB_VENDOR_NAME_MAX = 128 bytes
AXL_USB_DEVICE_NAME_MAX = 192 bytes
AXL_USB_NAME_COMPOSED_MAX = 384 bytes
AXL_USB_CLASS_NAME_MAX = 128 bytes
AXL_USB_STRING_MAX = 384 bytes (USB string descriptors;
127 BMP chars * 3 UTF-8
bytes + NUL; BMP only)
Sized to comfortably hold real usb.ids entries; loader silently
truncates over-cap names. Pin
char buf[AXL_USB_NAME_COMPOSED_MAX] on the stack and never have
to worry about formatter overflow.
Bulk population from canonical usb.ids
The shipped share/usb-ids.json5 is a curated starter set (~22
vendors). For fleet-scale OEM-rebadge coverage, run the conversion
against the canonical usb.ids:
# Full set:
scripts/usb-ids-to-json5.py /usr/share/hwdata/usb.ids \
> usb-ids.json5
# Curated subset (vendor entries always emitted; only their
# devices are dropped for vendors not in the list):
scripts/usb-ids-to-json5.py --vendors-only 046d,0bda,1d6b \
/usr/share/hwdata/usb.ids > usb-ids.json5
# Verify the script itself:
scripts/usb-ids-to-json5.py --self-test
The .deb / .rpm install the converter under
/usr/share/axl/scripts/; the line-level parser is shared with
pci-ids-to-json5.py via _ids_parser.py.
API Reference
USB device enumeration via EFI_USB_IO_PROTOCOL handles.
The UEFI USB stack exposes one EFI_USB_IO_PROTOCOL handle per interface* of every enumerated device — multiple handles therefore refer to the same physical device when it has more than one function (e.g. a composite keyboard+mouse, or a USB-net adapter with separate control / data interfaces). AxlUsb derives stable (bus, addr, intf) ordinals from each handle’s device path so consumers can present a Linux-lsusb-shaped view: one row per interface, deduplicated and ordered by bus/device/interface.
Cursor-style iteration mirrors axl_pci_next:
AxlUsbAddr *u = NULL;
while ((u = axl_usb_next(u)) != NULL) {
uint16_t vid, pid;
if (axl_usb_get_vid_pid(*u, &vid, &pid) == 0) {
// ...
}
}
Phase A: enumeration + vendor/product ID readout. Phase B: interface class triplet (class / subclass / protocol) decode via the same compiled-in tables AxlPci uses for PCI classes. Phase C: string descriptor reads — manufacturer / product / serial via UsbGetStringDescriptor + UCS-2 → UTF-8. Phase D: vendor/device-name database via usb-ids.json5 sidecar (handle + singleton API mirroring AxlPciIds). See docs/AXL-Usb-Handoff.md.
USB-name length contracts
Maximum bytes (including NUL) any USB-IDs database lookup can return.
Sized comfortably for real usb.ids entries — vendor strings like “Logitech, Inc.” run ~20 bytes, device strings frequently 60-100, the rare full descriptive name fits in 192. Composed name covers vendor + device + small fixed overhead, so axl_usb_format_name never truncates non-truncated inputs.
-
AXL_USB_VENDOR_NAME_MAX
vendor entry max bytes
-
AXL_USB_DEVICE_NAME_MAX
device entry max bytes
-
AXL_USB_NAME_COMPOSED_MAX
axl_usb_format_name output max
Database iteration callbacks
Non-zero callback return stops iteration and propagates as the iter rc.
-
typedef int (*AxlUsbIdsVendorFn)(uint16_t vid, const char *name, void *ctx)
-
typedef int (*AxlUsbIdsDeviceFn)(uint16_t vid, uint16_t pid, const char *name, void *ctx)
-
int axl_usb_ids_foreach_vendor(const AxlUsbIds *ids, AxlUsbIdsVendorFn fn, void *ctx)
-
int axl_usb_ids_foreach_device(const AxlUsbIds *ids, AxlUsbIdsDeviceFn fn, void *ctx)
Defines
-
AXL_USB_CLASS_NAME_MAX
Buffer cap for a class-triplet decoded string. Sized for the longest plausible “Base / Sub / Prot” composition.
-
AXL_USB_STRING_MAX
Buffer cap for UTF-8 string-descriptor output. USB string descriptors max out at 254 bytes of UCS-2 payload (127 BMP code points); a BMP code point in U+0800..U+FFFF expands to 3 UTF-8 bytes, so the worst-case payload is 127 * 3 = 381 bytes plus NUL. BMP only —
axl_ucs2_to_utf8_bufdoes not decode surrogate pairs, so supplementary-plane code points (U+10000+) are not supported.
-
AXL_USB_TREE_MAX_DEPTH
Maximum hub depth the tree walker will descend. USB 2.0/3.x caps the bus depth at 5 hubs between root and device (= 6 USB device-path nodes including the leaf), so 8 levels is generous headroom against malformed firmware paths.
Typedefs
-
typedef int (*AxlUsbTreeFn)(AxlUsbAddr addr, unsigned depth, void *ctx)
Per-node callback for axl_usb_tree_for_each.
- Param addr:
the interface being visited (same shape axl_usb_next emits)
- Param depth:
USB hub depth — 0 means the device is directly attached to the host controller’s root hub; 1 means the device is one hub deep; etc. Different from
addr.bus(which is the controller ordinal).- Param ctx:
caller’s opaque context
- Return:
non-zero to stop the walk early; the value becomes the return of axl_usb_tree_for_each. Return 0 to continue.
-
typedef struct AxlUsbIds AxlUsbIds
Opaque handle to a loaded USB vendor/device-name database.
Created by axl_usb_ids_open or axl_usb_ids_open_from_buffer, destroyed by axl_usb_ids_close. Multiple handles can coexist — a consumer that wants a “public + private” overlay loads two handles and queries them in priority order. Mirrors AxlPciIds and AxlSpdIds.
Schema 1 is the only supported layout. The structure is hierarchical from the start (vendors with nested devices) — USB has no subsystem dimension that motivated PCI’s v1→v2 split, so there’s no flat-vs-hierarchical schema dispatch.
{ schema: 1, vendors: [ { id: 0x046D, name: 'Logitech, Inc.', devices: [ { pid: 0xC52B, name: 'Unifying Receiver' }, ], }, ], }
Enums
-
enum AxlUsbClassFmt
Output shape selector for axl_usb_class_string_fmt.
USB class triplets decode into base / subclass / protocol tiers. Verbose tools want the full slash-joined triplet; row-oriented tools want the subclass alone (matches Linux lsusb shape); coarse categorization wants just the base. Mirrors AxlPciClassFmt.
Values:
-
enumerator AXL_USB_CLASS_FMT_FULL
“Human Interface Device / Boot Interface / Mouse”
-
enumerator AXL_USB_CLASS_FMT_SUBCLASS
“Boot Interface” (collapses to base if unknown)
-
enumerator AXL_USB_CLASS_FMT_BASE
“Human Interface Device” (collapses to numeric if unknown)
-
enumerator AXL_USB_CLASS_FMT_FULL
Functions
-
AxlUsbAddr *axl_usb_next(AxlUsbAddr *prev)
Iterate every USB interface exposed by
EFI_USB_IO_PROTOCOL.Returns a pointer to a static internal cursor; the storage is reused across calls and is invalidated by the next call. Pass NULL to start the walk fresh, or the previous non-NULL return value to advance — passing any other pointer (including a caller-allocated AxlUsbAddr) restarts iteration silently. The caller never owns the cursor’s storage.
Iteration order is
(bus, addr, intf)ascending. Returns NULL when the walk is complete or noEFI_USB_IO_PROTOCOLhandles are installed (the platform has no USB stack, or the firmware did not enumerate any USB devices).- Parameters:
prev – previous result, or NULL to start
- Returns:
pointer to the next interface, or NULL when enumeration is complete (or the USB stack is unavailable).
-
int axl_usb_get_vid_pid(AxlUsbAddr addr, uint16_t *vid, uint16_t *pid)
Read vendor ID and product ID from a USB device descriptor.
Reads the
idVendor/idProductfields of the standard 18-byte device descriptor viaEFI_USB_IO_PROTOCOL.UsbGetDeviceDescriptor. All interfaces of one physical device share the same(vid, pid)— the per-interface granularity ofAxlUsbAddrdoes not change the descriptor that backs this call.- Parameters:
addr – target interface
vid – [out] vendor ID
pid – [out] product ID
- Returns:
0 on success (both fields populated), -1 if
addris not a known interface or the firmware fails the descriptor read.
-
int axl_usb_get_class(AxlUsbAddr addr, uint8_t *class_, uint8_t *sub, uint8_t *prot)
Read the interface class triplet for a USB interface.
Reads
bInterfaceClass/bInterfaceSubClass/bInterfaceProtocolfrom the interface descriptor viaEFI_USB_IO_PROTOCOL.UsbGetInterfaceDescriptor. Composite devices (DeviceDescriptor.bDeviceClass = 0) drive their class identity per interface — the right granularity to query for tools that present one row per interface (Linux lsusb -v shape).Out parameters may be individually NULL if the caller doesn’t need that field.
- Parameters:
addr – target interface
class_ – [out, optional] base class (e.g. 0x03 for HID)
sub – [out, optional] subclass
prot – [out, optional] protocol
- Returns:
0 on success, -1 if
addris not a known interface or the firmware fails the descriptor read.
-
int axl_usb_class_string_fmt(uint8_t class_, uint8_t sub, uint8_t prot, AxlUsbClassFmt fmt, char *buf, size_t buflen)
Format a USB class triplet as a human-readable string.
Decodes per the USB-IF Defined Class Codes spec (https://www.usb.org/defined-class-codes) — up to three tiers: base class, subclass, and protocol. Tiers with no spec-defined name are omitted rather than rendered as
<unknown>placeholders.Output shapes (FMT_FULL):
All known:
"<base> / <sub> / <prot>"(e.g."Human Interface Device / Boot Interface / Mouse")Known base+sub, unknown prot:
"<base> / <sub>"Known base, unknown sub:
"<base>"Wholly unknown:
"Class XXXXXX"(numeric hex, in the spirit of Linux lsusb’s numeric fallback).
Always NUL-terminates
buf(snprintf-shape).- Parameters:
class_ – base class
sub – subclass
prot – protocol
fmt – output shape selector
buf – destination buffer
buflen – capacity of
buf
- Returns:
number of bytes written excluding NUL, or -1 if
bufis NULL orbuflenis 0 orfmtis unrecognized.
-
int axl_usb_class_string(uint8_t class_, uint8_t sub, uint8_t prot, char *buf, size_t buflen)
Convenience wrapper for axl_usb_class_string_fmt with
FMT_FULL.
-
int axl_usb_get_string(AxlUsbAddr addr, uint8_t string_index, char *buf, size_t buflen)
Read a USB string descriptor by index, decoded to UTF-8.
Indices are unsigned bytes in the device’s string descriptor table: the device descriptor’s
iManufacturer/iProduct/iSerialNumberfields name three of them by convention; class- specific descriptors (HID, Audio, Configuration) reference others.Index 0 is reserved for the language-ID table (USB 2.0 §9.6.7);
axl_usb_get_stringhandles that internally — pass 1..255 for actual strings. The library picks the first language ID the device advertises and caches it per interface; multi-language devices that need a specific LANGID are out of scope for this helper.Output is NUL-terminated UTF-8 in
buf. Truncation is silent at the byte boundary (never writes a partial multi-byte sequence) —axl_ucs2_to_utf8_buf’s contract.- Parameters:
addr – target interface
string_index – 1..255; 0 is reserved
buf – destination UTF-8 buffer
buflen – capacity in bytes (incl. NUL)
- Returns:
number of UTF-8 bytes written excluding NUL on success, -1 if
addris unknown, the device has no string descriptors, index 0 was passed, the firmware fails the descriptor read, orbuf/buflenare bad.
-
int axl_usb_get_manufacturer(AxlUsbAddr addr, char *buf, size_t buflen)
Read the device’s manufacturer string (UTF-8).
Convenience over axl_usb_get_string — reads the
iManufacturerindex from the device descriptor, then fetches that string. Returns -1 if the device descriptor declares no manufacturer string (index = 0), mirroringaxl_usb_get_string.- Returns:
UTF-8 byte count or -1 (see axl_usb_get_string).
-
int axl_usb_get_product(AxlUsbAddr addr, char *buf, size_t buflen)
Read the device’s product string (UTF-8). See axl_usb_get_manufacturer.
-
int axl_usb_get_serial(AxlUsbAddr addr, char *buf, size_t buflen)
Read the device’s serial-number string (UTF-8). See axl_usb_get_manufacturer.
-
int axl_usb_tree_for_each(AxlUsbTreeFn fn, void *ctx)
Walk the USB topology in tree order, depth-first per bus.
Each
EFI_USB_IO_PROTOCOLhandle’s device path encodes its full port chain via consecutive USB messaging-type nodes (PciRoot/.../Pci(usb_ctrl)/USB(parent_port, intf)/USB(...)). The walker recovers that chain at ingest time and emits entries in (bus, port_chain, intf) ascending order — guaranteeing parents arrive before children, so a renderer can print indentation derived fromdepthwithout lookahead.Hubs that have no leaf descendants still appear (depth = N for an N-deep hub); their interface is enumerable via the same
EFI_USB_IO_PROTOCOLhandle every other USB device exposes. The caller can disambiguate hubs from leaves by reading the interface class via axl_usb_get_class — class 0x09 is the USB Hub class.The callback may freely call AxlUsb read-only APIs against the visited
addr(vid/pid, class, string descriptors) but must not invoke axl_usb_next during the walk — the cursor it uses is module-static and a re-entrant call would corrupt the outer iteration.- Returns:
0 on a clean walk, the callback’s first non-zero return if it stopped early, or -1 if
fnis NULL or no USB stack is available.
-
AxlSidecarStatus axl_usb_ids_open(const char *path, AxlUsbIds **out)
Open a USB-IDs database from a JSON5 file.
- Returns:
AXL_SIDECAR_OKon success (handle returned viaout),AXL_SIDECAR_FILE_MISSINGifpathdoes not exist,AXL_SIDECAR_PARSE_ERRORon JSON5 / schema rejection.
-
AxlSidecarStatus axl_usb_ids_open_from_buffer(const char *json5, size_t len, AxlUsbIds **out)
Open a USB-IDs database from an in-memory JSON5 buffer.
- Returns:
AXL_SIDECAR_OKon success,AXL_SIDECAR_PARSE_ERRORon parse / schema error.
-
const char *axl_usb_ids_vendor_name(const AxlUsbIds *ids, uint16_t vid)
Vendor lookup against an explicit handle.
- Returns:
database-owned string or NULL if unknown / handle empty.
-
const char *axl_usb_ids_device_name(const AxlUsbIds *ids, uint16_t vid, uint16_t pid)
Device lookup against an explicit handle.
- Returns:
database-owned string or NULL if (vid, pid) is unknown.
-
int axl_usb_ids_format_name(const AxlUsbIds *ids, uint16_t vid, uint16_t pid, char *buf, size_t buflen)
Compose a “vendor + device” display string against a handle.
Centralizes the rendering convention every consumer would otherwise reinvent — every tool prints the same string for the same
(vid, pid) pair:vendor known + device known →
"<vendor> <device>"vendor known + device unknown →
"<vendor> Device <PID hex>"vendor unknown →
"<VID>:<PID>"
Hex literals are lowercase, 4-wide, zero-padded (matches Linux lsusb’s
-dfilter form). Output never exceeds AXL_USB_NAME_COMPOSED_MAX bytes.- Returns:
number of bytes written excluding NUL (snprintf shape), or -1 on bad arguments.
-
AxlSidecarStatus axl_usb_ids_load(const char *override_path)
Load the curated USB vendor/device name database into the process-global slot.
Two modes selected by
override_path:Explicit (
override_pathnon-NULL): use exactly that path.Autodiscover (
override_pathNULL): tryusb-ids.json5next to the running .efi (companion path), then in the current working directory.
Idempotent — a successful load is a no-op on subsequent calls. Registers an axl_atexit cleanup on first success so the parsed table is freed automatically at runtime cleanup.
-
void axl_usb_ids_free(void)
Free the loaded database. Safe to call when none is loaded.
-
const char *axl_usb_vendor_name(uint16_t vid)
Singleton-backed vendor lookup.
- Returns:
database-owned string, or NULL if no database loaded or
vidis not present.
-
const char *axl_usb_device_name(uint16_t vid, uint16_t pid)
Singleton-backed device lookup. Does not fall back to the vendor name when the device is unknown — callers compose their own “vendor name + numeric PID” via axl_usb_format_name.
-
int axl_usb_format_name(uint16_t vid, uint16_t pid, char *buf, size_t buflen)
Singleton-backed convenience wrapper for axl_usb_ids_format_name.
-
struct AxlUsbAddr
- #include <axl-usb.h>
A USB controller address (bus / device / interface).
busis a 1-based ordinal of the host controller (xHCI/EHCI/UHCI/ OHCI) the device is behind, in EFI device-path order.addris a 1-based ordinal of the physical device within that bus, deduplicated across interfaces.intfis the real interface number returned byUsbGetInterfaceDescriptor— multiple(bus, addr, *)entries with differentintfvalues refer to interfaces of the same physical device.Ordinals are stable within a single boot but not across boots — the underlying EFI handle order can change. Consumers that need a persistent identity should hash the device descriptor (vid:pid:serial) instead.