ROM Handlers: CON, Port, Queue and RAM

AmigaOS 3.x ships a small set of handlers that turn devices and RAM into AmigaDOS streams and volumes: the CON-Handler (CON:, RAW:, AUX:), the Port-Handler (SER:, PAR:, PRT:), the Queue-Handler (PIPE:) and the RAM-Handler (RAM:). This article, based on §13.2–13.5 of the 2024 RKM, documents the path syntax each one accepts, its mountlist and dol_Startup parameters, and its behaviour as seen by programs. The FastFileSystem is covered in AmigaDOS Filesystem On-Disk Structures; the packets each handler implements are listed in the DOS Packet Reference.

CON-Handler

The CON-Handler implements the AmigaDOS console. It runs a graphical console in an Intuition window on top of console.device, or a serial console on serial.device (or any device that supports CMD_READ, CMD_WRITE and SDCMD_SETPARAMS). CON:, RAW: and — since V47 — AUX: are all served by it; the disk-based L:Aux-Handler is only a small wrapper that collects its mount parameters and starts the CON-Handler from ROM.

The console and the Shell are independent: the Shell runs on any stream (it reads scripts from files), and any program, e.g. Ed, can use a console.

The CON-Handler leaves dol_Task NULL, so every Open("CON:...") starts a new handler process with its own window. Opening * or a CONSOLE: path re-uses the console of the calling process instead. The window closes when the last handle on it is closed (subject to AUTO and WAIT).

Path for graphical consoles

CON:<left>/<top>/<width>/<height>/<title>[/<options>]
RAW:<left>/<top>/<width>/<height>/<title>[/<options>]

The window is described by the path given to Open(): the handler receives it as dp_Arg1 of its startup packet, not from the open packet.

Field Meaning If missing or negative
<left>, <top> Window position in pixels Intuition picks it — by default under the mouse pointer
<width> Window width including borders Screen width. A bare CON:/RAW: without any parameters gets 640 pixels
<height> Window height including borders Missing: 100 pixels; negative: screen height
<title> Drag-bar title \/ inserts a /, \\ a backslash

Options, separated by / and combinable:

Option Effect
CLOSE / NOCLOSE Add / remove a close gadget
AUTO Open the window only when something is read or written; the close gadget closes it while no request is pending, and it reopens on the next request. Not in raw mode
WAIT Keep the window open after the last handle is closed until the user closes it (close gadget or Ctrl+\). Not in raw mode
SMART / SIMPLE Smart refresh (more RAM, no redraw) / simple refresh (default)
INACTIVE Do not activate the window when it opens
BACKDROP 1.3+ Open behind all other windows; with NOBORDER, empty title, NOSIZE, NODRAG, NODEPTH, full size and SCREEN gives a full-screen console
NOBORDER No window borders (the drag bar remains if there is a title)
NOSIZE, NODRAG, NODEPTH Remove the size gadget, the drag bar, the depth gadget
WINDOW <hex> Run inside an already open window (address in hex, optional 0x); the console owns and closes it
SCREEN <name> Open on the named public screen; * = frontmost public screen
ALT <l>,<t>,<w>,<h> Alternative position and size for the zoom gadget (comma-separated)
ICONIFY Add an iconify gadget; needs ConClip running, which supplies the icon. The window reopens on the next request or a double-click on the icon
BPTR con = Open("CON:0/20/640/200/Output \\/ Log/CLOSE/AUTO/WAIT", MODE_NEWFILE);

ACTION_DISK_INFO disables AUTO and ICONIFY: once a program has fetched the window pointer the console cannot close or iconify the window any more. Send ACTION_UNDISK_INFO (V45) to give them back — see Console packets.

