Phase 8.2: kernel ↔ daemon chardev bridge with round-trip test
Adds /dev/daedalus-v4l2 misc chardev to the kernel module. The
chardev is the IPC channel for the future userspace decoder
daemon: kernel enqueues REQ_* messages, daemon read()s them,
processes, write()s RESP_* back.
Wire protocol (pre-1.0, header in include/daedalus_v4l2_proto.h):
- struct daedalus_msg_hdr: magic (D04V) + version + type +
cookie + payload_len + reserved
- Request/response separated by high bit of type field
- Max 64 KiB payload per message
- Cookie correlates request with matching response
Kernel implementation (kernel/daedalus_v4l2_chardev.{c,h}):
- Single-instance chardev (-EBUSY on second open)
- In-kernel FIFO bounded at 64 messages
- Blocking + non-blocking read; poll() with EPOLLIN on queued
- write() parses + validates header, logs response at pr_debug
- Bad magic → -EBADMSG, bad version → -EPROTO, oversize → -EMSGSIZE
- All error paths free resources
Phase 8.2 test trigger via debugfs:
- /sys/kernel/debug/daedalus_v4l2/test_ping — any byte
enqueues a PING with a fixed 24-byte payload. Removed in
Phase 8.4 when real REQ_DECODE from V4L2 path takes over.
Userspace verification tool (tools/test_chardev_pingpong.c):
- Real C program, proper error reporting via strerror
- Validates the 6-step round-trip: open → empty-queue EAGAIN →
trigger ping → read PING → verify all fields → write PONG → close
- Builds with -Wall -Wextra clean
Verification on hertz (Pi 5, 6.12.75+rpt-rpi-2712):
$ sudo insmod daedalus_v4l2.ko
$ sudo tools/test_chardev_pingpong
opening /dev/daedalus-v4l2...
non-blocking read on empty queue: EAGAIN ✓
injected PING via debugfs ✓
read PING: magic ✓ version ✓ type=PING ✓ cookie=0x1234 ✓ payload=24 bytes
payload: "DAEDALUS-V4L2-PING-PL"
wrote PONG (cookie=0x1234) ✓
ALL TESTS PASSED.
$ sudo rmmod daedalus_v4l2 # clean
Per correctness-before-speed: full kerneldoc on structs, 8-tab
kernel style, SPDX headers, proper error paths, real test
program (not "I ran it once"), failure-mode coverage documented.
Phase 8.3 next: userspace daemon with dlopen'd FFmpeg parse path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
|
||||
#include "daedalus_v4l2_chardev.h"
|
||||
|
||||
#define DAEDALUS_DRV_NAME "daedalus_v4l2"
|
||||
#define DAEDALUS_VIDEO_NAME "daedalus"
|
||||
|
||||
@@ -181,29 +183,40 @@ static int __init daedalus_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = daedalus_chardev_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
daedalus_platform_device = platform_device_alloc(DAEDALUS_DRV_NAME, -1);
|
||||
if (!daedalus_platform_device)
|
||||
return -ENOMEM;
|
||||
if (!daedalus_platform_device) {
|
||||
ret = -ENOMEM;
|
||||
goto err_chardev;
|
||||
}
|
||||
|
||||
ret = platform_device_add(daedalus_platform_device);
|
||||
if (ret) {
|
||||
platform_device_put(daedalus_platform_device);
|
||||
return ret;
|
||||
goto err_chardev;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&daedalus_platform_driver);
|
||||
if (ret) {
|
||||
platform_device_unregister(daedalus_platform_device);
|
||||
return ret;
|
||||
goto err_chardev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_chardev:
|
||||
daedalus_chardev_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit daedalus_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&daedalus_platform_driver);
|
||||
platform_device_unregister(daedalus_platform_device);
|
||||
daedalus_chardev_exit();
|
||||
}
|
||||
|
||||
module_init(daedalus_init);
|
||||
|
||||
Reference in New Issue
Block a user