[PATCH v2 1/1] serial: core: Don't clobber the baud rate on hangup via B0
From: Maciej W. Rozycki
Date: Sun Oct 11 2026 - 21:59:22 EST
Requesting hangup via the B0 baud rate has this nasty side effect of
clobbering the previously set rate for the port unless it happens to be
9600bps or the port minimum rate if higher. Consequently if there's a
consumer still active at the other end, then it receives garbled data
from any other producers outputting messages to the port, such as
init(8) or the kernel console.
There doesn't appear to be any particular reason for this clobbering
other than that we have been doing it since 2.1.131, so take a saner
approach and keep track of the most recently set baud rate and then use
it whenever hangup has been requested.
Signed-off-by: Maciej W. Rozycki <macro@xxxxxxxxxxx>
---
Changes from v1,
<https://lore.kernel.org/r/alpine.DEB.2.21.2605242242330.1450@xxxxxxxxxxxxxxxxx/>:
- Cache the most recently set actual baud rate in port->hup_speed and use
it whenever the B0 rate has been requested since the old termios may be
NULL or have the B0 rate recorded.
---
drivers/tty/serial/serial_core.c | 16 +++++++++-------
include/linux/serial_core.h | 1 +
2 files changed, 10 insertions(+), 7 deletions(-)
linux-serial-uart-get-baud-rate-hup.diff
Index: linux-macro/drivers/tty/serial/serial_core.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/serial_core.c
+++ linux-macro/drivers/tty/serial/serial_core.c
@@ -461,15 +461,15 @@ EXPORT_SYMBOL(uart_update_timeout);
* @max: maximum acceptable baud rate
*
* Decode the termios structure into a numeric baud rate, taking account of the
- * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600
- * baud or min argument, whichever is greater.
+ * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to the
+ * previously used rate provided by @port.
*
* If the new baud rate is invalid, try the @old termios setting. If it's still
* invalid, clip to the nearest chip supported rate.
*
- * The @termios structure is updated to reflect the baud rate we're actually
- * going to be using. Don't do this for the case where B0 is requested ("hang
- * up").
+ * The @termios and @port structures are updated to reflect the baud rate
+ * we're actually going to be using. Don't do this for the case where %B0
+ * is requested ("hang up").
*
* Locking: caller dependent
*/
@@ -514,10 +514,12 @@ uart_get_baud_rate(struct uart_port *por
* Special case: B0 rate.
*/
if (baud == 0)
- return max(min, 9600);
+ return port->hup_speed;
- if (baud >= min && baud <= max)
+ if (baud >= min && baud <= max) {
+ port->hup_speed = baud;
return baud;
+ }
/*
* If the range cannot be met then try again with
Index: linux-macro/include/linux/serial_core.h
===================================================================
--- linux-macro.orig/include/linux/serial_core.h
+++ linux-macro/include/linux/serial_core.h
@@ -569,6 +569,7 @@ struct uart_port {
bool hw_stopped; /* sw-assisted CTS flow state */
bool cons_flow; /* user specified console flow control */
+ speed_t hup_speed; /* speed to use for B0 rate (hang-up) */
unsigned int mctrl; /* current modem ctrl settings */
unsigned int frame_time; /* frame timing in ns */
unsigned int type; /* port type */