From 0ae055f34bc133c80a02553411cd626417313a57 Mon Sep 17 00:00:00 2001 From: Felipe Moura Date: Thu, 3 Sep 2026 12:15:17 -0300 Subject: [PATCH] xtensa/esp32s3: Fix CONSOLE_DEV clobbered by USBSERIAL macro. When a real UART (CONFIG_UARTx_SERIAL_CONSOLE) is selected as the system console while CONFIG_ESP32S3_USBSERIAL is also enabled (e.g. to keep /dev/ttyACM0 available as a secondary device alongside an external console UART), the unconditional #ifdef CONFIG_ESP32S3_USBSERIAL # define CONSOLE_DEV g_uart_usbserial #endif block silently redefines CONSOLE_DEV, clobbering the correct earlier definition that pointed it at the chosen UART device. Confirmed on real hardware (Seeed XIAO ESP32-S3): with UART0 selected as console and USBSERIAL also enabled, the board boot-looped on RTCWDT_RTC_RST every ~8s, never reaching NSH. With this fix, NSH comes up normally over UART0 and /dev/ttyACM0 remains available. Signed-off-by: Felipe Moura Assisted-by: Claude:claude-sonnet-5 --- arch/xtensa/src/esp32s3/esp32s3_serial.c | 284 ++++++++++++----------- 1 file changed, 145 insertions(+), 139 deletions(-) diff --git a/arch/xtensa/src/esp32s3/esp32s3_serial.c b/arch/xtensa/src/esp32s3/esp32s3_serial.c index 11d4b3f71c11b..33d23f2251e3f 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_serial.c +++ b/arch/xtensa/src/esp32s3/esp32s3_serial.c @@ -101,8 +101,11 @@ # endif #endif /* CONSOLE_UART */ -#ifdef CONFIG_ESP32S3_USBSERIAL +#if defined(CONFIG_ESP32S3_USBSERIAL) && !defined(CONSOLE_DEV) # define CONSOLE_DEV g_uart_usbserial +#endif + +#ifdef CONFIG_ESP32S3_USBSERIAL # define TTYACM0_DEV g_uart_usbserial #endif @@ -855,194 +858,196 @@ static int esp32s3_ioctl(struct file *filep, int cmd, unsigned long arg) { #ifdef CONFIG_SERIAL_TIOCSERGSTRUCT - /* Get the internal driver data structure for debug purposes. */ - - case TIOCSERGSTRUCT: - { - struct esp32s3_uart_s *user = (struct esp32s3_uart_s *)arg; - if (user == NULL) - { - ret = -EINVAL; - } - else - { - memcpy(user, dev->priv, sizeof(struct esp32s3_uart_s)); - } - } - break; + /* Get the internal driver data structure for debug purposes. */ + + case TIOCSERGSTRUCT: + { + struct esp32s3_uart_s *user = (struct esp32s3_uart_s *)arg; + + if (user == NULL) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev->priv, sizeof(struct esp32s3_uart_s)); + } + } + break; #endif #ifdef CONFIG_SERIAL_TERMIOS - /* Fill a termios structure with the required information. */ + /* Fill a termios structure with the required information. */ + + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct esp32s3_uart_s *priv = (struct esp32s3_uart_s *)dev->priv; - case TCGETS: - { - struct termios *termiosp = (struct termios *)arg; - struct esp32s3_uart_s *priv = (struct esp32s3_uart_s *)dev->priv; - if (termiosp == NULL) - { - ret = -EINVAL; - break; - } + if (termiosp == NULL) + { + ret = -EINVAL; + break; + } - /* Return parity (0 = no parity, 1 = odd parity, 2 = even parity). */ + /* Return parity (0 = no, 1 = odd, 2 = even). */ - termiosp->c_cflag = (priv->parity != 0 ? PARENB : 0) | - (priv->parity == 1 ? PARODD : 0); + termiosp->c_cflag = (priv->parity != 0 ? PARENB : 0) | + (priv->parity == 1 ? PARODD : 0); - /* Return stop bits */ + /* Return stop bits */ - termiosp->c_cflag |= priv->stop_b2 != 0 ? CSTOPB : 0; + termiosp->c_cflag |= priv->stop_b2 != 0 ? CSTOPB : 0; #ifdef CONFIG_SERIAL_OFLOWCONTROL - termiosp->c_cflag |= priv->oflow != 0 ? CCTS_OFLOW : 0; + termiosp->c_cflag |= priv->oflow != 0 ? CCTS_OFLOW : 0; #endif #ifdef CONFIG_SERIAL_IFLOWCONTROL - termiosp->c_cflag |= priv->iflow != 0 ? CRTS_IFLOW : 0; + termiosp->c_cflag |= priv->iflow != 0 ? CRTS_IFLOW : 0; #endif - /* Set the baud rate in the termiosp using the - * cfsetispeed interface. - */ - - cfsetispeed(termiosp, priv->baud); - - /* Return number of bits. */ - - switch (priv->bits) - { - case 5: - termiosp->c_cflag |= CS5; - break; - - case 6: - termiosp->c_cflag |= CS6; - break; - - case 7: - termiosp->c_cflag |= CS7; - break; - - default: - case 8: - termiosp->c_cflag |= CS8; - break; - } - } - break; - - case TCSETS: - { - struct termios *termiosp = (struct termios *)arg; - struct esp32s3_uart_s *priv = (struct esp32s3_uart_s *)dev->priv; - uint32_t baud; - uint32_t current_int_sts; - uint8_t parity; - uint8_t bits; - uint8_t stop2; + /* Set the baud rate in the termiosp using the + * cfsetispeed interface. + */ + + cfsetispeed(termiosp, priv->baud); + + /* Return number of bits. */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct esp32s3_uart_s *priv = (struct esp32s3_uart_s *)dev->priv; + uint32_t baud; + uint32_t current_int_sts; + uint8_t parity; + uint8_t bits; + uint8_t stop2; #ifdef CONFIG_SERIAL_IFLOWCONTROL - bool iflow; + bool iflow; #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - bool oflow; + bool oflow; #endif - if (termiosp == NULL) - { - ret = -EINVAL; - break; - } + if (termiosp == NULL) + { + ret = -EINVAL; + break; + } - /* Get the target baud rate to change. */ + /* Get the target baud rate to change. */ - baud = cfgetispeed(termiosp); + baud = cfgetispeed(termiosp); - /* Decode number of bits. */ + /* Decode number of bits. */ - switch (termiosp->c_cflag & CSIZE) - { - case CS5: - bits = 5; - break; + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + bits = 5; + break; - case CS6: - bits = 6; - break; + case CS6: + bits = 6; + break; - case CS7: - bits = 7; - break; + case CS7: + bits = 7; + break; - case CS8: - bits = 8; - break; + case CS8: + bits = 8; + break; - default: - ret = -EINVAL; - break; - } + default: + ret = -EINVAL; + break; + } - /* Decode parity. */ + /* Decode parity. */ - if ((termiosp->c_cflag & PARENB) != 0) - { - parity = (termiosp->c_cflag & PARODD) != 0 ? 1 : 2; - } - else - { - parity = 0; - } + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) != 0 ? 1 : 2; + } + else + { + parity = 0; + } - /* Decode stop bits. */ + /* Decode stop bits. */ - stop2 = (termiosp->c_cflag & CSTOPB) != 0 ? 1 : 0; + stop2 = (termiosp->c_cflag & CSTOPB) != 0 ? 1 : 0; #ifdef CONFIG_SERIAL_IFLOWCONTROL - iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; + iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; + oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; #endif - /* Verify that all settings are valid before - * performing the changes. - */ + /* Verify that all settings are valid before + * performing the changes. + */ - if (ret == OK) - { - /* Fill the private struct fields. */ + if (ret == OK) + { + /* Fill the private struct fields. */ - priv->baud = baud; - priv->parity = parity; - priv->bits = bits; - priv->stop_b2 = stop2; + priv->baud = baud; + priv->parity = parity; + priv->bits = bits; + priv->stop_b2 = stop2; #ifdef CONFIG_SERIAL_IFLOWCONTROL - priv->iflow = iflow; + priv->iflow = iflow; #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - priv->oflow = oflow; + priv->oflow = oflow; #endif - /* Effect the changes immediately - note that we do not - * implement TCSADRAIN or TCSAFLUSH, only TCSANOW option. - * See nuttx/libs/libc/termios/lib_tcsetattr.c - */ + /* Effect the changes immediately - note that we do not + * implement TCSADRAIN or TCSAFLUSH, only TCSANOW option. + * See nuttx/libs/libc/termios/lib_tcsetattr.c + */ - esp32s3_lowputc_disable_all_uart_int(priv, ¤t_int_sts); - ret = esp32s3_setup(dev); + esp32s3_lowputc_disable_all_uart_int(priv, ¤t_int_sts); + ret = esp32s3_setup(dev); - /* Restore the interrupt state */ + /* Restore the interrupt state */ - esp32s3_lowputc_restore_all_uart_int(priv, ¤t_int_sts); - } - } - break; + esp32s3_lowputc_restore_all_uart_int(priv, ¤t_int_sts); + } + } + break; #endif /* CONFIG_SERIAL_TERMIOS */ - default: - ret = -ENOTTY; - break; + default: + ret = -ENOTTY; + break; } return ret; @@ -1086,6 +1091,7 @@ static bool esp32s3_rxflowcontrol(struct uart_dev_s *dev, { bool ret = false; struct esp32s3_uart_s *priv = dev->priv; + if (priv->iflow) { if (nbuffered == 0 || upper == false)