[usb_uart] Fixes for transfer queue allocation (#11548)

This commit is contained in:
Clyde Stubbs
2025-11-04 10:23:45 +11:00
committed by GitHub
parent 99ce989eae
commit 99d1a9cf6e
4 changed files with 51 additions and 40 deletions
+15 -7
View File
@@ -214,7 +214,7 @@ void USBUartComponent::dump_config() {
}
}
void USBUartComponent::start_input(USBUartChannel *channel) {
if (!channel->initialised_.load() || channel->input_started_.load())
if (!channel->initialised_.load())
return;
// THREAD CONTEXT: Called from both USB task and main loop threads
// - USB task: Immediate restart after successful transfer for continuous data flow
@@ -226,12 +226,18 @@ void USBUartComponent::start_input(USBUartChannel *channel) {
//
// The underlying transfer_in() uses lock-free atomic allocation from the
// TransferRequest pool, making this multi-threaded access safe
// if already started, don't restart. A spurious failure in compare_exchange_weak
// is not a problem, as it will be retried on the next read_array()
auto started = false;
if (!channel->input_started_.compare_exchange_weak(started, true))
return;
const auto *ep = channel->cdc_dev_.in_ep;
// CALLBACK CONTEXT: This lambda is executed in USB task via transfer_callback
auto callback = [this, channel](const usb_host::TransferStatus &status) {
ESP_LOGV(TAG, "Transfer result: length: %u; status %X", status.data_len, status.error_code);
if (!status.success) {
ESP_LOGE(TAG, "Control transfer failed, status=%s", esp_err_to_name(status.error_code));
ESP_LOGE(TAG, "Input transfer failed, status=%s", esp_err_to_name(status.error_code));
// On failure, don't restart - let next read_array() trigger it
channel->input_started_.store(false);
return;
@@ -263,8 +269,9 @@ void USBUartComponent::start_input(USBUartChannel *channel) {
channel->input_started_.store(false);
this->start_input(channel);
};
channel->input_started_.store(true);
this->transfer_in(ep->bEndpointAddress, callback, ep->wMaxPacketSize);
if (!this->transfer_in(ep->bEndpointAddress, callback, ep->wMaxPacketSize)) {
channel->input_started_.store(false);
}
}
void USBUartComponent::start_output(USBUartChannel *channel) {
@@ -357,11 +364,12 @@ void USBUartTypeCdcAcm::on_disconnected() {
usb_host_endpoint_flush(this->device_handle_, channel->cdc_dev_.notify_ep->bEndpointAddress);
}
usb_host_interface_release(this->handle_, this->device_handle_, channel->cdc_dev_.bulk_interface_number);
channel->initialised_.store(false);
channel->input_started_.store(false);
channel->output_started_.store(false);
// Reset the input and output started flags to their initial state to avoid the possibility of spurious restarts
channel->input_started_.store(true);
channel->output_started_.store(true);
channel->input_buffer_.clear();
channel->output_buffer_.clear();
channel->initialised_.store(false);
}
USBClient::on_disconnected();
}