Block Driver Specification
==========================

Version history
---------------
   Rev 2.12  17 Aug 1994, Hugo Fiennes
   -----------------------------------
      - Last known release by the original author.

   Rev 2.00  27 Nov 2002, Paul Reuvers
   -----------------------------------
      - Internal32 added to run on 32-bit RISC OS.
      - Version number of Internal32 changed to 2.xx.
      - Flag added to show 32-bit compliancy.
      - Flag added to show non-26-bit compliancy.
      - Fixed flushing of TX and RX buffers.

Contact
-------
Hugo Fiennes:
  Contact me on 0749 670058 (altman@cryton.demon.co.uk, fidonet 2:255/102.0)
  for information about the latest version of the spec.

Paul Reuvers:
   support@xat.nl
   X-Ample Technology bv, Elzentlaan 43, 5611 LH Einbdhoven, The Netherlands.
   Phone: +31 (0)40 2940297

Aim
---
To provide a standard way for applications to access serial devices. Any
application supporting block drivers can be used with many serial devices,
with no modification required to the application code - and it's easier
to use than the serial SWIs anyway!

Info
----
This standard is public domain. The drivers supplied are freely distributable
but  1994 Hugo Fiennes of The Serial Port. If you intend to use the block
drivers, please distribute the whole block driver package (inc sample source,
this file, and the complete !SerialDev application) with your program,
making sure that you are distributing the latest version (available from
The World of Cryton BBS, Arcade BBS, and ftp.demon.co.uk in the /pub/archimedes
directory).

An application called !SerialDev holds the drivers - in your application !Run
sequence you should check to see if <SerialDev$Path> is set, and if not, set
it to your application directory, inside which is Modules.Internal at least,
for your application to default to the internal port.

Eventually the idea is to have !SerialDev hold an application that handles
the installation in a 'pretty way' - eg dragging new drivers to a window to
install them, this would check to see if the driver was a later version of an
existing driver and if so replace the old one, otherwise it would install the
driver. Maybe this application could look a bit like ArtWorks !FontInst.
Hint, hint, somebody write one...

The drivers each have their own directory just in case, possibly extensions
with !Run files, modules, etc relating to the driver could be stored there.
Of course, drivers know their own name and could load files into RMA on
initialisation now and cause no problems.

ARCterm 7 1.44 and later use drivers of this specification. In this
archive I have included some other drivers, documented below.
Other programs that support block drivers are: Binkleyterm (2.11+),
Hearsay 2 (2.17+), ARCfax (1.06+), ARCbbs (1.63+), RISCbbs (1.02+),
Netway.

C headers have been provided for C programmers. BASIC/Assembler people
should have no problems working it out either - a small application,
'Example' is provided which will work with any block driver module to
provide a very simple terminal program.

REVISION 4 : Added 'wont empty' and 'dont overlay io' flags for pipes and
             (unfixed) RO3.10 serial ports.

REVISION 5 : Intialise can now return an error string.

REVISION 6 : More information on calling initialise.

REVISION 7 : Pipe drivers now support 'peek byte' - return next byte in
             buffer without removing it.

REVISION 8 : Internal port with PC cable now works with DCD low (bit 1
             on SerialOp 0 now set). OSBYTE 152 used for peek byte
             (for some reason the proper legal method doesn't work well).

REVISION 9 : All drivers must now store R14 on the stack so they can
             be called from supervisor mode.

REVISION 10: Basically this release just tidied the internal driver for
             RiscPC use - hitting the metal isn't required anymore to
             set high rates, so it isn't done. Still needed on A5000,
             A3010, A3020, A4000 & A4 though.

             Inquiry initialise (see below) added for JP :-) This is
             implemented in Internal, SP_Dual and Pipe drivers. It's
             only really necessary in the Internal (sets baud tables)
             and the SP_Dual (counts installed ports) drivers.

REVISION 10a:"I must not release software without testing it" :-)
             A little buglet in the SP_Dual drivers was pointed out to
             me, "they don't work!". This has now been fixed. Drivers
             should now also preserve the PSR (Internal, Dummy, Pipe,
             and SP_Dual do) just in case.

