Phase 1 continued: serial, input devices + README indexes

10_devices:
- serial.md: expanded with DB-25 pinout, custom chip UART registers,
  baud rate calculation table, open/configure/read/write patterns,
  serial debugging (KPrintF/Sushi)
- input.md: expanded with handler chain architecture diagram,
  InputEvent struct, event classes table, qualifier bits, custom
  handler with key remapping, event consumption/blocking,
  synthetic event injection, Commodities Exchange

Updated indexes:
- 07_dos/README.md — enriched descriptions for all files
- 10_devices/README.md — enriched descriptions for all files
This commit is contained in:
Ilia Sharin 2026-04-23 20:28:03 -04:00
parent da9e7d3b63
commit 0ded078134
4 changed files with 326 additions and 73 deletions

View file

@ -6,13 +6,13 @@
| File | Description |
|---|---|
| [dos_base.md](dos_base.md) | DosLibrary structure and global state |
| [file_io.md](file_io.md) | Open, Close, Read, Write, Seek |
| [locks_examine.md](locks_examine.md) | Lock, UnLock, Examine, ExNext, ExAll |
| [pattern_matching.md](pattern_matching.md) | ParsePattern, MatchPattern, wildcards |
| [dos_base.md](dos_base.md) | DosLibrary structure, RootNode, BCPL heritage |
| [file_io.md](file_io.md) | Open/Close/Read/Write/Seek, buffered I/O (FRead/SetVBuf), FileInfoBlock, practical patterns |
| [locks_examine.md](locks_examine.md) | Lock semantics (shared/exclusive), handler discovery, Examine/ExNext/ExAll, antipatterns |
| [pattern_matching.md](pattern_matching.md) | ParsePattern, MatchPattern, AmigaDOS wildcard syntax |
| [process_management.md](process_management.md) | CreateNewProc, SystemTagList, Execute |
| [packet_system.md](packet_system.md) | DosPacket, ACTION_* codes, handler protocol |
| [filesystem.md](filesystem.md) | FFS/OFS layout, block structure |
| [environment.md](environment.md) | GetVar/SetVar, local/global env variables |
| [error_handling.md](error_handling.md) | IoErr, Fault, PrintFault, error codes |
| [cli_shell.md](cli_shell.md) | CLI/Shell: pipes, redirection, scripts, ReadArgs |
| [packet_system.md](packet_system.md) | DosPacket wire format, ACTION_* codes, handler protocol, BSTR encoding |
| [filesystem.md](filesystem.md) | FFS/OFS block layout, root/file/data blocks, bitmap, hash function, ADF reader |
| [environment.md](environment.md) | GetVar/SetVar, local/global/persistent env variables |
| [error_handling.md](error_handling.md) | IoErr, Fault, PrintFault, complete error code table |
| [cli_shell.md](cli_shell.md) | CLI/Shell: pipes, redirection, scripts, ReadArgs template parsing |

View file

@ -2,17 +2,19 @@
# Devices — Overview
Amiga devices are shared libraries with an exec I/O request interface. They provide standardised access to hardware peripherals via `OpenDevice`/`CloseDevice` and `DoIO`/`SendIO` patterns.
## Section Index
| File | Description |
|---|---|
| [trackdisk.md](trackdisk.md) | trackdisk.device — floppy I/O |
| [trackdisk.md](trackdisk.md) | Floppy disk DMA: MFM encoding, track format, disk geometry, track caching, direct HW access |
| [scsi.md](scsi.md) | scsi.device / 2nd.scsi.device — hard disk I/O |
| [serial.md](serial.md) | serial.device — RS-232 |
| [parallel.md](parallel.md) | parallel.device — Centronics |
| [timer.md](timer.md) | timer.device — timing and delays |
| [audio.md](audio.md) | audio.device — DMA audio channels |
| [keyboard.md](keyboard.md) | keyboard.device — keyboard events |
| [gameport.md](gameport.md) | gameport.device — joystick/mouse |
| [input.md](input.md) | input.device — event merging |
| [serial.md](serial.md) | UART/RS-232: CIA registers, baud rate calculation, serial debugging (KPrintF) |
| [parallel.md](parallel.md) | parallel.device — Centronics parallel port |
| [timer.md](timer.md) | CIA timers, E-clock, VBlank: delays, ReadEClock, periodic patterns, signal-based waiting |
| [audio.md](audio.md) | 4-channel DMA audio: hardware registers, priority allocation, double-buffering, modulation |
| [keyboard.md](keyboard.md) | CIA-A serial handshake, raw key codes, key matrix, reset sequence, FPGA protocol notes |
| [gameport.md](gameport.md) | gameport.device — joystick/mouse port reading |
| [input.md](input.md) | Input handler chain: priority dispatch, event classes, key remapping, Commodities Exchange |
| [console.md](console.md) | console.device — text terminal I/O |

