Initialisation
==============

HAL_Init(unsigned int *riscos_header)

   Will be called after the MMU is turned on, before any other entries points.
   The HAL workspace will be filled with zeroes.


Interrupts
==========

The HAL must provide the ability to identify, prioritise and mask IRQs, and the ability
to mask FIQs. RISC OS supplies the ARM's processor vectors, and on an IRQ calls the HAL
to request the identity of the highest priority interrupt.

IRQ and FIQ device numbers are arbitrary, varying from system to system. They should be
arranged to allow quick mappings to and from hardware registers, and should ideally
be packed, starting at 0.

HAL_IRQEnable
HAL_IRQDisable
HAL_IRQClear
HAL_IRQSource (get highest priority asserted IRQ)
HAL_IRQDisableAll

HAL_FIQEnable
HAL_FIQDisable
HAL_FIQClear
HAL_FIQDisableAll

Timers
======

The HAL must supply at least one timer capable of generating periodic
interrupts. Each timer should generate a separate logical interrupt, and the
interrupt must be latched. The timers must either be variable rate (period is
a multiple of a basic granularity), or be fixed rate (period = 1*granularity).
Optionally, the timer should be capable of reporting the time until the
next interrupt, in units of the granularity.

int HAL_Timers(void)

  Returns number of timers. Timers are numbered from 0 upwards. Timer 0
  must exist.

int HAL_TimerDevice(int timer)

  Returns device number of timer n

unsigned int HAL_TimerGranularity(int timer)

  Returns basic granularity of timer n in ticks per second.

unsigned int HAL_TimerMaxPeriod(int timer)

  Returns maximum period of the timer, in units of Granularity. Will be 1
  for a fixed rate timer.

void HAL_TimerSetPeriod(int timer, unsigned int period)

  Sets period of timer n. If period > 0, the timer will generate interrupts every
  (period / granularity) seconds. If period = 0, the timer may be stopped.
  This may not be possible on some hardware, so the corresponding interrupt
  should be masked in addition to calling this function with period 0.
  If period > maxperiod, behaviour is undefined.

unsigned int HAL_TimerPeriod(int timer)

  Reads period of timer n. This should be the actual period in use by the
  hardware, so if for example period 0 was requested and impossible, the
  actual current period should be reported.

unsigned int HAL_TimerReadCountdown(int timer)

  Returns the time until the next interrupt in units of granularity, rounded down.
  If not available, 0 is returned.

Counter
=======

The HAL must supply a counter that varies rapidly, appropriate for use for
sub-millisecond timing. On many systems, this counter will form part of
timer 0 - as such it is not required to operate when timer 0 is not running.
On other systems, the periodic timers may have no readable latch, and a
separate unit will be required.

The counter should count down from (period-1) to 0 continuously.

unsigned int HAL_CounterRate(void)

  Returns the rate of the counter in ticks per second. Typically will
  equal HAL_TimerGranularity(0).

unsigned int HAL_CounterPeriod(void)

  Returns the period of the counter, in ticks. Typically will equal
  HAL_TimerPeriod(0).

unsigned int HAL_CounterRead(void)

  Reads the current counter value. Typically will equal
  HAL_TimerReadCountdown(0).

unsigned void HAL_CounterDelay(unsigned int microseconds)

  Delay for at least the specified number of microseconds.


Non-volatile memory
===================

The HAL should provide at least 240 bytes of non-volatile memory. If no
non-volatile memory is available, the HAL may provide fake NVRAM contents
suitable for RISC OS - however, it is preferable that the HAL just state that
NVRAM is not available, and RISC OS will act as though a CMOS reset has been
performed every reset.

NVRAM is typically implemented as an IIC device, so the calls are permitted
to be slow, and to enable interrupts. The HAL is not expected to cache
contents.

If the HAL has no particular knowledge of NVMemory, then it may
just say that "NVMemory is on IIC", and the OS will probe for CMOS/EEPROM
devices on the IIC bus.

