mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-12 16:16:28 +00:00
174 lines
4.2 KiB
Markdown
174 lines
4.2 KiB
Markdown
[← Home](../README.md) · [Driver Development](README.md)
|
|
|
|
# Exec Device Driver Framework
|
|
|
|
## Overview
|
|
|
|
An Amiga **device** is a shared library with additional I/O semantics. Devices handle hardware or protocol communication via `IORequest` messages. Understanding this framework is essential before writing any specific driver (network, graphics, audio).
|
|
|
|
---
|
|
|
|
## Device vs Library
|
|
|
|
| Feature | Library | Device |
|
|
|---|---|---|
|
|
| Base structure | `struct Library` | `struct Device` (extends Library) |
|
|
| Entry points | `Open`, `Close`, `Expunge`, LVO functions | `Open`, `Close`, `Expunge` + `BeginIO`, `AbortIO` |
|
|
| Communication | Direct function calls | `IORequest` messages via `DoIO`/`SendIO` |
|
|
| Concurrency | Caller's task context | Can have own task/interrupt context |
|
|
|
|
---
|
|
|
|
## Minimal Device Structure
|
|
|
|
```c
|
|
/* mydevice.h */
|
|
struct MyDevBase {
|
|
struct Device md_Device; /* MUST be first */
|
|
struct Library *md_SysBase;
|
|
struct Library *md_DOSBase;
|
|
/* ... device-specific state ... */
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Device Function Table
|
|
|
|
Every device must provide exactly these entry points in its function vector:
|
|
|
|
```c
|
|
/* Function table (same as library, plus BeginIO/AbortIO): */
|
|
static const APTR funcTable[] = {
|
|
(APTR) DevOpen, /* -6 (standard library Open) */
|
|
(APTR) DevClose, /* -12 (standard library Close) */
|
|
(APTR) DevExpunge, /* -18 (standard library Expunge) */
|
|
(APTR) DevReserved, /* -24 (reserved, must return 0) */
|
|
(APTR) DevBeginIO, /* -30 (start I/O operation) */
|
|
(APTR) DevAbortIO, /* -36 (abort pending I/O) */
|
|
(APTR) -1 /* end marker */
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## DevOpen
|
|
|
|
```c
|
|
LONG DevOpen(struct IORequest *ioreq, ULONG unit, ULONG flags,
|
|
struct MyDevBase *base)
|
|
{
|
|
/* Initialize per-unit state if needed */
|
|
struct MyUnit *u = &base->md_Units[unit];
|
|
|
|
ioreq->io_Device = (struct Device *)base;
|
|
ioreq->io_Unit = (struct Unit *)u;
|
|
ioreq->io_Error = 0;
|
|
|
|
base->md_Device.dd_Library.lib_OpenCnt++;
|
|
u->mu_OpenCnt++;
|
|
|
|
return 0; /* success */
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## DevBeginIO — The Core
|
|
|
|
```c
|
|
void DevBeginIO(struct IORequest *ioreq, struct MyDevBase *base)
|
|
{
|
|
struct IOStdReq *ios = (struct IOStdReq *)ioreq;
|
|
|
|
ios->io_Error = 0;
|
|
|
|
switch (ios->io_Command) {
|
|
case CMD_READ:
|
|
/* Handle synchronously or queue for async */
|
|
if (!(ios->io_Flags & IOF_QUICK)) {
|
|
/* Queue request — reply later via ReplyMsg */
|
|
AddTail(&unit->mu_ReadQueue, &ios->io_Message.mn_Node);
|
|
ios->io_Flags &= ~IOF_QUICK;
|
|
return; /* do NOT ReplyMsg yet */
|
|
}
|
|
/* ... do sync read ... */
|
|
break;
|
|
|
|
case CMD_WRITE:
|
|
/* ... */
|
|
break;
|
|
|
|
default:
|
|
ios->io_Error = IOERR_NOCMD;
|
|
break;
|
|
}
|
|
|
|
/* Complete the request: */
|
|
if (!(ios->io_Flags & IOF_QUICK)) {
|
|
ReplyMsg(&ios->io_Message);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## DevAbortIO
|
|
|
|
```c
|
|
LONG DevAbortIO(struct IORequest *ioreq, struct MyDevBase *base)
|
|
{
|
|
/* Remove from pending queue if found */
|
|
Forbid();
|
|
Remove(&ioreq->io_Message.mn_Node);
|
|
Permit();
|
|
|
|
ioreq->io_Error = IOERR_ABORTED;
|
|
ReplyMsg(&ioreq->io_Message);
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## IOF_QUICK — Synchronous Fast Path
|
|
|
|
The `IOF_QUICK` flag is critical:
|
|
- Caller sets `IOF_QUICK` in `ioreq->io_Flags`
|
|
- If device completes immediately, it leaves `IOF_QUICK` set → caller knows it's done (no `WaitIO` needed)
|
|
- If device queues the request, it **clears** `IOF_QUICK` → caller must `WaitIO`
|
|
|
|
```c
|
|
/* Caller pattern (DoIO does this internally): */
|
|
ioreq->io_Flags |= IOF_QUICK;
|
|
BeginIO(ioreq);
|
|
if (!(ioreq->io_Flags & IOF_QUICK))
|
|
WaitIO(ioreq);
|
|
```
|
|
|
|
---
|
|
|
|
## RomTag for Device
|
|
|
|
```c
|
|
static struct Resident romtag = {
|
|
RTC_MATCHWORD,
|
|
&romtag,
|
|
&endskip,
|
|
RTF_AUTOINIT,
|
|
1, /* version */
|
|
NT_DEVICE, /* ← not NT_LIBRARY */
|
|
0, /* priority */
|
|
"mydevice.device",
|
|
"mydevice 1.0",
|
|
&initTable
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- NDK39: `exec/devices.h`, `exec/io.h`
|
|
- ADCD 2.1: `DoIO`, `SendIO`, `WaitIO`, `AbortIO`
|
|
- RKRM: *Amiga ROM Kernel Reference Manual: Devices* — device driver chapter
|