Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions components/usb_host/include/usb_host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,14 @@ class UsbHost : public BaseComponent {
/// @param ec Set on failure. If any step of the teardown fails (a device the
/// driver cannot release, or the library refusing to uninstall) the host
/// stays initialized (is_initialized() remains true) and false is
/// returned, rather than tearing down under a live driver. Destroying
/// a UsbHost in that state aborts (see the destructor).
/// returned, rather than tearing down under a live driver. In that
/// state event delivery has already stopped, every device has been
/// retired, and the root port is left powered off (powering it back up
/// would only make the driver re-track the device that a retry needs
/// gone), so the host is not usable: the only valid next steps are to
/// call deinitialize() again (which waits for the driver again) or to
/// destroy the object, which aborts if teardown still fails (see the
/// destructor).
/// @return true on success.
bool deinitialize(std::error_code &ec);

Expand Down
22 changes: 19 additions & 3 deletions components/usb_host/src/usb_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,18 @@ bool UsbHost::deinitialize(std::error_code &ec) {
}
if (err != ESP_OK) {
// Tearing down under a driver that still references us would be a
// use-after-free waiting to happen; stay initialized and report it.
logger_.error("hid_host_uninstall failed: {} (a device could not be released)",
esp_err_to_name(err));
// use-after-free waiting to happen; stay initialized and report it. The
// root port deliberately stays powered OFF: powering it back up would make
// the driver re-enumerate (and track) the attached device again, which is
// exactly what a retry of deinitialize() needs to have gone away. Event
// delivery is already stopped, so the only valid next steps are retrying
// deinitialize() or destroying the object (see the header).
// ESP_ERR_INVALID_STATE is what the driver returns while it still tracks a
// device; anything else is reported as-is rather than guessed at.
logger_.error("hid_host_uninstall failed: {}{}; root port left powered off, retry "
"deinitialize()",
esp_err_to_name(err),
err == ESP_ERR_INVALID_STATE ? " (the driver still tracks a device)" : "");
ec = make_ec(err);
return false;
}
Expand Down Expand Up @@ -569,6 +578,13 @@ void UsbHost::on_interface_event(hid_host_device_handle_t handle,
if (err != ESP_OK) {
return;
}
if (len > cap) {
// The driver copies at most `cap` bytes, so this only happens if it ever
// reports the report's full length rather than the copied length; never
// let it turn into an out-of-bounds span.
logger_.warn("input report of {} bytes truncated to {} (max_input_report_size)", len, cap);
len = cap;
}
ev.len = len;
enqueue(std::move(ev));
break;
Expand Down
Loading