Internal driver
---------------

There are two version of this: Internal and InternalPC - the PC version
expects a standard PC serial cable, which will only work properly on A5000
or later machines (some early A5000s might have problems too).

Needs RO3.1 for block operations.

On a 'new hardware' machine (ie A5000 or later) will support 38400, 57600,
115200 automatically. Remember that these rates may well not be reliable
due to the lack of FIFO on the serial chip. These rates are acheived by
writing directly to the serial chip, which is definitely not Acorn-approved.
Beware!

On RiscPCs all rates to 115200 should be perfectly reliable as the hardware
now includes a FIFO.

Cables - the Acorn wiring for a modem is this:

   Acorn 9w female               Modem 25w male
   ---------------               --------------
       1-4-8                           20
         2                              3
         3                              2
         5                              7
         6                              5
         7                              4
         9                              8

And the PC wiring is this:

   Acorn 9w female               Modem 25w male
   ---------------               --------------
         1                              8
         2                              3
         3                              2
         4                             20
         5                              7
         6                              6 (not usually used much)
         7                              4
         8                              5
         9                             22 (not usually used much)

Serial Port Dual Serial
-----------------------

Again, there are 2 versions: SP_Dual and SP_DualPC, the PC version expects
a standard PC serial cable.

Since release 9, the Xon/Xoff flags are cleared every time flow control
is changed to stop things sticking if an Xoff has been received.

PipeA and PipeB
---------------

This will autoload the ARCbbs_Pipes module (contained in the PipeA directory)
if necessary.

The idea is, you open a port (0-15) on pipeA and data sent appears in the
input of the corresponding port on pipeB (and vice-versa). DTR at one end
is translated to DCD at the other (ditto for RTS-CTS). In this way, any
application which supports the block driver spec can talk to another, for
example, with ARCbbs and the ARCterm modem server on the same machine,
some ARCbbs ports could be given over to network access via the modem
server.

The pipes use the flag 'wont empty' as you can't wait for the pipe to
'finish sending' as the other end of the pipe may be waiting for the same
thing (unlike a serial port, where the data will go away eventually).

The pipes are 2k long in each direction.

