USB host interface for hardware platforms. More...
|
Data Structures | |
| struct | hw_usb_device_t |
| Describes one interface of a USB device observed by the host. More... | |
Macros | |
| #define | HW_USB_STRING_MAX_LENGTH 63 |
| Maximum length of USB string descriptor fields, excluding the null terminator. | |
| #define | HW_USB_INTERFACE_MAX_COUNT 8 |
| Maximum number of interfaces a backend will report attach/detach events for on any single device - internal to each backend's own per-device interface cache, not a limit on any public array. | |
Typedefs | |
| typedef struct hw_usb_t | hw_usb_t |
| Opaque USB host handle. | |
| typedef void(* | hw_usb_callback_t) (hw_usb_t *usb, hw_usb_event_t event, const hw_usb_device_t *device, void *userdata) |
| Callback invoked on USB hotplug events. More... | |
Enumerations | |
| enum | hw_usb_event_t { hw_usb_event_attached = (1 << 0), hw_usb_event_detached = (1 << 1) } |
| USB hotplug event type. More... | |
| enum | hw_usb_device_class_t { hw_usb_device_class_per_interface = 0x00, hw_usb_device_class_audio = 0x01, hw_usb_device_class_communications = 0x02, hw_usb_device_class_hid = 0x03, hw_usb_device_class_physical = 0x05, hw_usb_device_class_image = 0x06, hw_usb_device_class_printer = 0x07, hw_usb_device_class_mass_storage = 0x08, hw_usb_device_class_hub = 0x09, hw_usb_device_class_cdc_data = 0x0A, hw_usb_device_class_smart_card = 0x0B, hw_usb_device_class_content_security = 0x0D, hw_usb_device_class_video = 0x0E, hw_usb_device_class_personal_healthcare = 0x0F, hw_usb_device_class_audio_video = 0x10, hw_usb_device_class_bluetooth = 0xE0, hw_usb_device_class_miscellaneous = 0xEF, hw_usb_device_class_application_specific = 0xFE, hw_usb_device_class_vendor_specific = 0xFF } |
| USB device class codes. More... | |
| enum | hw_usb_device_subclass_t { hw_usb_device_subclass_none = 0x00, hw_usb_device_subclass_boot_interface = 0x01, hw_usb_device_subclass_abstract_control_model = 0x02, hw_usb_device_subclass_vendor_specific = 0xFF } |
| USB device subclass codes. More... | |
| enum | hw_usb_device_protocol_t { hw_usb_device_protocol_none = 0x00, hw_usb_device_protocol_keyboard = 0x01, hw_usb_device_protocol_mouse = 0x02 } |
| USB device protocol codes. More... | |
Functions | |
| const char * | hw_usb_device_class_to_string (hw_usb_device_class_t device_class) |
| Convert a USB device class code to a display string. More... | |
| const char * | hw_usb_device_protocol_to_string (hw_usb_device_protocol_t device_protocol) |
| Convert a USB device protocol code to a display string. More... | |
Lifecycle | |
| hw_usb_t * | hw_usb_init (void) |
| Initialize the USB host subsystem. More... | |
| void | hw_usb_deinit (hw_usb_t *usb) |
| Deinitialize the USB host subsystem. More... | |
Methods | |
| void | hw_usb_set_callback (hw_usb_t *usb, hw_usb_callback_t callback, void *userdata) |
| Attach or detach the USB hotplug callback. More... | |
HID Integration | |
| hid_device_t * | hw_usb_register_hid (hid_t *instance, hw_usb_t *usb) |
| Register a USB host hotplug observer as a HID source. More... | |
USB host interface for hardware platforms.
This module provides USB host functionality, including detection of devices as they are attached and detached. hw_usb_init brings the host controller up but attaches no callback - use hw_usb_set_callback for that, separately, so that whichever part of a program brings USB up doesn't have to be the same part that observes it (see hw_usb_register_hid for exactly that: a HID bridge that only observes a handle some other part of the program owns). Once a callback is attached, it's fired once for each device already connected to the host, with the hw_usb_event_attached event, then again whenever a device is physically attached or detached from then on.
Enumeration happens at the interface level, not the device level: a composite device (a keyboard+mouse combo, any multi-function gadget) fires the callback once per interface it exposes, not once for the whole device - the same shape the host OS itself typically uses (one /dev/input/eventN per interface on Linux, for example). Every one of those events shares the same hw_usb_device_t::device_id, hw_usb_device_t::vid, hw_usb_device_t::pid and string fields, but carries that interface's own hw_usb_device_t::interface_number and interface class/subclass/protocol - which is where the useful classification actually lives for a composite device, since its device-level class is conventionally 0x00 ("per-interface", hw_usb_device_class_per_interface) and tells you nothing on its own. Only interface alternate setting 0 (the default/active one) is considered.
The hw_usb_device_t structure describes one interface of a connected device. It carries the USB vendor/product identifiers, the device and interface class metadata, and the string descriptors that are available from the backend. On detach, the manufacturer, product and serial string fields may be empty, and some backends may only be able to provide zeroed identifier fields on a fallback detach path. If interface information couldn't be determined (the configuration descriptor wasn't readable, or declared no interfaces), a single fallback event fires with hw_usb_device_t::interface_number set to 0xFF and the interface class/subclass/protocol fields copied from the device-level ones.
Class-specific functionality (HID input, CDC-ACM serial streams, mass storage) is handled by separate modules that consume the device information provided here.
hw_usb_register_hid_device() (working name only; needs a better one, and a real signature - presumably taking a hw_usb_device_t identifying which interface to read) for keyboard and mouse to start with, scoped to boot-protocol interfaces (hw_usb_device_subclass_boot_interface, interface_protocol == hw_usb_device_protocol_keyboard / hw_usb_device_protocol_mouse) so a fixed, known report shape (8 bytes keyboard, 3-4 bytes mouse) can be assumed without a general HID report-descriptor parser. This is NOT a single cross-platform implementation on top of this module - the three platforms need three genuinely different backends:CFG_TUH_HID, currently left at 0 in tusb_config.h, plus tuh_hid_report_received_cb()) - this process's USB stack is the only consumer of the bus, so there's nothing else to conflict with.usbhid driver already owns the interface the instant it's plugged in (confirmed via lsusb -t showing Driver=usbhid), so reading it via libusb would need libusb_detach_kernel_driver(), which steals the device from the rest of the running system (e.g. the real keyboard stops working for the OS itself). The correct mechanism is evdev (/dev/input/eventN), read alongside the OS rather than instead of it - see the already-reserved but unimplemented hid_type_evdev.IOHIDManager/ IOHIDDeviceClient (IOKit's HID Manager) taps into HID collections the kernel's own driver already parsed, without taking exclusive ownership. Needs the user to grant Input Monitoring permission on modern macOS. The Linux/Darwin backends don't need hw_usb_init/PICOFUSE_USB engaged at all, since they observe at the kernel-input layer rather than the raw USB layer this module provides.On the Pico platform, the USB peripheral is fixed hardware and operates in host mode exclusively. On Linux and macOS, the host controller is managed via libusb. In both cases, hw_usb_init takes no platform-specific address parameter.
| typedef void(* hw_usb_callback_t) (hw_usb_t *usb, hw_usb_event_t event, const hw_usb_device_t *device, void *userdata) |
Callback invoked on USB hotplug events.
| usb | The USB host handle. |
| event | The hotplug event type (attached or detached). |
| device | Descriptor of the interface that was attached or detached. For normal attach/detach callbacks this is non-NULL. A device with multiple interfaces fires this callback once per interface (see this file's own top-level doc) - each of those calls shares the same device's device_id/vid/ pid/strings, but carries that interface's own interface_number/interface_class/_subclass/_protocol. After initial enumeration completes, the callback is invoked once with hw_usb_event_attached and device set to NULL as an "enumeration complete" marker. String fields may be empty on detach. |
| userdata | Opaque user pointer supplied to hw_usb_set_callback. |
USB device protocol codes.
Protocol values are class-specific USB descriptor codes. Only the raw descriptor value is standardized here; callers may still observe any 8-bit value defined by the device's class.
hw_usb_device_protocol_keyboard and hw_usb_device_protocol_mouse are only meaningful when the interface's subclass is hw_usb_device_subclass_boot_interface - they're USB HID's own "boot protocol" codes, a simplified report format BIOS/bootloader-level code can read without parsing the device's actual HID report descriptor. Support for it is optional and only covers keyboards and mice: a non-boot HID interface (a keyboard's own media-key/consumer-control interface, a touchpad, a joystick, a gamepad, ...) reports hw_usb_device_protocol_none here regardless of what it actually is - telling those apart needs the interface's HID report descriptor itself (Usage Page/Usage - Generic Desktop's Mouse/Joystick/Gamepad/Keyboard, Digitizers' Touch Pad, ...), which nothing in this module parses.
Definition at line 218 of file usb.h.
| enum hw_usb_event_t |
| void hw_usb_deinit | ( | hw_usb_t * | usb | ) |
Deinitialize the USB host subsystem.
Shuts down the USB host controller and releases all associated resources. The hotplug callback is deregistered and will not be invoked after this call returns. Safe to call on an already-deinitialized handle, in which case it is a no-op.
| usb | The USB host handle to deinitialize. |
| const char* hw_usb_device_class_to_string | ( | hw_usb_device_class_t | device_class | ) |
Convert a USB device class code to a display string.
In debug builds this returns a symbolic name such as "hw_usb_device_class_hid" when known; otherwise it returns a hexadecimal fallback formatted as "0x%02X". In non-debug builds this always returns the hexadecimal fallback.
| device_class | USB device class code. |
| const char* hw_usb_device_protocol_to_string | ( | hw_usb_device_protocol_t | device_protocol | ) |
Convert a USB device protocol code to a display string.
In debug builds this returns a symbolic name such as "hw_usb_device_protocol_keyboard" when known; otherwise it returns a hexadecimal fallback formatted as "0x%02X". In non-debug builds this always returns the hexadecimal fallback.
| device_protocol | USB device protocol code. |
| hw_usb_t* hw_usb_init | ( | void | ) |
Initialize the USB host subsystem.
Initializes the USB host controller. The returned handle has no callback attached - enumeration and hotplug detection still happen, just silently, until one is attached via hw_usb_set_callback.
| hid_device_t* hw_usb_register_hid | ( | hid_t * | instance, |
| hw_usb_t * | usb | ||
| ) |
Register a USB host hotplug observer as a HID source.
| instance | HID instance that owns the registration. |
| usb | USB handle from hw_usb_init. Ownership isn't transferred - the caller remains responsible for hw_usb_deinit, which this doesn't call. |
usb is NULL, or a USB HID source is already registered - like usb itself, this is a singleton, only one registration can be active at a time).Attaches a callback via hw_usb_set_callback (replacing whatever was attached before) and forwards every event it fires as a hid_event_type_usb event - see hid_usb_t. Deregistering (via the owning hid_t's own teardown) detaches the callback but does not deinitialize usb.
| void hw_usb_set_callback | ( | hw_usb_t * | usb, |
| hw_usb_callback_t | callback, | ||
| void * | userdata | ||
| ) |
Attach or detach the USB hotplug callback.
| usb | Handle from hw_usb_init. |
| callback | Callback to invoke on attach/detach events, or NULL to detach the current callback. |
| userdata | Opaque user pointer forwarded to callback. |
Separate from init so that whichever part of a program brought USB up doesn't have to be the same part that observes it - see this file's own top-level doc, and hw_usb_register_hid for exactly that use. Once attached, the callback is fired with hw_usb_event_attached for each device already connected, then once more with hw_usb_event_attached and device set to NULL to mark enumeration complete, then again whenever a device is physically attached or detached from then on. Safe to call at any time. A no-op on an invalid handle.