From e36445fa5feb4db65586186ec823a225339b8885 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sat, 5 Sep 2026 06:00:25 -0500 Subject: [PATCH] [usb_uart] Keep the comm interface number valid when its claim fails (#18968) --- esphome/components/usb_uart/usb_uart.cpp | 12 +++++++----- esphome/components/usb_uart/usb_uart.h | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/esphome/components/usb_uart/usb_uart.cpp b/esphome/components/usb_uart/usb_uart.cpp index cf66e4c369..60b7fe4e9c 100644 --- a/esphome/components/usb_uart/usb_uart.cpp +++ b/esphome/components/usb_uart/usb_uart.cpp @@ -434,11 +434,12 @@ void USBUartTypeCdcAcm::on_connected() { auto err_comm = usb_host_interface_claim(this->handle_, this->device_handle_, channel->cdc_dev_.interrupt_interface_number, 0); if (err_comm != ESP_OK) { + // Continue anyway: the interface number stays valid for CDC request addressing ESP_LOGW(TAG, "Could not claim comm interface %d: %s", channel->cdc_dev_.interrupt_interface_number, esp_err_to_name(err_comm)); - channel->cdc_dev_.interrupt_interface_number = 0xFF; // Mark as unavailable, but continue anyway } else { ESP_LOGD(TAG, "Claimed comm interface %d", channel->cdc_dev_.interrupt_interface_number); + channel->cdc_dev_.interrupt_interface_claimed = true; } } auto err = @@ -465,14 +466,15 @@ void USBUartTypeCdcAcm::on_disconnected() { usb_host_endpoint_halt(this->device_handle_, channel->cdc_dev_.out_ep->bEndpointAddress); usb_host_endpoint_flush(this->device_handle_, channel->cdc_dev_.out_ep->bEndpointAddress); } - if (channel->cdc_dev_.notify_ep != nullptr) { + // Only tear down the notify pipe when we claimed its interface ourselves; + // no transfer is ever submitted on it, so there is nothing else to cancel. + if (channel->cdc_dev_.notify_ep != nullptr && channel->cdc_dev_.interrupt_interface_claimed) { usb_host_endpoint_halt(this->device_handle_, channel->cdc_dev_.notify_ep->bEndpointAddress); usb_host_endpoint_flush(this->device_handle_, channel->cdc_dev_.notify_ep->bEndpointAddress); } - if (channel->cdc_dev_.interrupt_interface_number != 0xFF && - channel->cdc_dev_.interrupt_interface_number != channel->cdc_dev_.bulk_interface_number) { + if (channel->cdc_dev_.interrupt_interface_claimed) { usb_host_interface_release(this->handle_, this->device_handle_, channel->cdc_dev_.interrupt_interface_number); - channel->cdc_dev_.interrupt_interface_number = 0xFF; + channel->cdc_dev_.interrupt_interface_claimed = false; } usb_host_interface_release(this->handle_, this->device_handle_, channel->cdc_dev_.bulk_interface_number); // Reset the input and output started flags to their initial state to avoid the possibility of spurious restarts diff --git a/esphome/components/usb_uart/usb_uart.h b/esphome/components/usb_uart/usb_uart.h index 00b34fb942..9d87bf964c 100644 --- a/esphome/components/usb_uart/usb_uart.h +++ b/esphome/components/usb_uart/usb_uart.h @@ -34,7 +34,10 @@ struct CdcEps { const usb_ep_desc_t *in_ep; const usb_ep_desc_t *out_ep; uint8_t bulk_interface_number; + // Also the wIndex target for CDC class requests (SET_LINE_CODING etc.), so it + // must remain valid even when the interface itself is not claimed. uint8_t interrupt_interface_number; + bool interrupt_interface_claimed{false}; }; enum CH34xChipType : uint8_t {