unsigned int HAL_NVMemoryType(void)

  Returns a flags word describing the NVMemory
        bits 0-7: 0 => no NVMemory available
                  1 => NVMemory may be available on the IIC bus
                  2 => NVMemory is available on the IIC bus, and the
                       device characteristics are known
                  3 => the HAL provides NVMemory access calls.
        bit 8:    NVMemory has a protected region at the end
        bit 9:    Protected region is software deprotectable
        bit 10:   Memory locations 0-15 are readable
        bit 11:   Memory locations 0-15 are writeable

  If bits 0-7 are 0 or 1 no other NVMemory calls need be available,
  and bits 8-31 should be zero.

  If bits 0-7 are 2, Size, PageSize, ProtectedSize, Protection and IICAddress
  calls must be available.

  If bits 0-7 are 3, all calls except IICAddress must be available.

unsigned int HAL_NVMemorySize(void)

  Returns the number of bytes of non-volatile memory available. Bytes 0-15
  should be included in the count, so for example a Philips PCF8583
  CMOS/RTC device (as used in the Archimedes and Risc PC) would be described
  as a 256-byte device, with locations 0-15 not readable. More complex
  arrangements would have to be abstracted out by the HAL providing its own
  NVMemory access calls.

  This is to suit the current RISC OS Kernel, which does not use bytes 0-15.

unsigned int HAL_NVMemoryPageSize(void)

  Returns the number of bytes in a page of NVMemory. The HAL can be assured
  that block writes to NVMemory will not straddle multiple pages (whether by
  IIC operation or HAL_NVMemoryWrite call).
  Returns 0 if page splitting is not required.

unsigned int HAL_NVMemoryProtectedSize(void)

  Returns the number of bytes of NVMemory that are protected. These should
  be at the top of the address space. The OS will not attempt to write
  to those locations without first requesting deprotection (if available).
  Returns 0 if bit 8 of the flags is clear.

void HAL_NVMemoryProtection(bool)

  Enables (if true) or disables if (false) the protection of the software
  protectable region. Does nothing if bits 8 and 9 not both set.

unsigned int HAL_NVMemoryIICAddress(void)

  Returns a word describing the addressing scheme of the NVRAM.
        bits 0-7:  IIC address
        
  This will always be on bus zero.

int HAL_NVMemoryRead(unsigned int addr, void *buffer, unsigned int n)

  Reads n bytes of memory from address addr onwards into the buffer supplied.
  Returns the number of bytes successfully read. Under all normal circumstances
  the return value will be n - if it is not, a hardware failure is implied.
  Behaviour is undefined if the address range specified is outside the NVMemory,
  or inside bytes 0-15, if declared unavailable.

int HAL_NVMemoryWrite(unsigned int addr, void *buffer, unsigned int n)

  Write n bytes of memory into address addr onwards from the buffer supplied.
  Returns the number of bytes successfully written. Under all normal circumstances
  the return value will be n - if it is not, a hardware failure is implied.
  Behaviour is undefined if the address range specified is outside the NVMemory.
  Writes inside the a protected region should be ignored.

I�C bus
=======

Many hardware designs have an I�C bus. Often, it is used only to place non-
volatile memory on, but in other systems TV tuners, TV modulators,
microcontrollers, and arbitrary expansion cards may be fitted.

Low-level and high level APIs are defined. An arbitrary number of buses are
supported, and each can be controlled by either the low or high level API.
The OS should normally only use one fixed API on each bus - mixing APIs may
not have good results.

The low-level API requires the OS to control the two lines of the bus
directly. The high-level API currently covers version 2.1 of the I�C
protocol, and allows high-level transactions to be performed.

It is expected that a HAL will always provide the low-level API on each
bus, where possible in hardware. Using this, the OS can provide Fast mode
single or multi-master operation. The HAL may wish to provide the high-level API
where a dedicated I�C port with hardware assistance is available; this will
further permit High-speed and slave operation.

As it is possible that some HAL APIs (eg NVMemory), although abstracted at
this API layer, are still actually an I�C device, a matching set of high-level
I�C calls are provided in the OS. These give the HAL access to the OS I�C engine,
which will make low-level HAL calls. This saves the HAL from implementing the
full I�C protocol. To illustrate this diagramatically:

    +----------+ NVMem_Read +------------+  NVMemoryRead  +------------+
    |          | ---------> |            | ------------>  |            |
    |   App    |            |     OS     |  IICTransmit   |    HAL     |
    |          |            |            | <------------  |            |
    |          |            |            |  IICSetLines   |            |
    |          |            |            | ------------>  |            |
    +----------+            +------------+                +------------+

