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]]
nameidentifies the pipe; a reader (MODE_OLDFILE) and a writer (MODE_NEWFILE) with the same name are connected.MODE_READWRITEis not supported.quantumsizeis the block size in bytes (default 1024). Data is passed to the reader block by block, or when the writer closes.buffercountis 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 forENV:, a link toENVARC: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-proofRAD:is the FFS running onramdrive.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¶
- Interactive Files and Handler Detection —
IsInteractive(),WaitForChar(),SetMode(), console packets - DOS Packet Reference
- Writing a DOS Handler or File System
- IFF Format and Mountlist Reference — mountlist keywords,
GlobVec - OS 3.2 File System and Handler Changes
- AmigaDOS Filesystem On-Disk Structures
- The AmigaDOS Shell
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