View file

@ -1,41 +1,216 @@
[← Home](../README.md) · [Devices](README.md)
# input.device — Event Stream Merging
# input.device — Input Event Handler Chain
## Overview
`input.device` merges events from keyboard, mouse, gameport, and timer into a single input stream that feeds Intuition. Input handlers can be installed at various priorities to filter, modify, or consume events.
`input.device` is the central dispatcher for all input events on AmigaOS. It collects raw events from keyboard, mouse, joystick, and other sources, then distributes them through a **priority-ordered handler chain**. Intuition sits at priority 50 in this chain — custom input handlers can intercept events before or after Intuition.
---
## Handler Priority Levels
## Handler Chain Architecture
| Priority | Consumer |
|---|---|
| 100 | System reserved |
| 51+ | Custom high-priority handlers |
| 50 | Intuition |
| 20 | Console.device |
| 0 | Default |
```mermaid
flowchart TD
KB["keyboard.device"] --> ID["input.device"]
GP["gameport.device"] --> ID
OTHER["Other sources"] --> ID
ID --> H1["Handler Pri 100<br/>Commodities Exchange"]
H1 --> H2["Handler Pri 51<br/>Custom 'hot key' handler"]
H2 --> H3["Handler Pri 50<br/>Intuition"]
H3 --> H4["Handler Pri 0<br/>Console.device"]
H4 --> H5["Handler Pri -50<br/>Application handler"]
style H3 fill:#e8f4fd,stroke:#2196f3,color:#333
```
Events flow from highest to lowest priority. Each handler can:
- **Pass** the event through (return the event list unchanged)
- **Modify** the event (e.g., remap keys)
- **Consume** the event (remove from chain — lower handlers never see it)
- **Insert** new synthetic events
---
## Commands
## InputEvent Structure
| Code | Constant | Description |
```c
/* devices/inputevent.h — NDK39 */
struct InputEvent {
struct InputEvent *ie_NextEvent; /* linked list */
UBYTE ie_Class; /* event type (IECLASS_*) */
UBYTE ie_SubClass; /* subclass */
UWORD ie_Code; /* key code, button, qualifier */
UWORD ie_Qualifier; /* modifier keys state */
union {
struct {
WORD ie_x; /* mouse X delta or absolute */
WORD ie_y; /* mouse Y delta or absolute */
} ie_xy;
APTR ie_addr; /* pointer data */
} ie_position;
struct timeval ie_TimeStamp; /* when event occurred */
};
```
### Event Classes
| Class | Constant | Source |
|---|---|---|
| 9 | `IND_ADDHANDLER` | Add input handler |
| 10 | `IND_REMHANDLER` | Remove input handler |
| 11 | `IND_WRITEEVENT` | Inject an InputEvent into the stream |
| 12 | `IND_SETTHRESH` | Set double-click threshold |
| 13 | `IND_SETPERIOD` | Set key repeat period |
| 14 | `IND_SETMPORT` | Set mouse port type |
| 15 | `IND_SETMTRIG` | Set mouse trigger |
| 16 | `IND_SETMTYPE` | Set mouse type |
| $01 | `IECLASS_RAWKEY` | Raw key press/release |
| $02 | `IECLASS_RAWMOUSE` | Mouse movement + buttons |
| $04 | `IECLASS_TIMER` | Timer tick event |
| $07 | `IECLASS_NEWPOINTERPOS` | Absolute pointer position |
| $09 | `IECLASS_DISKINSERTED` | Disk inserted |
| $0A | `IECLASS_DISKREMOVED` | Disk removed |
| $0D | `IECLASS_NEWPREFS` | Preferences changed |
### Qualifier Bits
| Bit | Constant | Key |
|---|---|---|
| 0 | `IEQUALIFIER_LSHIFT` | Left Shift |
| 1 | `IEQUALIFIER_RSHIFT` | Right Shift |
| 2 | `IEQUALIFIER_CAPSLOCK` | Caps Lock |
| 3 | `IEQUALIFIER_CONTROL` | Ctrl |
| 4 | `IEQUALIFIER_LALT` | Left Alt |
| 5 | `IEQUALIFIER_RALT` | Right Alt |
| 6 | `IEQUALIFIER_LCOMMAND` | Left Amiga |
| 7 | `IEQUALIFIER_RCOMMAND` | Right Amiga |
| 8 | `IEQUALIFIER_NUMERICPAD` | Key is on numeric pad |
| 9 | `IEQUALIFIER_REPEAT` | Key repeat (auto-repeat) |
| 10 | `IEQUALIFIER_INTERRUPT` | Event from interrupt |
| 11 | `IEQUALIFIER_MULTIBROADCAST` | Broadcast to all handlers |
| 12 | `IEQUALIFIER_MIDBUTTON` | Middle mouse button |
| 13 | `IEQUALIFIER_RBUTTON` | Right mouse button |
| 14 | `IEQUALIFIER_LEFTBUTTON` | Left mouse button |
| 15 | `IEQUALIFIER_RELATIVEMOUSE` | Mouse values are deltas |
---
## Installing a Custom Input Handler
```c
#include <devices/input.h>
#include <devices/inputevent.h>
/* Handler function — called from input.device context: */
struct InputEvent * __saveds __asm MyHandler(
register __a0 struct InputEvent *events,
register __a1 APTR handlerData)
{
struct InputEvent *ev;
for (ev = events; ev; ev = ev->ie_NextEvent)
{
if (ev->ie_Class == IECLASS_RAWKEY)
{
UWORD key = ev->ie_Code & 0x7F;
BOOL up = ev->ie_Code & 0x80;
/* Example: remap F10 ($59) to Escape ($45): */
if (key == 0x59)
ev->ie_Code = (up ? 0x80 : 0x00) | 0x45;
}
}
return events; /* pass all events to next handler */
}
/* Install the handler: */
struct Interrupt handlerInt;
handlerInt.is_Node.ln_Type = NT_INTERRUPT;
handlerInt.is_Node.ln_Pri = 51; /* just above Intuition (50) */
handlerInt.is_Node.ln_Name = "MyKeyMapper";
handlerInt.is_Data = myData;
handlerInt.is_Code = (APTR)MyHandler;
struct MsgPort *inputPort = CreateMsgPort();
struct IOStdReq *inputReq = (struct IOStdReq *)
CreateIORequest(inputPort, sizeof(struct IOStdReq));
OpenDevice("input.device", 0, (struct IORequest *)inputReq, 0);
inputReq->io_Command = IND_ADDHANDLER;
inputReq->io_Data = (APTR)&handlerInt;
DoIO((struct IORequest *)inputReq);
/* ... handler is now active ... */
/* Remove handler before exit: */
inputReq->io_Command = IND_REMHANDLER;
inputReq->io_Data = (APTR)&handlerInt;
DoIO((struct IORequest *)inputReq);
```
### Consuming Events (Blocking)
```c
/* To consume an event (prevent it from reaching Intuition): */
struct InputEvent * __saveds __asm BlockEscape(
register __a0 struct InputEvent *events,
register __a1 APTR data)
{
struct InputEvent *ev, *prev = NULL;
for (ev = events; ev; )
{
if (ev->ie_Class == IECLASS_RAWKEY &&
(ev->ie_Code & 0x7F) == 0x45) /* Escape */
{
/* Remove from chain: */
if (prev)
prev->ie_NextEvent = ev->ie_NextEvent;
else
events = ev->ie_NextEvent;
ev = ev->ie_NextEvent;
continue;
}
prev = ev;
ev = ev->ie_NextEvent;
}
return events;
}
```
---
## Injecting Synthetic Events
```c
/* Send a fake key press: */
struct InputEvent fake;
fake.ie_Class = IECLASS_RAWKEY;
fake.ie_Code = 0x45; /* Escape, key down */
fake.ie_Qualifier = 0;
inputReq->io_Command = IND_WRITEEVENT;
inputReq->io_Data = (APTR)&fake;
inputReq->io_Length = sizeof(struct InputEvent);
DoIO((struct IORequest *)inputReq);
```
---
## Commodities Exchange
The Commodities Exchange (`commodities.library`) provides a high-level framework for input handlers:
```c
/* Define a hot key: */
CxObj *broker = CxBroker(&newBroker, NULL);
CxObj *filter = CxFilter("rawkey control esc"); /* Ctrl+Esc */
CxObj *sender = CxSender(brokerPort, EVT_HOTKEY);
AttachCxObj(filter, sender);
AttachCxObj(broker, filter);
ActivateCxObj(broker, TRUE);
```
This is the preferred method for applications — avoids writing raw input handlers.
---
## References
- NDK39: `devices/input.h`
- [input_events.md](../09_intuition/input_events.md) — handler installation example
- NDK39: `devices/input.h`, `devices/inputevent.h`
- ADCD 2.1: input.device autodocs
- See also: [keyboard.md](keyboard.md) — raw key code map
- See also: [idcmp.md](../09_intuition/idcmp.md) — Intuition input handling
- See also: [input_events.md](../09_intuition/input_events.md) — event flow through Intuition

