Christian Werner e0a78871ca feat(kernel): Add GPIO descriptor-based initialization and self-test script
Replace legacy gpio_to_desc() with GPIO descriptor resolution by chip label
and hardware number, ensuring compatibility with kernels using non-zero
gpiochip bases. Added `selftest.sh` for non-persistent module testing, which
performs a hardware self-test and verifies wiring before connecting the real
bus. Included a detailed README.md documenting the self-test process.
2026-06-19 00:23:45 +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
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 checks vermagic, loads the module, runs the self-test, and always unloads it again.

sudo ./selftest.sh                                # auto-finds ./ or ~/iec_listener.ko, address 4
sudo ./selftest.sh ~/iec_listener.ko --address 5  # runs with ~/iec_listener.ko, address 5

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.