Skip to content

Case Study: va2000-amix

asokero/va2000-amix is a single-file character framebuffer driver that exposes the MNT VA2000 Zorro II RTG (ReTargetable Graphics) card to Amix as /dev/va2000, char major 68, minor 0 ✅. The kernel side discovers the board via the Amiga AUTOCONFIG mechanism, maps its 4 MB Zorro II window, and lets user space read/write/mmap the framebuffer; on top of it the companion Xrtg X11R5 server draws an actual desktop. This page is the worked, real-world counterpart to the conceptual Amix device-driver model and the parallel-port teaching driver.

Everything here is ✅ (from the repo's README and source) unless a claim carries another tag. The driver targets Amix 2.1p2a on an Amiga 3000 / 68030, Zorro II ✅, like the other modern Amix driver repos.

At a glance

Property Value Tag
Repo github.com/asokero/va2000-amix
Device node /dev/va2000
Class / major / minor character, major 68, minor 0
Card MNT VA2000 RTG, Zorro II
AutoConfig manufacturer 0x6D6E
AutoConfig product 0x01
Board window 4 MB Zorro II
Modes 800×600 / 1024×768 / 1280×720 @ 16-bit
Build native cc va2000.c (single source file)
Kernel files patched by installer 6 (see below)

What the driver does

The VA2000 is treated as a generic linear-framebuffer RTG board, not as Amiga custom-chip graphics (Amix never touches Agnus/Denise/Paula — see the overview). The driver:

  • Probes for the board at boot via autocon() using the card's AutoConfig product id.
  • Maps the board's 4 MB Zorro II window and splits it into a register region and a framebuffer region (see Memory map).
  • Supports three resolutions, all 16-bit colour: 800×600, 1024×768, and 1280×720 ✅.
  • Lets user space access the framebuffer through standard character-device entry points (read/write via uiomove(), plus the user/kernel copy primitives) and a page-frame mapping for mmap.

It is a character driver, which is the right class for a framebuffer: its core is read()/write() plus memory mapping, not the block layer's strategy() (compare the two classes in the driver model).

AutoConfig identity and discovery

The VA2000 announces itself on the Amiga expansion bus through AUTOCONFIG, the Zorro II protocol that assigns each board a base address at reset. The driver matches the board by its AutoConfig identity ✅:

Field Value
Manufacturer (mfr) 0x6D6E
Product 0x01

Amix exposes the AUTOCONFIG results to drivers through the Amix-specific autocon() call (Zorro II only — there is no Zorro III mapping in Amix ✅; see Quirks). The driver passes the product id to autocon() to obtain the board's assigned base address, then computes its register and framebuffer pointers as offsets from that base. The same AutoConfig fields are what a userspace scanner like lszorro would print for the card.

Note: the VA2000 is a register-only board (its 4 MB Zorro II window contains registers and a framebuffer, not RAM). It has a valid AutoConfig identity (0x6D6E/0x01), but userspace scanners like lszorro detect such boards by fingerprint rather than by reading a memory-mapped AutoConfig ROM body 🟡 — see the lszorro case study.

Memory map: the 4 MB window

The board presents a single 4 MB Zorro II window, split into registers and framebuffer ✅:

Offset (from board base) Region Size
0x0000000x00FFFF registers 64 KB
0x0100000x3FFFFF framebuffer ~4 MB − 64 KB

For mmap, the driver converts a framebuffer offset to a physical page-frame number with (base + off) >> 11 — the right-shift-by-11 "page frame" convention also used by the Piccolo RTG path ✅. (A right shift of 11 corresponds to the page granularity the HAT/MMU layer expects for this mapping; the value is taken verbatim from the repo, not re-derived here.)

Kernel APIs the driver uses

The driver draws on the standard SVR4 DDI/DKI surface plus the one Amix-specific call ✅. See the driver model's API table for the full list; the ones load-bearing here are:

API Role in this driver
autocon(product_id, dev, &board, &dummy) Amix-specific Zorro II board discovery — finds the VA2000's assigned base address 🟡 (repo-confirmed)
uiomove() move pixel data between the framebuffer and the user uio on read/write
copyin() / copyout() move control data across the user/kernel boundary
page frame (base + off) >> 11 translate a framebuffer offset to a page frame for mmap

Building the driver

The driver is one C file and builds with the native AT&T SVR4 cc already on the system ✅ — a single cc call, where the multi-file Hydra STREAMS driver needs a make plus a full-kernel make force (both native, no cross-compiler):

cc va2000.c

Because it is plain native cc, there is no toolchain bootstrap problem here — and there is none for Hydra either; both build on-box (the m68k-amix-gcc cross-compiler has no public recipe 🔴 but is not needed — see the toolchain page). The object goes into the kernel source tree and is linked statically into the kernel — Amix has no loadable modules, so every driver is part of /unix (the kernel architecture explains why).

The six kernel files the installer patches

Adding a statically-linked driver means editing the kernel source tree under /usr/sys and relinking. The va2000 installer patches six files ✅:

# File Change
1 amiga/driver/Makefile add va2000.o to the build
2 amiga/console/scrdev.c register the RTG screen type
3 amiga/console/c0.c register the RTG screen type
4 amiga/console/screen.c register the RTG screen type
5 master.d/kernel.c extern declarations + cdevsw[] slot 68 + va2000init added to io_init[]
6 (the mknod step, below) create the /dev/va2000 node

The three amiga/console/ files (scrdev.c, c0.c, screen.c) teach the Amix console/screen subsystem about a new RTG screen type so the X server can open the VA2000 as a screen ✅. The heart of the wiring is in master.d/kernel.c, the in-source kernel config file:

  • an extern declaration for each entry point,
  • a cdevsw[] entry at major 68 (the index is the major number — see the switch-table model),
  • and va2000init added to the boot-time init array, which this kernel.c calls io_init[] ✅.

Note: the Ditto paper calls the boot-time init array init_tbl[]; this modern kernel.c calls it io_init[]. Treat them as the same concept (a list of functions run once at boot). The full original master.d/kernel.c is not publicly archived, so the exact array name is version-dependent 🔴 — see the driver model.

Install sequence

End to end, the installer does the following ✅ (the generic version of this cycle is in Building and installing a kernel):

# 1. Build the driver object (native cc, single file)
cc va2000.c

# 2. Patch the six kernel files (Makefile, three console files, kernel.c) — done by the installer
#    (adds va2000.o, the RTG screen type, extern decls, cdevsw[68], va2000init in io_init[])

# 3. Create the device node: char, major 68, minor 0
mknod /dev/va2000 c 68 0

# 4. Relink the kernel
make install                       # -> produces relocunix

# 5. Write the new kernel into the boot partition
cp relocunix /stand
make bootpart KERNEL=relocunix

# 6. Reboot into the new kernel
shutdown -i6                       # keep the old /unix as a fallback

The kernel image is relocunix on modern 2.1 systems (the 1990 Ditto paper called the equivalent image rdbunix — a historical rename 🟡). After reboot, /dev/va2000 is live and the Xrtg server can be started against it.

Gotchas worth stealing

These are the practical traps the repo documents — useful for anyone writing or installing any Amix driver, not just this one ✅:

  • Amix /bin/sh is pre-POSIX. No $(...) command substitution (use backticks) and no grep -q (redirect to /dev/null and test $?). Install scripts that assume a modern shell will fail silently — this is a system-wide Amix quirk, not specific to va2000 (see Quirks and the userland notes) ✅.
  • extern declarations must precede io_init[] in kernel.c. If you append your extern va2000init(); after the array that references it, the relink fails — order the patch so declarations come first ✅.
  • Always remove stale objects before relinking. Run rm -f amiga/config/unix.o master.d/exp unix before make, or the build can link against stale objects and produce a kernel that doesn't reflect your changes ✅.

See also

Sources

  • asokero/va2000-amix repo (README + va2000.c source): https://github.com/asokero/va2000-amix — device node, char major 68, AutoConfig mfr 0x6D6E/product 0x01, 4 MB window split, modes, native cc build, the six patched kernel files, install sequence, (base+off)>>11 page frame, and the shell/extern/stale-object gotchas.
  • sources/research-brief.md §6 (modern driver repos — va2000 entry), §5 (device-driver model, cdevsw[]/io_init[]/init_tbl[], autocon()/uiomove()/copyin/copyout), §4 (monolithic kernel, no loadable modules, kernel.c in source), §2 (Zorro II only), §11 (pre-POSIX /bin/sh).
  • Ditto, Writing Amix Device Drivers, 1990 European Amiga Developer's Conference — driver-add procedure and the init_tbl[] vs io_init[] naming note (the full original master.d/kernel.c is not publicly archived 🔴).