[PATCH v4 2/2] platform/x86: dell-uart-backlight: recover from stray EC response byte

From: chitranshmandhaniya

Date: Sat Oct 17 2026 - 03:38:46 EST


From: Chitransh Mandhaniya <Chitransh_Mandhaniya@xxxxxxxx>

On some Dell All-in-One machines the EC occasionally inserts a spurious
byte after the command echo in UART backlight response frames. For
example a get-brightness reply that should be "04 0c 0a e5" arrives as
"04 0c 0d 0a e5". The length field still reflects the original frame
size, so the parser treats the stray byte as payload and the real
payload as the checksum, producing a spurious -EIO.

Add single-attempt recovery inside dell_uart_bl_receive_data(): on a
checksum mismatch for a frame longer than the minimum size, drop the
byte at the first payload offset, shift the remaining data down by one,
and decrement resp_idx so serdev re-delivers the real checksum byte on
the next callback. Status remains -EBUSY, so no special handling is
needed in the caller.

A per-transaction resync_used flag, cleared at the start of each
command, limits recovery to one attempt. A second mismatch is a hard
-EIO. Well-formed frames never enter the recovery path.

Tested on Dell OptiPlex AIO 7410 65W (board 0TKWC4) where the EC
inserts a stray byte on every get-brightness response.

Signed-off-by: Chitransh Mandhaniya <Chitransh_Mandhaniya@xxxxxxxx>
---
drivers/platform/x86/dell/dell-uart-backlight.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/platform/x86/dell/dell-uart-backlight.c b/drivers/platform/x86/dell/dell-uart-backlight.c
index 5f01ad108338..1243c191c5b0 100644
--- a/drivers/platform/x86/dell/dell-uart-backlight.c
+++ b/drivers/platform/x86/dell/dell-uart-backlight.c
@@ -60,6 +60,7 @@ struct dell_uart_backlight {
u8 resp_len;
u8 resp_max_len;
u8 pending_cmd;
+ bool resync_used;
int status;
int power;
};
@@ -91,6 +92,7 @@ static int dell_uart_bl_command(struct dell_uart_backlight *dell_bl,
dell_bl->resp_len = -1; /* Invalid / unset */
dell_bl->resp_max_len = resp_max_len;
dell_bl->pending_cmd = cmd[1];
+ dell_bl->resync_used = false;

/* The TTY buffer should be big enough to take the entire cmd in one go */
ret = serdev_device_write_buf(to_serdev_device(dell_bl->dev), cmd, cmd_len);
@@ -245,6 +247,14 @@ static size_t dell_uart_bl_receive_data(struct dell_uart_backlight *dell_bl,
csum = dell_uart_checksum(dell_bl->resp, dell_bl->resp_len - 1);
if (dell_bl->resp[dell_bl->resp_len - 1] == csum) {
dell_bl->status = 0; /* Success */
+ } else if (!dell_bl->resync_used && dell_bl->resp_len > MIN_RESP_LEN) {
+ /* Stray byte after cmd-echo? Drop it, let serdev re-deliver checksum. */
+ dell_bl->resync_used = true;
+ dev_dbg(dell_bl->dev, "Resync: dropping stray byte 0x%02x at offset %d\n",
+ dell_bl->resp[RESP_DATA], RESP_DATA);
+ memmove(&dell_bl->resp[RESP_DATA], &dell_bl->resp[RESP_DATA + 1],
+ dell_bl->resp_len - RESP_DATA - 1);
+ dell_bl->resp_idx = dell_bl->resp_len - 1;
} else {
dev_err(dell_bl->dev, "Checksum mismatch got 0x%02x expected 0x%02x\n",
dell_bl->resp[dell_bl->resp_len - 1], csum);
--
2.43.0