QDOS Internals

Anything you never knew you wanted to know about the Sinclair QL.

User Tools

Site Tools


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.

$00Space for link
$04Address of I/O routine
$08Address of OPEN routine
$0CAddress 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 entryOn exit
D3.LOpen type -
A0.LPointer to device nameAddress of channel definition block
A3.LAssumed start of driver definition block -
A6.LSystem 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.LStart of channel definition block
A3.LAssumed start of driver definition block
A6.LSystem 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.LOperation type
D3.L0 on 1st entry, 1 on subsequent entries
A0.LChannel definition block
A3.LAssumed start of driver definition block
A6.LSystem variables


  • 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:

$00Link to next device
$04Pointer to IO routine
$08Pointer to OPEN routine
$0CPointer 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
          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
          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
qdosmsq/memory/sdrives.txt · Last modified: 2010/10/27 16:16 by george.gwilt