Acorn Telnet (Needs Acorn's TCP/IP protocol suite)
------------
*Note! Does not store R14_SVC

This is only in testing, but is supplied as it might be useful. The coding
is possibly quite inefficient, but it works. You require !Internet and
!Telnet to have been run before trying to use the driver. It will prompt
for a host name - type one, or an internet address. You can add ',xx'
where xx is the port number to telnet into. DCD as reported by modem
status will go high when a sucessful connection is made. Dropping DTR
then raising it again will clear any current call.

Known bugs: You can't have multiple sessions - if you load another emulator
and run telnet the port_claim message will stop the first one - possibly a
'dynamic' port number (returned by init?) should be put into the spec to
cater for things like this.


Dummy (/dev/null)
-----

This is a dummy driver, for when you want somewhere to trash data. It
always shows CTS, DSR and DCD, and will completely ignore any data you
send to it. It never has any data to give you.

II_Dual driver
--------------
*Note! Does not store R14_SVC

This is a temporary stop-gap until v3.xx software is available for the II
card. The port number you specify is the II port number -1, ie II port 3
would be specified as port 2. If you want to use the internal port while
using II ports, you need the Internal2 driver. Both of these drivers
rely on the poll entry being called directly after each wimp poll, to set
the current port.

Econet driver (not supplied with this release)
-------------

This works with ARCterm's new 16-line modem server to allow remote serial
access. To support connection, etc, it has 3 special functions:

Connect (function code 128)
  r1=handle/net/station (handle in bits 16-23,net in bits 8-15, station in 0-7)
  r2-> password, null terminated

  Tries to set up a connection with the modem server. Returns 0 for success,
  1 for no reply, 2 for already connected, or a pointer to an error block if
  r0 is 'big' on return.

Disconnect (function code 129)
  Disconnects from the modem server.

Scan for modem servers (function code 130)
  r1=buffer to fill of format:
     0    station
     1    net
     2    handle
     3    modem driver number as defined in the modem server config file
     4-63 modem ID string (null terminated)
  r2=max number of entries table can handle

-------------------------------------------------------------------------------
Driver layout
-------------------------------------------------------------------------------

0x000 Entry point to call routines

      In:  r0=function code
           r1-r3=data

      Out: r0=result

      NOTE! CHANGE IN REVISION 9!
      |
      | This entry point can be called in EITHER user or supervisor mode, so
      | R14 should always be pushed on the stack (STMFD R13!,{R14}) and be used
      | to return from the driver so that r14_svc is preserved if the driver is
      | called when in supervisor mode.
      |

      r0-r3 can be corrupted, r4-r12 should be preserved. r14 contains the
      return address

      Callers note that r13 should point to a full, descending stack
      with a decent amount of space free on it.

      Example handler code follows:

      entry
            STMFD R13!,{R14}
            CMP   R0,#((endoftable-table)/4)
            ADDCC PC,PC,R0,LSL#2
            LDMFD R13!,{PC}

      table
            B     func_0
            B     func_1
      endtable

0x080 Driver information string (31 bytes max, 0 terminated)
0x0A0 Manufacturer information string (31 bytes max, 0 terminated)
0x0C0 Version number (top 16 bits major, low 16 bits minor)
0x0C4 Driver flags

      0x00000001 - More than one port availiable
      0x00000002 - Supports split rates
      0x00000004 - Has >1 byte hardware FIFO
      0x00000008 - Can use Set control lines to generate a break
      0x00000010 - Requires polling (by function 19)
      0x00000020 - Won't empty (is a shared buffer)
      0x00000040 - Supports block get/put operations
      0x00000080 - Prefer not to overlap serial IO and disk IO
      0x00000100 - Supports inquiry initialise

      Flags added by Andy Ray
      -----------------------
      0x00000200 - Supports return of RISC OS TX and RX buffers
                   (function 20 and 21)

      Flags added by Paul Reuvers, 27 Nov 2002
      ----------------------------------------
      0x00010000 - Code is 32-bit compliant  (bit 16 set)
      0x00020000 - Code is NOT 26-bit compatible (bit 17 set)
      0x00040000 - Allows flags in the top 24 bits of the port number in r1
                   on entry to 'Driver_Initialise'

      0xdd...... - Top byte is highest port number supported (numbered from 0)
0x0C8 Driver number. This is allocated by me, and always has the lowest byte
      as 0. The purpose of the driver number is for the Device_Claim protocol:
      when a serial port is specified, the port number is used to specify
      which port is to be claimed/released. The internal port is port 0 and
      driver number 0. To make the port number to use you add the sub-port
      number and the driver number together. eg, say the II dual card was
      driver number 1 (0x00000100) and you wanted to claim port 5, you
      would use the port number 0x00000105. This is unique and hopefully
      would cause no problems.

      PORT NUMBERS PASSED TO BLOCK DRIVERS ARE THE LOWER 8 BITS ONLY: THEY DO
      NOT INCLUDE THE DRIVER NUMBER.

      Currently allocated driver numbers:

        0 - Internal serial (i.e. Internal, InternalPC, Internal32)
        1 - II dual serial
        2 - Serial port dual serial
        3 - Internal serial with PC cable
        4 - Brainsoft Multipod (Kelvin Hill, #179 on Cryton)
        5 - Acorn telnet interface
        6 - Serial port dual serial with PC cable

      100 - Remote econet driver
      128 - Virtual pipe (end A)
      129 - Virtual pipe (end B)

0x0CC - 0x0FF reserved

0x100 Supported speed table. One word per speed, terminated with a null word.

0x180-> driver code.

Function codes
--------------

r0=0  Put byte
      --------
      r1=port number
      r2=byte to send

      Returns with r0=-1 if byte not inserted, r0=0 if byte inserted into
      TX queue.

r0=1  Get byte
      --------
      r1=port number

      Returns with r0=-1 if no byte availiable, r0=byte if a byte was removed.

r0=2  Put block
      ---------
      r1=port number
      r2=pointer to block
      r3=number of bytes to try and insert

      Returns with r0=number of bytes sucessfully inserted.

r0=3  Get block
      ---------
      r1=port number
      r2=pointer to block
      r3=maximum number of bytes to put into buffer

      Returns with r0=number of bytes put in buffer.

r0=4  Check TX buffer
      ---------------
      r1=port number

      Returns with r0=number of bytes free in TX buffer

r0=5  Check RX buffer
      ---------------
      r1=port number

      Returns with r0=number of bytes used in RX buffer

r0=6  Flush TX buffer (and hardware FIFO if applicable)
      ---------------
      r1=port number

r0=7  Flush RX buffer (and hardware FIFO if applicable)
      ---------------
      r1=port number

r0=8  Control lines
      -------------
      r1=port number
      r2=-1 to read or new settings

      Returns r0=control line settings

      b0=DTR
      b1=RTS
      b2=If set, set TX data active (ie break state)

r0=9  Read modem control lines
      ------------------------
      r1=port number

      Returns r0=control line status

      b0=CTS
      b1=DSR
      b2=RI
      b3=DCD

r0=10 Read RX errors
      --------------
      r1=port number

      Returns r0=bitset of errors seen since last read RX errors.

      b0=Overrun error
      b1=Parity error
      b2=Framing error
      b3=Break received

r0=11 Send break
      ----------
      r1=port number
      r2=break time (in centiseconds)

      This does not return until the break has been sent - although some
      serial ports could multitask when sending a break, the internal port
      can't. Check the driver flags to see if you can use a multitasking
      break before using this call.

r0=12 Examine byte (like Get byte but leaves it in the buffer)
      ------------
      r1=port number

      Returns with r0=-1 if no byte availiable, r0=byte if a byte was
      returned.

r0=13 TX Speed
      --------
      r1=port number
      r2=speed to set or -1 to read

      Returns with r0=speed.

r0=14 RX Speed
      --------
      r1=port number
      r2=speed to set or -1 to read

      Returns with r0=speed.

r0=15 Set word format
      ---------------
      r1=port number
      r2=word format to set or -1 to read

      Returns with r0=word format.

r0=16 Set flow control
      ----------------
      r1=port number
      r2=flow control method to set or -1 to read

      Returns with r0=method

      0=no flow control
      1=hardware
      2=xon/xoff
      3=both

r0=17 Initialise driver
      -----------------
      r1=port number
      r2=parameter string (optional)

      r1 hold the port number as usual, however if bit 18 of the DriverFlags
      word is set, you may pass optional flags in the top 24 bits of r1.
      Currently the following flags are defined:

         bit 8 = Device is shared (i.e. allows multiple users).

      r3 = flags (or 0 if not used) [added by PRE, 16 Dec 2003]

      r2 optionally points to a null terminated string which can specify
      device options.

      Returns with r0 pointing to error string if
      initialisation unsucessful, otherwise r0=0.

      NOTE! Do not read the baud rate tables or driver flags UNTIL AFTER
      the intialise driver entry has been called. This allows for drivers
      to configure themselves to the available hardware and adjust the
      services offered accordingly.

      Release 10: There is now a flag, 'supports inquiry initialise' (see
      above) which allows you to call the initialise entry with r1=-1,
      which will not touch any hardware, just set all the baud tables,
      driver flags, and count the number of ports installed (if necessary),
      so you can read them and set up menus, etc.

r0=18 Close down driver
      -----------------
      r1=port number

r0=19 Poll driver
      -----------
      r1=port number

      This should be called regularly (eg in a polling loop) for the driver
      to perform polling tasks - eg the econet driver needs to check internal
      buffers and poll econet protocol tasks. Polls can be as infrequent as
      three or four times a second : if a driver needs polling more often
      than that, it should install a module and hook onto a vector somewhere.

r0=20 Get TX buffer
r0=21 Get RX buffer
