Simple Device Drivers
A simple device driver can be added by linking a block in the common heap by means of MT_LIOD.
The block must have at least four long words.
Address | Item |
---|---|
$00 | Space for link |
$04 | Address of I/O routine |
$08 | Address of OPEN routine |
$0C | Address of CLOSE routine |
The I/O sub system (IOSS) accesses these routines, in supervisor mode, to satisfy requests to use the device. That's probably why the block is called the access layer.
Of course the I/O, OPEN and CLOSE routines have to be written.
OPEN Routine
On entry to the OPEN routine the IOSS has set the registers as follows. The requirement on exit is also shown.
On entry | On exit | |
---|---|---|
D3.L | Open type | - |
A0.L | Pointer to device name | Address of channel definition block |
A3.L | Assumed start of driver definition block | - |
A6.L | System variables | - |
The OPEN routine must first check the device name and then set up the channel block. The device name should be checked by IO_NAME. If all is well space for the channel block should be allocated by the vector MM_ALCHP. THe IOSS will fill in the first $18 bytes of this block and will also set the entry in the Channel Table.
CLOSE Routine
On entry to the CLOSE routine the IOSS has set the registers as follows.
A0.L | Start of channel definition block |
A3.L | Assumed start of driver definition block |
A6.L | System variables |
The space allocated for the channel block must be returned to the heap by the vector MM_RECHP.
I/O Routine
On entry to the I/O routine the registers are set by the IOSS as shown.
D0.L | Operation type |
D1.L | Parameter |
D2.L | Parameter |
D3.L | 0 on 1st entry, 1 on subsequent entries |
A0.L | Channel definition block |
A1.L | Parameter |
A2.L | Parameter |
A3.L | Assumed start of driver definition block |
A6.L | System variables |
Notes
- The parameters in D1, D2, A1 and A2 as well as the value in D0 are what you would expect for a Trap #3 call.
- Registers D2-7/A2-5 can be used as required.
- D1 and A1 can be set for convenience on re-entry if needed.
The device driver need only have three routines, test for pending input, read a byte and send a byte. The more complex operations can be covered by the vector IO_SERIO.
The MIM Device
Here is an example of the coding for a very simple device which just accesses RAM.
This device has no parameters. Thus OPEN#3,MIM is all that is needed. (All types of open will work. Ie OPEN_IN, OPEN_NEW OPEN_OVER and even OPEN_DIR operate just like OPEN.) First set the addresses for IO_SERIO.
lea ptrs,a0 lea io_ready,a2 move.l a2,(a0)+ lea fetch,a2 move.l a2,(a0)+ lea send,a2 move.l a2,(a0)
Now set the addresses in the linkage block and link it in
lea linkage+4,a0 lea IO,a2 move.l a2,(a0)+ lea open,a2 move.l a2,(a0)+ lea close,a2 move.l a2,(a0) lea linkage,a0 moveq #mt_liod,d0 link in MIM trap #1 moveq #0,d0 bad_exit rts
Linkage Block
This linkage block consists of 4 long words:
$00 | Link to next device |
$04 | Pointer to IO routine |
$08 | Pointer to OPEN routine |
$0C | Pointer to CLOSE routine |
linkage dcb.l 4,0 4 long zeros * * This gets space from the heap for the 24 bytes needed for the minimum * channel block plus 4 bytes to hold the address to which MIM currently * points. * open movea.w io_name,a4 jsr (a4) bra bad_exit ----> bra bad_exit ----> bra ok dc.w 3 dc.b 'MIM',0 dc.w 0 No parameters ok moveq #$1c,d1 get 28 bytes for . . movea.w mm_alchp,a4 . . the channel block jmp (a4) * close movea.w mm_rechp,a4 return to heap jmp (a4) * IO cmpi.b #fs_posab,d0 beq posab cmpi.b #fs_posre,d0 beq posre movea.w io_serio,a4 Deal with other trap #3 . . jsr (a4) . . calls by IO.SERIO * * These three pointers are to: * * io ready - here does nothing * fetch a byte to D1 * send a byte from D1 * * NOTE D1 has to end up containing the current position of the file * which is at $18(A0) * ptrs dcb.l 3,0 rts * fetch movea.l $18(a0),a1 move.b (a1),d1 Set the next byte to D1.B fetch_1 addq.l #1,$18(a0) Increment the current address io_ready moveq #0,d0 rts * send movea.l $18(a0),a0 move.b d1,(a0) bra fetch_1 * posab move.l d1,$18(a0) Set the current address bra io_ready * posre add.l d1,$18(a0) Increment the current address . . move.l $18(a0),d1 . . and set this in D1.L bra io_ready