Skip to content

Commit e860885

Browse files
committed
fix: replay framebuffer content across USB reconnects
1 parent b6e868b commit e860885

4 files changed

Lines changed: 27 additions & 25 deletions

File tree

‎docs/architecture.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ structure sizes and an ABI version so fields can be appended without forcing
4848
unrelated backends to change.
4949

5050
Backends may request a periodic `tick` callback. This keeps control traffic
51-
alive even when fbdev or DRM has not published a new frame.
51+
alive even when fbdev or DRM has not published a new frame. Physical backends
52+
never replace the current framebuffer image with a daemon splash during
53+
reconnect; the latest fbdev snapshot is replayed when the stream is reopened.
5254

5355
The daemon publishes a readiness file after the backend opens. The file carries
5456
the live daemon PID, a positive transport `generation`, and `physical=1` only

‎kernel/usbdisplay_drv.c‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,8 @@ static void usbdisplay_producer_opened(struct usbdisplay_device *udev)
266266

267267
static void usbdisplay_producer_closed(struct usbdisplay_device *udev)
268268
{
269-
if (atomic_dec_and_test(&udev->producer_open)) {
270-
usbdisplay_publish_initial(udev);
271-
}
269+
/* Keep the last fbdev snapshot for a reconnecting transport. */
270+
(void)atomic_dec_and_test(&udev->producer_open);
272271
}
273272

274273
static int usbdisplay_fbdev_open(struct fb_info *info, int user)

‎packaging/usb-displayd.service‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[Unit]
22
Description=USBDisplayStack frame transport daemon
33
After=systemd-modules-load.service
4-
ConditionPathExists=/dev/usbdisplay0
54

65
[Service]
76
Type=simple

‎userspace/usb-displayd.c‎

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,9 @@ static int validate_update(const struct usbdisplay_device_info *info,
269269
}
270270

271271
static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
272-
const void *mapping,
273-
const struct usbdisplay_backend_v1 *backend,
274-
void *backend_context)
272+
const void *mapping,
273+
const struct usbdisplay_backend_v1 *backend,
274+
void *backend_context)
275275
{
276276
struct pollfd descriptor;
277277
struct usbdisplay_update update;
@@ -281,21 +281,25 @@ static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
281281
uint64_t now_ns = 0;
282282
uint64_t last_submit_ns = 0;
283283
uint32_t *splash_pixels = NULL;
284-
size_t splash_bytes;
284+
size_t splash_bytes = 0;
285285
bool frame_valid = false;
286+
bool physical_backend = (backend->capabilities &
287+
USBDISPLAY_BACKEND_CAP_PHYSICAL) != 0;
286288
int result = 0;
287289

288-
/* INITIAL 只表示当前没有业务生产者,守护进程在实体链路就绪后替换为状态页。 */
289-
splash_bytes = usbdisplay_splash_bytes(info->width, info->height);
290-
if (splash_bytes == 0) {
291-
result = -EOVERFLOW;
292-
} else {
293-
splash_pixels = malloc(splash_bytes);
294-
if (splash_pixels == NULL) {
295-
result = -ENOMEM;
290+
/* Physical output must preserve the current fb1 image during reconnects. */
291+
if (!physical_backend) {
292+
splash_bytes = usbdisplay_splash_bytes(info->width, info->height);
293+
if (splash_bytes == 0) {
294+
result = -EOVERFLOW;
296295
} else {
297-
result = usbdisplay_splash_render(splash_pixels, info->width,
298-
info->height, info->width * 4U);
296+
splash_pixels = malloc(splash_bytes);
297+
if (splash_pixels == NULL) {
298+
result = -ENOMEM;
299+
} else {
300+
result = usbdisplay_splash_render(splash_pixels, info->width,
301+
info->height, info->width * 4U);
302+
}
299303
}
300304
}
301305
descriptor.fd = device_fd;
@@ -317,7 +321,9 @@ static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
317321
result = -EPROTO;
318322
} else {
319323
result = validate_update(info, &update);
320-
if (result == 0) {
324+
if (result == 0 &&
325+
(update.source != USBDISPLAY_SOURCE_INITIAL ||
326+
!physical_backend)) {
321327
memset(&frame, 0, sizeof(frame));
322328
frame.struct_size = sizeof(frame);
323329
if (update.source == USBDISPLAY_SOURCE_INITIAL) {
@@ -357,9 +363,7 @@ static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
357363
result = -EIO;
358364
}
359365
now_ns = monotonic_nanoseconds();
360-
/* 静止界面也每两秒重交最新帧,避免固件因长期无视频退回等待页。 */
361-
if (result == 0 && frame_valid &&
362-
(backend->capabilities & USBDISPLAY_BACKEND_CAP_PHYSICAL) != 0 &&
366+
if (result == 0 && frame_valid && physical_backend &&
363367
now_ns >= last_submit_ns &&
364368
now_ns - last_submit_ns >= IDLE_FRAME_REFRESH_NS) {
365369
result = backend->submit(backend_context, &frame);
@@ -371,7 +375,6 @@ static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
371375
(backend->capabilities & USBDISPLAY_BACKEND_CAP_TICK) != 0 &&
372376
backend->struct_size >= USBDISPLAY_BACKEND_V1_TICK_SIZE &&
373377
backend->tick != NULL) {
374-
/* submit 可能发送心跳,tick 必须使用提交完成后的时间记录设备响应。 */
375378
now_ns = monotonic_nanoseconds();
376379
result = backend->tick(backend_context, now_ns);
377380
}
@@ -380,7 +383,6 @@ static int run_loop(int device_fd, const struct usbdisplay_device_info *info,
380383

381384
return result;
382385
}
383-
384386
int main(int argc, char **argv)
385387
{
386388
const char *device_path;

0 commit comments

Comments
 (0)