int HAL_IICBuses(void)

  Returns the number of IIC buses on the system.

unsigned int HAL_IICType(int bus)

  Returns a flag word describing the specified IIC bus.
        bit 0: Bus supplies the low-level API
        bit 1: Bus supplies the high-level API
        bit 2: High-level API supports multi-master operation
        bit 3: High-level API supports slave operation
        bit 4: High-level API supports background operation
       bit 16: Bus supports Fast (400kbps) operation
       bit 17: Bus supports High-speed (3.4Mbps) operation
   bits 20-31: Version number of I�C supported by high-level API, * 100.

Low level API
-------------

The low-level calls should be instantaneous. Interrupt status may not be altered.

The following structure is used:

   typedef struct { int SDA, SCL } IICLines;

Note the "__value_in_regs" keyword, which signifies that the binary ABI expects
SDA and SCL to be returned in registers a1 and a2.

__value_in_regs IICLines HAL_IICSetLines(int bus, IICLines lines)

  Sets the SDA and SCL lines on the specified bus. A 0 value represents
  logic LOW, 1 logic HIGH. The function then reads back and returns
  the values present on the bus, to permit arbitration.

__value_in_regs IICLines HAL_IICReadLines(int bus);

  Reads the state of the IIC lines on the specified bus, without changing
  their state.

High level API
--------------

The high-level interface process a single transfer at a time (from the
initial START to the STOP). It is designed to support background operations.

irq_descriptor HAL_IICDevice(int bus);

  Returns the interrupt specification for the bus. This is not meaningful
  if bit 4 of the flags word above is not set. The OS will claim the interrupt
  and call HAL_IICMonitorTransfer() each time it occurs.


#define IICSTATUS_COMPLETED  0
#define IICSTATUS_INPROGRESS 1  /* transfer proceeding in background */
#define IICSTATUS_NOACK      2  /* slave failed to acknowledge */
#define IICSTATUS_BUSY       3  /* IIC system busy (call back later) */
#define IICSTATUS_SLAVE      4  /* reserved for slave operations */
#define IICSTATUS_ERROR      5  /* other error prevented completion */

typedef struct iic_transfer
{
  unsigned addr:8;
  unsigned :22;
  unsigned checksumonly:1;
  unsigned nostart:1;
  union
  {   unsigned checksum;
      void *data;
  } d;
  unsigned len;
} iic_transfer;

int HAL_IICTransfer(int bus, unsigned n, iic_transfer transfer[static n]);

  Initiates an IIC transfer. The transfer shall progress in the background
  if bit 4 is set, in which case the normal return should be IICSTATUS_INPROGRESS.
  The OS will call HAL_IICMonitorTransfer each time an interrupt occurs - this
  will allow the HAL to progress through the transfer if it's not totally automatic.
  If the transfer happens in the foreground, return values are as for
  IICMonitorTransfer (see below).

  If an IIC transfer is currently in progress, the call may return BUSY and the
  caller should retry later - although if background transfers are supported it may
  queue the transfer and return INPROGRESS. If another master is driving the bus,
  it should silently wait until the bus is free (in the background or foreground as
  appropriate). If we lose arbitration, the transfer should be retried when the bus
  becomes free.

  transfer[] is an array of n transfer descriptors. Each descriptor describes part
  of the transfer. The direction of the subtransfer is determined by the least
  significant bit of addr. If nostart is 0, a START is first transmitted followed
  by addr, otherwise the data flow continues where the previous subtransfer
  left off. nostart must be 0 for the first subtransfer.

  For writes, len bytes of data are read from "data" and transmitted. For reads,
  len bytes are received and written to "data", unless "checksumonly" is 1, in which
  case the len received bytes are summed and the (32-bit) sum stored in checksum.

  If background transfers are in use, the transfer[] array and the data blocks must
  remain available in unpaged memory for the duration of the transfer.

  IICTransfer is re-entrant, but may return BUSY if re-entered (see above).

  
