Christian Werner 2aa5104812 feat(kernel): Improve selftest.sh module discovery and error handling
Enhance module selection process by validating vermagic against the running kernel. Add detailed error messages with suggestions for manual path overrides or rebuilding for the current kernel. Ensure robust fallback behavior and improve user guidance.
2026-06-20 04:53:40 +02:00
..
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00

iec_listener kernel module

Commodore IEC listener (printer, default address 4) for the Raspberry Pi Zero 2 W. The timing-critical IEC handshake runs in this kernel module; received bytes and bus events are pushed to userspace through /dev/iec0.

Build/deploy, pinning, GPIO-descriptor and timing details live in ../docs/kernel-notes.md. This README documents the self-test, which is the first thing to run after loading the module on real hardware.

Self-test

The module exposes a hardware self-test via the IEC_IOC_SELFTEST ioctl on /dev/iec0. It drives the DATA line (the only line the Pi asserts) low and reads it back, releases it, then samples ATN / CLK / RESET, returning a bitmask of line states. Run it with the C64 disconnected to check the wiring before connecting the real bus (see PLAN.md §10).

Running it

selftest.sh is non-persistent (nothing is installed into /lib/modules, no autoload): it detects the running kernel, picks the matching module, loads it, runs the self-test, and always unloads it again.

A released package ships several kernel builds side by side:

comodore-iec-emu/
├── selftest.sh
└── modules/
    ├── iec_listener_1-6.12.93-1+rpt1.ko   # built for 6.12.x (bookworm)
    └── iec_listener_1-6.18.34-1+rpt1.ko   # built for 6.18.x (trixie)

You don't pick the file yourself: the script reads uname -r, then scans modules/ (and a few fallback locations) and selects the .ko whose vermagic matches the running kernel. Matching is by vermagic rather than filename because the packaged name carries a Debian epoch/revision (1:6.12.93-1+rpt1) that uname -r (6.12.93+rpt-rpi-v8) does not.

sudo ./selftest.sh                                # auto-selects the matching module, address 4
sudo ./selftest.sh --address 5                    # same, address 5
sudo ./selftest.sh ~/iec_listener.ko --address 5  # force a specific module file

If no module matches the running kernel, the script lists the modules it found (with the kernel each was built for) and exits — rebuild for the current kernel, or pass a path explicitly.

It exits non-zero unless the result is a full pass (0x1F), so it is usable in scripts/CI.

Result bitmask

The ioctl returns a u32; a full pass is 0x1F (all five bits set).

Bit Value Meaning Source
DATA_ASSERT_OK 0x01 DATA read low while the module drives it low Pi drive + sense path
DATA_FLOAT_OK 0x02 DATA read high after release (Hi-Z) external pull-up on DATA
ATN_RELEASED 0x04 ATN high (idle) line state
CLK_RELEASED 0x08 CLK high (idle) line state
RESET_RELEASED 0x10 RESET high (idle) line state

Constants are defined in iec_listener.h; the ioctl number is _IOR('I', 3, __u32) = 0x80044903.

Interpreting failures

  • DATA_ASSERT_OK missing → driving DATA low doesn't read back low: level shifter wired backwards/inverting, wrong pin, or the sense path is broken. This is the only bit that is fully internal to the Pi — if it fails, suspect the module/build or the DATA wiring, not pull-ups.
  • DATA_FLOAT_OK missing → DATA stays low after release: missing/weak pull-up on DATA, or the pin didn't return to input.
  • CLK_RELEASED missing → CLK reads low at idle: no pull-up on CLK, short, or a swapped signal.
  • ATN_RELEASED / RESET_RELEASED missing → that line reads low at idle: short, missing pull-up, or swapped wiring.

⚠️ Bare-board caveat

With nothing connected, the expected result is 0x15, not a fault:

  • DATA_ASSERT_OK (0x01) passes — it's internal to the Pi.
  • ATN_RELEASED (0x04) and RESET_RELEASED (0x10) pass only because GPIO2/GPIO3 have fixed ~1.8 kΩ pull-ups built into the BCM2710 SoC (they are the I²C0 pins; the pull-ups can't be disabled). They read high even with nothing wired, so on a bare board these two bits prove nothing about your wiring.
  • DATA_FLOAT_OK (0x02) and CLK_RELEASED (0x08) read low because GPIO17/18 have no such built-in pull-up and nothing is attached.

So on a bare board the only meaningful signal is DATA_ASSERT_OK. A full 0x1F is only reachable once the level shifter (with its CLK/DATA pull-ups) is wired and powered. To make ATN/RESET meaningful, briefly ground each at the connector and confirm the corresponding bit drops.