View file

@ -1,54 +1,130 @@
[← Home](../README.md) · [Devices](README.md)
# serial.device — RS-232 Communication
# serial.device — UART and RS-232 Communication
## Overview
`serial.device` provides buffered RS-232 serial I/O through the Amiga's built-in 8520 CIA UART (active-high active sense).
`serial.device` provides access to the Amiga's built-in UART (Universal Asynchronous Receiver/Transmitter) for RS-232 serial communication. The hardware UART is implemented using **CIA-B** shift registers and custom chip DMA. Serial I/O is fundamental for debugging (serial console), modem communication, MIDI, and inter-machine networking.
---
## Opening
## Hardware
```c
struct IOExtSer *ser = (struct IOExtSer *)
CreateIORequest(port, sizeof(struct IOExtSer));
OpenDevice("serial.device", 0, (struct IORequest *)ser, 0);
```
### Serial Port Pins (DB-25)
---
| Pin | Signal | Direction | Description |
|---|---|---|---|
| 2 | TxD | Output | Transmit data |
| 3 | RxD | Input | Receive data |
| 4 | RTS | Output | Request to send (active low) |
| 5 | CTS | Input | Clear to send (active low) |
| 6 | DSR | Input | Data set ready |
| 7 | GND | — | Signal ground |
| 8 | CD | Input | Carrier detect |
| 20 | DTR | Output | Data terminal ready |
## Setting Parameters
### Custom Chip Registers
```c
ser->io_CtlChar = SER_DEFAULT_CTLCHAR;
ser->io_RBufLen = 4096; /* read buffer size */
ser->io_Baud = 9600;
ser->io_ReadLen = 8; /* data bits */
ser->io_WriteLen = 8;
ser->io_StopBits = 1;
ser->io_SerFlags = SERF_XDISABLED; /* no XON/XOFF */
ser->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)ser);
```
---
## Commands
| Code | Constant | Description |
| Register | Address | Description |
|---|---|---|
| 2 | `CMD_READ` | Read bytes |
| 3 | `CMD_WRITE` | Write bytes |
| 5 | `CMD_CLEAR` | Clear buffers |
| 8 | `CMD_FLUSH` | Abort pending requests |
| 9 | `SDCMD_QUERY` | Get status (bytes in buffer, errors) |
| 10 | `SDCMD_BREAK` | Send break signal |
| 11 | `SDCMD_SETPARAMS` | Set baud/bits/parity/stop |
| `SERDAT` | `$DFF030` | Serial data write (transmit) — 9 bits: stop bit + 8 data |
| `SERDATR` | `$DFF018` | Serial data read (receive) — status + received byte |
| `SERPER` | `$DFF032` | Serial period (baud rate divider) |
| `ADKCON` | `$DFF09E` | UARTBRK bit for break signal |
### Baud Rate Calculation
```c
/* SERPER value = (system_clock / baud_rate) - 1 */
/* PAL system clock for serial = 3,546,895 Hz */
/* NTSC = 3,579,545 Hz */
#define SERIAL_CLOCK_PAL 3546895
#define SERIAL_CLOCK_NTSC 3579545
UWORD serper_from_baud(ULONG baud, BOOL isPAL) {
return (isPAL ? SERIAL_CLOCK_PAL : SERIAL_CLOCK_NTSC) / baud - 1;
}
```
| Baud Rate | SERPER (PAL) | SERPER (NTSC) |
|---|---|---|
| 1200 | 2955 | 2982 |
| 2400 | 1477 | 1491 |
| 9600 | 368 | 372 |
| 19200 | 184 | 185 |
| 31250 (MIDI) | 112 | 113 |
| 57600 | 60 | 61 |
| 115200 | 29 | 30 |
---
## Using serial.device
### Open and Configure
```c
struct MsgPort *serialPort = CreateMsgPort();
struct IOExtSer *serialReq = (struct IOExtSer *)
CreateIORequest(serialPort, sizeof(struct IOExtSer));
/* Open serial.device unit 0: */
BYTE err = OpenDevice("serial.device", 0,
(struct IORequest *)serialReq, 0);
/* Configure: */
serialReq->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
serialReq->io_Baud = 9600;
serialReq->io_ReadLen = 8; /* 8 data bits */
serialReq->io_WriteLen = 8;
serialReq->io_StopBits = 1;
serialReq->io_RBufLen = 4096; /* receive buffer size */
serialReq->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)serialReq);
```
### Write Data
```c
serialReq->IOSer.io_Command = CMD_WRITE;
serialReq->IOSer.io_Data = "Hello Serial\r\n";
serialReq->IOSer.io_Length = 14;
DoIO((struct IORequest *)serialReq);
```
### Read Data
```c
/* Check how many bytes are waiting: */
serialReq->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)serialReq);
ULONG waiting = serialReq->IOSer.io_Actual;
if (waiting > 0) {
serialReq->IOSer.io_Command = CMD_READ;
serialReq->IOSer.io_Data = buffer;
serialReq->IOSer.io_Length = waiting;
DoIO((struct IORequest *)serialReq);
/* buffer now contains received data */
}
```
### Serial Debugging
Many developers use a null-modem cable to a terminal for kernel debugging:
```c
/* Kprintf — ROM debug output via serial (ROMTags/exec): */
/* This bypasses serial.device entirely — writes directly to SERDAT */
void KPrintF(const char *fmt, ...); /* available in debug ROMs */
/* Sushi/Sashimi — capture serial debug output on another Amiga */
```
---
## References
- NDK39: `devices/serial.h`
- HRM: *Amiga Hardware Reference Manual* — Serial Port chapter
- ADCD 2.1: serial.device autodocs