int HAL_IICMonitorTransfer(int bus);

  Will be called on every interrupt, and should return the status of the transfer
  currently in progress. If no transfer is in progress, the call should return
  COMPLETED.

  If the transfer is still in progress, INPROGRESS is returned.

  If the slave failed to acknowledge (either the address or any later transmitted
  byte), NOACK is returned.

  If we have been addressed as a slave, the call returns SLAVE. More details to
  be confirmed.

  BUSY is not a valid response.

  This will only be called in response to an IIC interrupt, with interrupts disabled.
  The interrupt shall be cleared by this call.

  Unknown return codes will be ignored.


Machine ID
==========

unsigned int64 HAL_MachineID(void)

  Returns a 64-bit unique machine identifier,this may later be used to
  form the ethernet MAC address but otherwise has no great significance on non
  networked machines.

  The top 8 bits are a CRC,based on the same algorithm the original DS2401 
  used - if the CRC fails zero will be substituted

ControllerAddress
=================

void *HAL_ControllerAddress(unsigned controller)

  Asks the HAL where various controllers might or might not be.
  Podule manager uses this information to determine at run time whether or not
  to bother doing anything.
  
  Returns r0=logical address of the chosen controller,or zero
  
     0 = EASI card access speed control
     1 = EASI space(s)
     2 = VIDC1
     3 = VIDC20
     4 = S space base (IOMD,podules,NICs,blah blah)
     5 = Extension ROM(s)

Matrix Keyboard
===============

Many devices provide a matrix keyboard interface. The following calls
provide access to it. Interrupt driven operation, or high-level calls will be
defined later.

int HAL_MatrixColumns(void)

  Returns the number of columns available via the matrix interface.
  Columns are numbered from 0 to <num columns>-1.

unsigned int HAL_MatrixScan(int column).

  Returns a bitfield describing which rows are active on the specified column.
  Any timing issues, or the driving of the matrix between calls are left to
  the HAL.

Touchscreen
===========

PDA-type devices usually have a touchscreen as their primary pointing device.
This API provides a simple interface to a touchscreen. The calls are described
in terms of a resistive touchscreen, but other technologies should be mappable
onto it. Interrupt operation is yet to be defined.


unsigned int HAL_TouchscreenType(void)

  Returns a flags word indicating the type of touchscreen.
    bits 0-7: Touchscreen type   0=>none, 1=>resistive
    bit 8:    Interrupt operation supported
    bit 9:    Calibration not required
    bits 10-15: Reserved
    bits 16-21: Bits of precision available
    bits 22-31: Reserved

  "Calibration not required" indicates that the raw values returned map linearly
  onto the screen display area to a usable accuracy as follows:

   X,Y  (00000000,00000000) = bottom left of display area
   X,Y  (FFFFFFFF,FFFFFFFF) = top right of display area
   Pres  00000000-1FFFFFFF  = no touch
   Pres  20000000-3FFFFFFF  = light touch
   Pres  3FFFFFFF-7FFFFFFF  = touch
   Pres  80000000-FFFFFFFF  = firm touch

unsigned int HAL_TouchscreenMeasure(int meas)
  Performs a touchscreen measurement. Measurements are:
      0 = X position
      1 = Y position
      2 = pressure
      3 = X resistance
      4 = Y resistance
  
  "X" and "Y" need not actually be X and Y - rotation can be dealt with by
  calibration.

  All values are returned as unsigned 32-bit values in the range &00000000-&FFFFFFFF.
  If using, for example, a 10-bit DAC, the 10-bit value read should be placed at the
  top of the returned word. Ideally, the 10 bits should be replicated in lower bits
  (ABCDEFGH IJABCDEF GHIJABCD EFGHIJAB) to ensure the returned values fully span
  the 32-bit range.

  Resistance measurements can be used to compensate for large pressed areas causing
  shorts - subtract the instantaneous resistance from the instantaneous precision.
  (I think).

Serial ports
============

The RS232 serial UART is a fundamental peripheral on most current hardware. All