From 8aaa706a8b206c97fdb36607a56011fed148dd9d Mon Sep 17 00:00:00 2001 From: Jaeyeong Lee Date: Sat, 29 Aug 2026 20:48:24 +0900 Subject: [PATCH 1/2] fix[usb]: stop aliasing rt_ringbuffer as rt_serial_rx_fifo in VCOM With RT_USB_DEVICE_CDC and RT_USING_SERIAL_V2 both enabled, _function_enable assigned the embedded rx_ringbuffer to serial.serial_rx. Serial V2 reads that pointer as a struct rt_serial_rx_fifo, whose first member is a rt_ringbuffer, so ring-buffer access happened to work while rx_cpt, rx_cpt_index and rx_timeout landed on the following members of struct vcom, corrupting tx_rbp. The layout shifts again with RT_SERIAL_USING_DMA, which inserts dma_ping_rb ahead of those fields. Serial V2 already owns the receive FIFO: dev_serial_v2.c allocates it with rt_malloc on open and releases it with rt_free on close, so the assignment also made rt_free run on memory inside struct vcom. Drop the assignment and read the FIFO Serial V2 owns. rt_hw_serial_isr reports RX_IND from serial_rx->rb, so the endpoint handler now fills that ring buffer and _vcom_getc drains it. The Serial V1 path is unchanged. Fixes #11739 Signed-off-by: Jaeyeong Lee --- .../legacy/usb/usbdevice/class/cdc_vcom.c | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/components/legacy/usb/usbdevice/class/cdc_vcom.c b/components/legacy/usb/usbdevice/class/cdc_vcom.c index 44f013f005ef..7d4463ea89ff 100644 --- a/components/legacy/usb/usbdevice/class/cdc_vcom.c +++ b/components/legacy/usb/usbdevice/class/cdc_vcom.c @@ -338,6 +338,9 @@ static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) { rt_base_t level; struct vcom *data; +#ifdef RT_USING_SERIAL_V2 + struct rt_serial_rx_fifo *rx_fifo; +#endif RT_ASSERT(func != RT_NULL); @@ -351,7 +354,15 @@ static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) /* receive data from USB VCOM */ level = rt_hw_interrupt_disable(); +#ifdef RT_USING_SERIAL_V2 + rx_fifo = (struct rt_serial_rx_fifo *)data->serial.serial_rx; + if (rx_fifo != RT_NULL) + { + rt_ringbuffer_put(&rx_fifo->rb, data->ep_out->buffer, size); + } +#else rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size); +#endif rt_hw_interrupt_enable(level); /* notify receive data */ @@ -514,10 +525,6 @@ static rt_err_t _function_enable(ufunction_t func) data->ep_out->buffer = rt_malloc(CDC_RX_BUFSIZE); RT_ASSERT(data->ep_out->buffer != RT_NULL); -#ifdef RT_USING_SERIAL_V2 - data->serial.serial_rx = &data->rx_ringbuffer; -#endif - data->ep_out->request.buffer = data->ep_out->buffer; data->ep_out->request.size = EP_MAXPACKET(data->ep_out); @@ -719,18 +726,30 @@ static int _vcom_getc(struct rt_serial_device *serial) rt_base_t level; struct ufunction *func; struct vcom *data; +#ifdef RT_USING_SERIAL_V2 + struct rt_serial_rx_fifo *rx_fifo; +#endif func = (struct ufunction*)serial->parent.user_data; data = (struct vcom*)func->user_data; + RT_UNUSED(data); result = -1; level = rt_hw_interrupt_disable(); +#ifdef RT_USING_SERIAL_V2 + rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + if(rx_fifo != RT_NULL && rt_ringbuffer_getchar(&rx_fifo->rb, &ch) != 0) + { + result = ch; + } +#else if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) { result = ch; } +#endif rt_hw_interrupt_enable(level); From ec20f9f29878afd0df27a5ffac4bbe0c41a4e025 Mon Sep 17 00:00:00 2001 From: Jaeyeong Lee Date: Sat, 12 Sep 2026 08:56:47 +0900 Subject: [PATCH 2/2] fix[usb]: support VCOM polling receive with Serial V2 Signed-off-by: Jaeyeong Lee --- .../legacy/usb/usbdevice/class/cdc_vcom.c | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/components/legacy/usb/usbdevice/class/cdc_vcom.c b/components/legacy/usb/usbdevice/class/cdc_vcom.c index 7d4463ea89ff..e99013ce395b 100644 --- a/components/legacy/usb/usbdevice/class/cdc_vcom.c +++ b/components/legacy/usb/usbdevice/class/cdc_vcom.c @@ -337,6 +337,7 @@ static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size) static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) { rt_base_t level; + rt_bool_t notify_rx = RT_FALSE; struct vcom *data; #ifdef RT_USING_SERIAL_V2 struct rt_serial_rx_fifo *rx_fifo; @@ -355,18 +356,30 @@ static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) level = rt_hw_interrupt_disable(); #ifdef RT_USING_SERIAL_V2 - rx_fifo = (struct rt_serial_rx_fifo *)data->serial.serial_rx; - if (rx_fifo != RT_NULL) + if (data->serial.config.rx_bufsz == 0) { - rt_ringbuffer_put(&rx_fifo->rb, data->ep_out->buffer, size); + rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size); + } + else + { + rx_fifo = (struct rt_serial_rx_fifo *)data->serial.serial_rx; + if (rx_fifo != RT_NULL) + { + rt_ringbuffer_put(&rx_fifo->rb, data->ep_out->buffer, size); + notify_rx = RT_TRUE; + } } #else rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size); + notify_rx = RT_TRUE; #endif rt_hw_interrupt_enable(level); /* notify receive data */ - rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_RX_IND); + if (notify_rx) + { + rt_hw_serial_isr(&data->serial, RT_SERIAL_EVENT_RX_IND); + } } data->ep_out->request.buffer = data->ep_out->buffer; @@ -732,20 +745,29 @@ static int _vcom_getc(struct rt_serial_device *serial) func = (struct ufunction*)serial->parent.user_data; data = (struct vcom*)func->user_data; - RT_UNUSED(data); result = -1; level = rt_hw_interrupt_disable(); #ifdef RT_USING_SERIAL_V2 - rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; - if(rx_fifo != RT_NULL && rt_ringbuffer_getchar(&rx_fifo->rb, &ch) != 0) + if (serial->config.rx_bufsz == 0) { - result = ch; + if (rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) + { + result = ch; + } + } + else + { + rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + if (rx_fifo != RT_NULL && rt_ringbuffer_getchar(&rx_fifo->rb, &ch) != 0) + { + result = ch; + } } #else - if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) + if (rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) { result = ch; }