picofuse

Data Structures | Macros | Typedefs | Enumerations | Functions

USB host interface for hardware platforms. More...

Collaboration diagram for USB:

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_thw_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_thw_usb_register_hid (hid_t *instance, hw_usb_t *usb)
 Register a USB host hotplug observer as a HID source. More...
 

Detailed Description

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.

Todo:
No module actually reads HID input (keystrokes, mouse movement) yet - something like 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:
  • Pico: safe to do directly through TinyUSB's own HID class driver (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.
  • Linux: NOT through libusb/this module at all - the kernel's own 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.
  • Darwin: same reasoning as Linux, different API - 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.

Note
On the Pico (RP2040), the USB peripheral and the UART/debug interface share the same physical USB connector. Enabling USB host mode will prevent the device from appearing as a USB serial device to a connected host PC. Use a debug probe if you need simultaneous debug output.

Typedef Documentation

◆ hw_usb_callback_t

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.

Parameters
usbThe USB host handle.
eventThe hotplug event type (attached or detached).
deviceDescriptor 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.
userdataOpaque user pointer supplied to hw_usb_set_callback.

Definition at line 301 of file usb.h.

Enumeration Type Documentation

◆ hw_usb_device_class_t

USB device class codes.

These are the standard bDeviceClass descriptor values defined by USB. A value of 0x00 means the class is defined at the interface level.

Definition at line 147 of file usb.h.

147  {
148  hw_usb_device_class_per_interface = 0x00,
149  hw_usb_device_class_audio = 0x01,
150  hw_usb_device_class_communications = 0x02,
151  hw_usb_device_class_hid = 0x03,
152  hw_usb_device_class_physical = 0x05,
153  hw_usb_device_class_image = 0x06,
154  hw_usb_device_class_printer = 0x07,
155  hw_usb_device_class_mass_storage = 0x08,
156  hw_usb_device_class_hub = 0x09,
157  hw_usb_device_class_cdc_data = 0x0A,
158  hw_usb_device_class_smart_card = 0x0B,
159  hw_usb_device_class_content_security = 0x0D,
160  hw_usb_device_class_video = 0x0E,
161  hw_usb_device_class_personal_healthcare = 0x0F,
162  hw_usb_device_class_audio_video = 0x10,
163  hw_usb_device_class_bluetooth = 0xE0,
164  hw_usb_device_class_miscellaneous = 0xEF,
165  hw_usb_device_class_application_specific = 0xFE,
166  hw_usb_device_class_vendor_specific = 0xFF,
hw_usb_device_class_t
USB device class codes.
Definition: usb.h:147

◆ hw_usb_device_protocol_t

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.

218  {
219  hw_usb_device_protocol_none = 0x00,
220  hw_usb_device_protocol_keyboard = 0x01,
221  hw_usb_device_protocol_mouse = 0x02,
hw_usb_device_protocol_t
USB device protocol codes.
Definition: usb.h:218

◆ hw_usb_device_subclass_t

USB device subclass codes.

Subclass values are class-specific USB descriptor codes. Only common raw values are named here; callers may still observe any 8-bit descriptor value.

Definition at line 190 of file usb.h.

190  {
191  hw_usb_device_subclass_none = 0x00,
192  hw_usb_device_subclass_boot_interface = 0x01,
193  hw_usb_device_subclass_abstract_control_model = 0x02,
194  hw_usb_device_subclass_vendor_specific = 0xFF,
hw_usb_device_subclass_t
USB device subclass codes.
Definition: usb.h:190

◆ hw_usb_event_t

USB hotplug event type.

Enumerator
hw_usb_event_attached 

A device has been attached.

hw_usb_event_detached 

A device has been detached.

Definition at line 135 of file usb.h.

135  {
136  hw_usb_event_attached = (1 << 0),
137  hw_usb_event_detached = (1 << 1),
A device has been detached.
Definition: usb.h:137
hw_usb_event_t
USB hotplug event type.
Definition: usb.h:135
A device has been attached.
Definition: usb.h:136

Function Documentation

◆ hw_usb_deinit()

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.

Parameters
usbThe USB host handle to deinitialize.

◆ hw_usb_device_class_to_string()

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.

Parameters
device_classUSB device class code.
Returns
Pointer to an internal string buffer.

◆ hw_usb_device_protocol_to_string()

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.

Parameters
device_protocolUSB device protocol code.
Returns
Pointer to an internal string buffer.

◆ hw_usb_init()

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.

Returns
A USB host handle, or NULL if initialization fails.

◆ hw_usb_register_hid()

hid_device_t* hw_usb_register_hid ( hid_t instance,
hw_usb_t usb 
)

Register a USB host hotplug observer as a HID source.

Parameters
instanceHID instance that owns the registration.
usbUSB handle from hw_usb_init. Ownership isn't transferred - the caller remains responsible for hw_usb_deinit, which this doesn't call.
Returns
Registered HID device descriptor, or NULL on failure (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.

◆ hw_usb_set_callback()

void hw_usb_set_callback ( hw_usb_t usb,
hw_usb_callback_t  callback,
void *  userdata 
)

Attach or detach the USB hotplug callback.

Parameters
usbHandle from hw_usb_init.
callbackCallback to invoke on attach/detach events, or NULL to detach the current callback.
userdataOpaque 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.