EXOS 2.1 Kernel Specification

6. Device Descriptors


6.1 The Device Chain

Every device driver has a device descriptor in RAM somewhere which defines the device's name, the address of the device driver code and various other details. They are kept in a linked list (called the device chain), and whenever a channel is opened, EXOS searches this list for a device with the correct name and opens the channel to that device.

The device chain is re­built whenever a reset EXOS call is made with the reset flags set to re­link devices (see section 11.2). This occurs at cold reset time and when a new applications program takes control. The chain is initially created with a descriptor for each of the built in device drivers, and also for any device drivers contained in extension ROMs.

The user, or a system extension, can link in new devices with a simple EXOS call. These will be added to the device chain but will be lost when the chain is re­built.


6.2 Details of Device Descriptors

The format of a device descriptor is given here. Each element is one byte, apart from the device name which is of a variable size. The offsets given are offsets from the DD_TYPE field since this is where the device chain pointers point to.

  -3   DD_NEXT_LOW   | 24-bit address of DD_TYPE field of next
  -2   DD_NEXT_HI    | descriptor. Address will be in Z80-page
  -1   DD_NEXT_SEG   | 1. End of chain indicated by
                     | DD_NEXT_SEG=0.

  +0   DD_TYPE         Must be zero.

  +1   DD_IRQFLAG      Defines device interrupt servicing.

  +2   DD_FLAGS        b0 set for video device. b1-b7 clear.

  +3   DD_TAB_LOW    | 24-bit address of device entry point
  +4   DD_TAB_HI     | table. Address must be in Z80-page 1.
  +5   DD_TAB_SEG    |

  +6   DD_UNIT_COUNT   Normally zero. Non-zero to allow
                       multiple devices with this name.

  +7.. DD_NAME         Device name string.                    

The DD_TYPE field is provided to allow for future expansion and also to enable a device to be disabled. This happens for example when a new device is linked in with the same name as an existing one. The old device will be disabled (unless DD_UNIT_COUNT is non­zero - see below).

The DD_IRQFLAG field has one bit for each of the four sources of interrupts in the Enterprise. If the appropriate bit is set then this device driver's interrupt routine will be entered whenever an interrupt of that type occurs. Any combination of bits can be set. The bit assignments are:

          b1 - Programmable sound interrupts
          b3 - 1Hz interrupts
          b5 - Video interrupts (50Hz)
          b7 - External interrupts (network)
    b0,2,4,6 - Should be zero.                

Bit­0 of the DD_FLAGS byte is used to control channel RAM allocation, which is different for video and non­video devices, as explained in section 7.3.

The entry point table address (DD_TAB_SEG, DD_TAB_HI and DD_TAB_LOW) points to a table of two byte entry addresses, one for each function which a device has to perform. The address given in the descriptor must be in Z80­page 1 since EXOS accesses the table there. However the entries in the table itself must be in Z80­page 3 since when EXOS calls a device it puts the devices code segment in page 3. The entry points themselves must all be in the same segment as the entry point table. The entries in the table are listed here and will be explained in the section on device drivers.

+00 - Interrupt (Need not be valid if DD_IRQFLAG=0)
+02 - OPEN CHANNEL
+04 - CREATE CHANNEL
+06 - CLOSE CHANNEL
+08 - DESTROY CHANNEL
+10 - READ CHARACTER
+12 - READ BLOCK
+14 - WRITE CHARACTER
+16 - WRITE BLOCK
+18 - CHANNEL READ STATUS
+20 - SET CHANNEL STATUS
+22 - SPECIAL FUNCTION
+24 - Initialisation
+26 - Buffer moved

The entry points printed in CAPITALS correspond directly to the relevant EXOS calls, the others are generated inside EXOS.

The DD_UNIT_COUNT field is normally zero but can be set non­zero to allow multiple devices of the same name to be handled by translating unit numbers. This is explained fully in section 11.1.

The DD_NAME field is the device name itself. The first byte of this is a length byte, followed by the characters of the name in ASCII. The name can be set up to 28 characters long and must consist of upper case letters only.


6.3 Extension ROM devices

At offset 0008/9h in every extension ROM is a pointer to the start of a chain of devices. If there are no devices drivers in the ROM then this pointer should be zero. Each element in the chain is basically a device descriptor as defined above, but with certain fields missing, or replaced by other information. The layout of one of these pseudo­descriptors is :

    XX_NEXT_LOW   | 16-bit pointer to XX_SIZE of next pseudo-
    XX_NEXT_HI    | descriptor. Must be in Z80-page 1.

    XX_RAM_LOW    | Amount of device RAM required.
    XX_RAM_HI     | 

    DD_TYPE       | These fields are exactly as in a complete
    DD_IRQFLAG    | device descriptor defined above.
    DD_FLAGS      | 
    DD_TAB_LOW    | The DD_TAB_SEG field can have any value
    DD_TAB_HI     | since EXOS fills this in when it links the 
    (DD_TAB_SEG)  | device
    DD_UNIT_COUNT |
    DD_NAME       |

--> XX_SIZE         Size of pseudo-descriptor (see text)      

The device chain pointer at the start of the ROM points to the XX_SIZE field of the first pseudo­descriptor, in Z80­page 1. Similarly the chain pointer (XX_NEXT_LOW and XX_NEXT_HI) in each pseudo­descriptor points to the XX_SIZE field of the next one, in Z80­page 1. The end of the chain is marked by a pseudo­descriptor with both SD_NEXT_HI and DD_NEXT_LOW set to zero.

The XX_SIZE field is a count of the number of bytes in the descriptor from DD_TYPE to the device name. Thus if the device name was one character long, XX_SIZE would be 9.

The main descriptor fields (all those starting with DD_) will simply be copied into RAM when the device is linked in, and a three byte link added to the start to create a complete device descriptor. Note however that EXOS fills in the DD_TAB_SEG field, since a ROM on the expansion stack cannot know what segment it will be in. This means that the entry point table must be in same segment as the pseudo­descriptor.

The XX_RAM_HI and XX_RAM_LOW fields define a 16­bit number which is the amount of device RAM which this device requires in the system segment. This number must be stored in two's complement and with an offset added to allow for the three byte link which EXOS puts on the start of the descriptor. If no device RAM is required then the value should be FFFEh (-2). If one byte is required it should be FFFDh(-3) and so on.

Whenever the device is entered register IY will point to its device descriptor, as will be explained in the section on device drivers. Since the device RAM is allocated immediately below the descriptor, the device RAM can be accessed relative to IY. If n bytes are requested then these can be accessed at addresses:

IY-4, IY-5, ···, IY-4-n

6.4 User Devices

User devices are those which are linked in with a link device EXOS call (code 21) which can be made either by the user or by a system extension. To link in a user device a complete device descriptor must be set up in RAM. All fields of this must be complete except for the 24­bit link ((DD_NEXT_SEG, DD_NEXT_HI and DD_NEXT_LOW). The EXOS call is then made with DE pointing to the DD_TYPE field of this descriptor, which can be in any Z80­page.

An area of device RAM can be requested by simply setting register BC to the amount required. This RAM will be allocated below the device RAM for any ROM extension devices. The device driver will be passed the address of this RAM area in register IX when it is first initialised. If n bytes are requested then they can be accessed at:

IX-1, IX-2, ···, IX-n

Note that this address will only be passed in IX on the first initialisation. It is the responsibility of the device driver to remember the address for future use, even when it is re­initialised such as after a warm reset.


Next chapter: Device Drivers



David Bouman. (dsbouma@cs.vu.nl)