* [PATCH 1/5] readkey: wait for the rest of an escape sequence
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
@ 2026-11-08 9:32 ` Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 2/5] lib: term: ask the terminal when a console can't tell its size Ahmad Fatoum
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2026-11-08 9:32 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Since commit 68d07f38e8e8 ("readkey: handle standalone ESC keypress
with timeout"), read_key() waits at most 50ms for each of the two
characters after an ESC. The gap after the ESC is what tells a bare ESC
from an escape sequence, but once the next character is a [ or an O,
the rest of the sequence is on its way. When it arrives later, e.g.
because it went into the next packet or the next batch of an emulator,
the ESC and the [ are dropped, and the line editor inserts the rest:
the up arrow types an A.
Wait for the rest of a sequence without a timeout, as read_key() did
before and still does for the digits in ESC [ 1 ~ and the like. Any
other character after an ESC can't start a sequence we know, so return
right away then instead of waiting for one more.
Fixes: 68d07f38e8e8 ("readkey: handle standalone ESC keypress with timeout")
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
lib/readkey.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/readkey.c b/lib/readkey.c
index 71f9b41c5055..fed2f70418b0 100644
--- a/lib/readkey.c
+++ b/lib/readkey.c
@@ -80,9 +80,11 @@ int read_key(void)
if (poll_key_into_buf(&esc[i++]))
return '\e';
- if (poll_key_into_buf(&esc[i++]))
+ if (esc[0] != '[' && esc[0] != 'O')
return -1;
+ esc[i++] = getchar();
+
if (isdigit(esc[1])) {
while(1) {
esc[i] = getchar();
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 2/5] lib: term: ask the terminal when a console can't tell its size
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 1/5] readkey: wait for the rest of an escape sequence Ahmad Fatoum
@ 2026-11-08 9:32 ` Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 3/5] serial: virtio_console: report the console size Ahmad Fatoum
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2026-11-08 9:32 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
term_cdev_get_size() returns whatever the get_size callback of a
console returns. A console may not always know its size, though: a
virtio console only does once the host has filled it in. Fall back to
querying the terminal when the callback fails, as for consoles without
one.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
lib/term.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/term.c b/lib/term.c
index 382250c70ddf..1322546ce8ac 100644
--- a/lib/term.c
+++ b/lib/term.c
@@ -82,8 +82,9 @@ int term_cdev_get_size(struct console_device *cdev,
if (!(cdev->f_active & CONSOLE_STDOUT))
return -ENOENT;
- if (cdev->get_size)
- return cdev->get_size(cdev, screenwidth, screenheight);
+ /* ask the terminal only if the console can't tell size */
+ if (cdev->get_size && !cdev->get_size(cdev, screenwidth, screenheight))
+ return 0;
if (!(cdev->f_active & CONSOLE_STDIN))
return -ENOENT;
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 3/5] serial: virtio_console: report the console size
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 1/5] readkey: wait for the rest of an escape sequence Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 2/5] lib: term: ask the terminal when a console can't tell its size Ahmad Fatoum
@ 2026-11-08 9:32 ` Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 4/5] console: give each console implementation its own console_ctrlc() Ahmad Fatoum
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2026-11-08 9:32 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Hosts that offer VIRTIO_CONSOLE_F_SIZE, like TinyEMU, keep the size of
their terminal in the config space. Implement get_size with it, so that
sedit and watch don't need to query the terminal and wait up to 100ms
for the reply. When the reply takes longer, as in the barebox web demo,
sedit gives up and the reply ends up in the edited file:
[24;80R#!/bin/sh
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
drivers/serial/virtio_console.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/serial/virtio_console.c b/drivers/serial/virtio_console.c
index ae36cad6e5bd..3d14bf502489 100644
--- a/drivers/serial/virtio_console.c
+++ b/drivers/serial/virtio_console.c
@@ -18,6 +18,7 @@
#include <xfuncs.h>
#include <linux/spinlock.h>
#include <linux/virtio.h>
+#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
#include <linux/virtio_console.h>
@@ -105,6 +106,24 @@ static int virtcons_getc(struct console_device *cdev)
return ch;
}
+static int virtcons_get_size(struct console_device *cdev, int *width, int *height)
+{
+ struct virtio_device *vdev = dev_to_virtio(cdev->dev);
+ u16 cols, rows;
+
+ virtio_cread(vdev, struct virtio_console_config, cols, &cols);
+ virtio_cread(vdev, struct virtio_console_config, rows, &rows);
+
+ /* the host may not have filled them in yet */
+ if (!cols || !rows)
+ return -ENODATA;
+
+ *width = cols;
+ *height = rows;
+
+ return 0;
+}
+
static int virtcons_probe(struct virtio_device *vdev)
{
struct virtqueue *vqs[2];
@@ -146,6 +165,8 @@ static int virtcons_probe(struct virtio_device *vdev)
virtcons->cdev.tstc = virtcons_tstc;
virtcons->cdev.getc = virtcons_getc;
virtcons->cdev.putc = virtcons_putc;
+ if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
+ virtcons->cdev.get_size = virtcons_get_size;
have_one = true;
@@ -168,9 +189,15 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
+static const unsigned int features[] = {
+ VIRTIO_CONSOLE_F_SIZE,
+};
+
static struct virtio_driver virtio_console = {
.driver.name = "virtio_console",
.id_table = id_table,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.probe = virtcons_probe,
.remove = virtcons_remove,
};
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 4/5] console: give each console implementation its own console_ctrlc()
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
` (2 preceding siblings ...)
2026-11-08 9:32 ` [PATCH 3/5] serial: virtio_console: report the console size Ahmad Fatoum
@ 2026-11-08 9:32 ` Ahmad Fatoum
2026-11-08 9:32 ` [PATCH 5/5] console: keep the keys typed ahead when checking for Ctrl-C Ahmad Fatoum
2026-11-09 9:50 ` [PATCH 0/5] console: escape sequence handling improvement Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2026-11-08 9:32 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
ctrlc_non_interruptible() reads the console input itself, inside an
ifdef for the architectures that bring their own check. Have the full
and the simple console each provide a console_ctrlc() for it instead,
so that they can check differently, and test CONFIG_ARCH_HAS_CTRLC with
IS_ENABLED().
No functional change.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
common/console.c | 10 ++++++++++
common/console_ctrlc.c | 10 ++++------
common/console_simple.c | 10 ++++++++++
include/console.h | 4 ++--
4 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/common/console.c b/common/console.c
index 0722af0a40fc..c57bb87b0114 100644
--- a/common/console.c
+++ b/common/console.c
@@ -605,6 +605,16 @@ int pollchar(ktime_t duration)
}
EXPORT_SYMBOL(pollchar);
+/**
+ * console_ctrlc - check the console input for a Ctrl-C
+ *
+ * Return: true if Ctrl-C was pressed
+ */
+bool console_ctrlc(void)
+{
+ return tstc() && getchar() == 3;
+}
+
int console_putc(struct console_device *con, char c)
{
bool crlf = c == '\n';
diff --git a/common/console_ctrlc.c b/common/console_ctrlc.c
index 6fbe07252eff..5c912841c694 100644
--- a/common/console_ctrlc.c
+++ b/common/console_ctrlc.c
@@ -28,12 +28,10 @@ int ctrlc_non_interruptible(void)
if (ctrlc_abort)
return 1;
-#ifdef CONFIG_ARCH_HAS_CTRLC
- ret = arch_ctrlc();
-#else
- if (tstc() && getchar() == 3)
- ret = 1;
-#endif
+ if (IS_ENABLED(CONFIG_ARCH_HAS_CTRLC))
+ ret = arch_ctrlc();
+ else
+ ret = console_ctrlc();
if (ret)
ctrlc_abort = 1;
diff --git a/common/console_simple.c b/common/console_simple.c
index 6771d457455e..97beec2d8d2e 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -80,6 +80,16 @@ int pollchar(ktime_t duration)
}
EXPORT_SYMBOL(pollchar);
+/**
+ * console_ctrlc - check the console input for a Ctrl-C
+ *
+ * Return: true if Ctrl-C was pressed
+ */
+bool console_ctrlc(void)
+{
+ return tstc() && getchar() == 3;
+}
+
void console_flush(void)
{
if (console && console->flush)
diff --git a/include/console.h b/include/console.h
index 4b2893d5c4df..6469802531d5 100644
--- a/include/console.h
+++ b/include/console.h
@@ -239,9 +239,7 @@ static inline int barebox_set_loglevel(int loglevel)
}
#endif
-#ifdef CONFIG_ARCH_HAS_CTRLC
int arch_ctrlc(void);
-#endif
#ifndef CONFIG_CONSOLE_NONE
/* stdout */
@@ -255,6 +253,7 @@ int console_vprintf(struct console_device *con, const char *fmt, va_list args);
int ctrlc(void);
int ctrlc_non_interruptible(void);
+bool console_ctrlc(void);
void ctrlc_handled(void);
void console_ctrlc_allow(void);
void console_ctrlc_forbid(void);
@@ -266,6 +265,7 @@ static inline void console_flush(void) {}
/* test if ctrl-c was pressed */
static inline int ctrlc (void) { return 0; }
static inline int ctrlc_non_interruptible(void) { return 0; }
+static inline bool console_ctrlc(void) { return false; }
static inline void ctrlc_handled(void) { }
static inline void console_ctrlc_allow(void) { }
static inline void console_ctrlc_forbid(void) { }
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 5/5] console: keep the keys typed ahead when checking for Ctrl-C
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
` (3 preceding siblings ...)
2026-11-08 9:32 ` [PATCH 4/5] console: give each console implementation its own console_ctrlc() Ahmad Fatoum
@ 2026-11-08 9:32 ` Ahmad Fatoum
2026-11-09 9:50 ` [PATCH 0/5] console: escape sequence handling improvement Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Ahmad Fatoum @ 2026-11-08 9:32 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
ctrlc() reads a character to see whether it is a Ctrl-C and throws it
away if it isn't. Commands like sleep call it in a loop, so whatever is
typed while they run is lost.
For the full console, move the pending input into the input FIFO
instead and look for a Ctrl-C there, leaving everything else for the
next reader. As on a tty, a Ctrl-C discards all of the queued input.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
common/console.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/common/console.c b/common/console.c
index c57bb87b0114..b4ff7ca30f29 100644
--- a/common/console.c
+++ b/common/console.c
@@ -20,6 +20,7 @@
#include <module.h>
#include <sched.h>
#include <ratp_bb.h>
+#include <readkey.h>
#include <magicvar.h>
#include <globalvar.h>
#include <linux/list.h>
@@ -608,11 +609,35 @@ EXPORT_SYMBOL(pollchar);
/**
* console_ctrlc - check the console input for a Ctrl-C
*
+ * Unlike reading the input with getchar(), this keeps all other characters
+ * queued, so that keys typed while a command runs aren't lost. As on a tty,
+ * a Ctrl-C discards all queued input.
+ *
* Return: true if Ctrl-C was pressed
*/
bool console_ctrlc(void)
{
- return tstc() && getchar() == 3;
+ struct kfifo *fifo = console_input_fifo;
+ unsigned int i;
+
+ while (tstc_raw()) {
+ int c = getc_raw();
+
+ if (c < 0)
+ break;
+
+ kfifo_putc(fifo, c);
+ }
+
+ /* Check full FIFO: earlier getchar() may also have queued a Ctrl-C */
+ for (i = fifo->out; i != fifo->in; i++) {
+ if (fifo->buffer[i & (fifo->size - 1)] == CTL_CH('c')) {
+ kfifo_reset(fifo);
+ return true;
+ }
+ }
+
+ return false;
}
int console_putc(struct console_device *con, char c)
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH 0/5] console: escape sequence handling improvement
2026-11-08 9:32 [PATCH 0/5] console: escape sequence handling improvement Ahmad Fatoum
` (4 preceding siblings ...)
2026-11-08 9:32 ` [PATCH 5/5] console: keep the keys typed ahead when checking for Ctrl-C Ahmad Fatoum
@ 2026-11-09 9:50 ` Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2026-11-09 9:50 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Sun, 08 Nov 2026 10:32:02 +0100, Ahmad Fatoum wrote:
> The v2026.07.0 update broke arrow key usage in the web demo for some
> users. Proper fix is on the riscvemu side, but there's still some things
> we can do at the barebox side to make escape sequence handling more
> robust.
>
> Ahmad Fatoum (5):
> readkey: wait for the rest of an escape sequence
> lib: term: ask the terminal when a console can't tell its size
> serial: virtio_console: report the console size
> console: give each console implementation its own console_ctrlc()
> console: keep the keys typed ahead when checking for Ctrl-C
>
> [...]
Applied, thanks!
[1/5] readkey: wait for the rest of an escape sequence
https://git.pengutronix.de/cgit/barebox/commit/?id=817a1128a2a7 (link may not be stable)
[2/5] lib: term: ask the terminal when a console can't tell its size
https://git.pengutronix.de/cgit/barebox/commit/?id=d4f6a1c064ee (link may not be stable)
[3/5] serial: virtio_console: report the console size
https://git.pengutronix.de/cgit/barebox/commit/?id=05234d4bd72b (link may not be stable)
[4/5] console: give each console implementation its own console_ctrlc()
https://git.pengutronix.de/cgit/barebox/commit/?id=39276e6d6023 (link may not be stable)
[5/5] console: keep the keys typed ahead when checking for Ctrl-C
https://git.pengutronix.de/cgit/barebox/commit/?id=961f0d11ac4d (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 7+ messages in thread