Close gadget and end of file. In cooked and medium mode, clicking the close gadget while handles are open delivers end-of-file (a read returns 0) to the reader; what happens next is up to the program. Ctrl+\ does the same from the keyboard. In raw mode neither is interpreted: the close gadget produces a raw input event (only if the program subscribed with CSI 11{), Ctrl+\ produces the byte 0x1C, and iconifying must be done by the program. This is also why AUTO and WAIT do not work in raw mode.

AUX: serial consoles

Since V47 the CON-Handler also runs AUX: (earlier versions used a separate BCPL handler):

AUX:<baud>/<control>[/<options>]
Field Meaning
<baud> Baud rate, e.g. 9600
<control> Three characters: data bits 5–8; parity N, E, O, M or S; stop bits 0, 1 or 2. 8N1 is typical and best for serial.device
RAW Raw mode
UNIT <n> Device unit (serial.device has only unit 0)
AUTO Open the connection on the first read or write
WAIT Keep the connection open after the last handle is closed, until the user sends Ctrl+\ (0x1C)

Settings are taken from Serial preferences, overridden by the mountlist (Baud, Control, Unit), overridden by the path. A non-serial device must support SDCMD_SETPARAMS for the path parameters to be forwarded.

Startup and mount parameters

CON: and RAW: are mounted by the ROM. AUX: has a mountlist in DEVS:DosDrivers, and you can create more consoles by mounting L:Aux-Handler as Handler or EHandler. A custom serial console on another device must use EHandler:

EHandler = L:Aux-Handler
Device   = duart.device
Unit     = 0
Baud     = 9600
Control  = "8N1"

With Handler = it always runs on serial.device, and Startup selects the mode. Because of how Mount works, Startup is not available with EHandler, and Device, Unit, Baud and Control are not available with Handler. GlobVec does not matter: the AUX-Handler works with either startup convention.

dol_Startup values understood by the CON-Handler:

dol_Startup Meaning
< 0 Legacy: raw mode in an existing window whose struct Window * (plain pointer) is in dp_Arg1 instead of a path. Deprecated — use WINDOW
0 CON:: cooked mode, new window
1 RAW:: raw mode, new window
2 Medium mode, new window (V47)
3 Reserved
BPTR, bit 30 clear Raw mode on the device/unit of a FileSysStartupMsg
BPTR, bit 30 set Cooked mode on the device/unit of a FileSysStartupMsg

Bit 30 is free in a BPTR (BPTRs are shifted left by two to form addresses), so the AUX-Handler uses it to pass the mode along with the FileSysStartupMsg.

Buffer modes

The mode is set at startup or later with SetMode() (ACTION_SCREEN_MODE). It applies to the whole console, graphical or serial.

Mode Name Behaviour
0 Cooked (CON:, AUX:) Echo and line editing; a complete line goes to the output buffer when Return is pressed. Programs read whole lines
1 Raw (RAW:) Every keystroke is delivered at once, unechoed and uninterpreted, as single bytes or ECMA-48 CSI (0x9B) sequences from the keymap; a pending read returns after each keystroke even if it asked for more
2 Medium (V47, no device name) Like cooked, but the history and TAB keys are reported immediately as TAB Report sequences; used by the Shell

Keys in cooked mode (* = reported differently in medium mode):

Key Function
Cursor left / right Move one character
Shift+Cursor left / right Start / end of line
Cursor up / down* Nothing
Shift+Cursor up* Start of line (the manual's table also lists it as "nothing")
Shift+Cursor down* Erase line (the manual's table also lists it as "nothing")
TAB* Insert a TAB
Shift+TAB* Nothing
Return, Ctrl+M Send the line
Ctrl+A Start of line
Ctrl+B, Ctrl+X Erase the line
Ctrl+C … Ctrl+F Send break signal SIGBREAKB_CTRL_C … _F (12–15)
Ctrl+H, Backspace Delete character left of the cursor
Del Delete character under the cursor
Ctrl+J Insert a line feed: split the line and keep editing the lower part; all lines are sent together on Return
Ctrl+K / Ctrl+Y Cut to the console's own yank buffer / paste it (independent of the clipboard)
Ctrl+Q / Ctrl+S Resume / suspend output
Ctrl+R* Nothing
Ctrl+U Delete from the start of line to the cursor
Ctrl+W Delete the word left of the cursor
Ctrl+Z End of line
Ctrl+\ End of file

In medium mode the starred keys and Ctrl+R/Ctrl+B produce a TAB Report CSI <m>;<s>;<c>U<line> (<m>: 2/3 history up/down, 4/5 search up/down, 6 partial search, 10 rewind, 12/13 TAB forwards/backwards; <s> line length; <c> 1-based cursor column; <line> the current input). The Shell answers by typing the result back with ACTION_FORCE. The full table is in OS 3.2 File System and Handler Changes. Before running a command the Shell switches back to cooked mode and restores medium mode afterwards, which also lets the V47 Shell run in a RAW: window.

The V47 CON-Handler has no command history of its own any more; the history belongs to the Shell.

In raw mode only Ctrl+C … Ctrl+F are still interpreted (they always send break signals). The console never interprets output control sequences itself; it passes them to console.device — or, on a serial line, to the terminal at the other end.

Break signals

Ctrl+C … Ctrl+F signal the process that most recently read from the console and the one that most recently wrote to it (twice if they differ; background Shells are skipped). A program can redirect the reader side with ACTION_CHANGE_SIGNAL. AmigaDOS cannot kill processes asynchronously, so programs must poll with CheckSignal(). By convention Ctrl+C stops a program, Ctrl+D stops a script (tested by the Shell), Ctrl+E is unassigned, and Ctrl+F brings up the Commodities control window.

#include <dos/dos.h>
#include <proto/dos.h>

/* Long loop that honours Ctrl-C; returns FALSE if interrupted. */
BOOL ProcessItems(LONG n)
{
    LONG i;

    for (i = 0; i < n; i++) {
        if (CheckSignal(SIGBREAKF_CTRL_C)) {
            PrintFault(ERROR_BREAK, NULL);
            return FALSE;
        }
        /* ... work on item i ... */
    }
    return TRUE;
}

Port-Handler

The Port-Handler turns the Amiga ports into byte streams: SER: on serial.device, PAR: on parallel.device, PRT: on printer.device. Unlike AUX:, SER: has no line editing; even in raw mode AUX: turns Ctrl+C into a signal, while SER: passes byte 0x03 through.

Path

Up to V40 the Port-Handler took no options. Since V45:

SER:[[BAUD=]<baud>/][[CONTROL=]<control>/][NOWAIT/][UNIT=<n>]
PAR:[UNIT=<n>]
PRT:[TRANSPARENT/][RAW/][UNIT=<n>]
Option Device Meaning
BAUD SER: Baud rate. Without the keyword it must be the first component; with it, separate by space or =
CONTROL SER: Data bits, parity, stop bits as for AUX: (e.g. 8N1); positional (second) or by keyword
NOWAIT SER: Do not block on reads: return end-of-file when no data is waiting
TRANSPARENT PRT: Send CSI sequences to the printer untranslated instead of letting printer.device translate them
RAW PRT: Do not translate line feed (0x0A) into line feed + carriage return
UNIT all Device unit (decimal; space or =)

Missing SER: settings come from the mountlist and then from Serial preferences. As an alternative to NOWAIT, use WaitForChar(), supported by the Port-Handler since V45.

BPTR ser = Open("SER:BAUD=19200/CONTROL=8N1/NOWAIT", MODE_OLDFILE);

Startup and mount parameters

SER:, PAR: and PRT: are mounted by the ROM with fixed parameters, but you can mount the Port-Handler under other names.

dol_Startup Meaning
0 SER: on serial.device
1 PAR: on parallel.device
2 PRT: on printer.device
BPTR Serial-style I/O on the device of a FileSysStartupMsg (EHandler mount, V45)

The ROM entries correspond to:

Handler = L:Port-Handler
Startup = 0         /* 1 = PAR:, 2 = PRT: */
GlobVec = 0

Startup cannot be combined with Device/Unit, so such a mount always uses unit 0 of the default device unless the path says UNIT. The Port-Handler requires GlobVec = 0: it still uses the BCPL startup, although it is written in C.

A Port-Handler on a third-party serial device (V45):

EHandler = L:Port-Handler
Device   = duart.device
Unit     = 1
Baud     = 19200
Control  = "8N1"
GlobVec  = 0

It behaves like SER: by default. Using NSCMD_DEVICEQUERY (an AmigaDOS 43 extension) it detects parallel- or printer-like devices and then behaves like PAR: or PRT:, ignoring Baud and Control and accepting that device type's path options. The Baud mount keyword is understood since Port-Handler V43.

Queue-Handler (PIPE:)

The Queue-Handler connects a writer and a reader through named pipes; the Shell uses it for |. The reader blocks while no data is available, the writer blocks while the buffers are full, and when the reader closes, the Queue-Handler sends SIGBREAKF_CTRL_C to the writer. All pipes are served by one process. Earlier releases had a similar PIPE: that had to be mounted by hand; since V47 the ROM mounts the disk-based L:Queue-Handler as PIPE: at startup.

Path

PIPE:name[/quantumsize[/buffercount]]
  • name identifies the pipe; a reader (MODE_OLDFILE) and a writer (MODE_NEWFILE) with the same name are connected. MODE_READWRITE is not supported.
  • quantumsize is the block size in bytes (default 1024). Data is passed to the reader block by block, or when the writer closes.
  • buffercount is how many blocks may be waiting before the writer blocks (default 8, i.e. 8K). 0 lets a pipe fill memory up to a 64K safety margin.

The empty name (PIPE: alone, V45) is the anonymous pipe: opened for reading it re-uses the pipe already on the process's standard input, opened for writing the one on its standard output; if that stream is not a Queue-Handler pipe, the open fails. It lets commands that only write to a named file take part in a Shell pipe:

Join A B TO PIPE: | More

Mount parameters

The ROM uses the equivalent of:

Handler = L:Queue-Handler
Startup = 0
GlobVec = -1

It is a C handler (GlobVec = -1). A custom-configured instance, which must not be named PIPE, takes its defaults from the environment vector:

EHandler  = L:Queue-Handler
Device    = no.device      /* required by Mount, ignored */
BlockSize = 1024           /* de_SizeBlock: quantum size */
Buffers   = 8              /* de_NumBuffers: blocks per pipe */
GlobVec   = -1

RAM-Handler

The RAM-Handler is the ROM file system behind RAM:. It stores everything in RAM and implements almost all file-system packets, but not the console packets and not ACTION_SET_OWNER.

  • External links (V47). MakeLink(..., LINK_HARD) with a target on another volume creates an external link: an initially empty file or directory whose contents are copied from the target when first accessed ("copy on read"); afterwards the copy is independent. The system uses this for ENV:, a link to ENVARC: from which only the variables actually read are copied into RAM. No separate handler is needed.
  • Not mountable. It is not a file and not registered in FileSystem.resource, so it cannot be mounted from a mountlist. Its startup value is 0 and is ignored.
  • RAD: is different. The reset-proof RAD: is the FFS running on ramdrive.device, which presents RAM as a block device pre-initialised as an empty FFS volume.
  • Behavioural differences from the FFS (useful when testing a program only on RAM:):
Behaviour RAM-Handler FFS
ACTION_SET_PROTECT on a hard link Ignored (bits always follow the target) Link and target kept in sync
ACTION_SET_PROTECT/SET_DATE on a soft link (last component) Changes the link ERROR_IS_SOFT_LINK (target is changed)
MODE_NEWFILE on a file with hard links Links keep the old contents Links see the new contents
ACTION_READ_LINK without a link in the path ERROR_OBJECT_WRONG_TYPE ERROR_OBJECT_NOT_FOUND
id_NumBlocks before version 45 0 Partition size
ChangeMode(CHANGE_FH, ...) New mode not interpreted correctly —

See Also


Sources: Thomas Richter, Amiga ROM Kernel Reference Manual: AmigaDOS (2024, v1.27), §5.5.4 (pp. 38–39), §8.1 (pp. 96–107), §13.2–13.5 (pp. 220–232), §14.1–14.5 (pp. 255–287), §14.8 (pp. 294–305); NDK 3.2 R4 Include_H/dos/dos.h, dos/dosextens.h, dos/filehandler.h Updated: 2026-11-13