
Subject: Buffer Manager
Author: David De Vorchik
Status: draft
History:
        04-Feb-91 DDV Recreated.
        04-Mar-91 DDV Added Buffer_Threshold
        04-Mar-91 DDV Added information on UpCalls.
        08-Mar-91 DDV Service_BufferStarting.
        13-Jun-91 TMD Updated
        12-Jul-91 TMD Updated spec of Buffer_Info
        17-Jul-91 TMD Updated


Issues - ignore on first reading.
======

* Should the use of r2 be switched to r3 on create to keep in line with
  register.


Buffer Manager
==============

The buffer manager provides a global buffer managing system, it provides a
set of calls for setting up a buffer, inserting and removing data from a
buffer and finally removing a buffer.  It is also possible to setup an area
of memory to be used as a buffer.

The buffer manager extends the INSV, REMV and CNPV to provide access to
these buffers and also allow block transfers.

The buffer manager is used by DeviceFS to provide buffers for the various
devices that can be accessed.  A device may be linked to a buffer supply
routines to be called when data enters the buffer and also a routine to be
called when a buffer is removed (or a new device is attached).

When registering or creating a buffer it is possible to force a specific
buffer handle, if this feature is not used then the manager will asign a
unique handle to it.  It should be noted that buffer handles are no longer
stored as eight bit quanities.

Block transfers are signalled by setting bit 31 of the buffer handle,
anything which can be performed one a byte by byte basis can also be
performed on a block, eg. examine the buffer contents.


SWI interface
=============

Buffer_Create
-------------

  in:   r0  = flags for the buffer
                bit  0 =0 => buffer is dormant and should be woken up when
                              data enters it
                bit  1 =1 => buffer generates "output buffer empty" events
                bit  2 =1 => buffer generates "input buffer full" events
                bit  3 =1 => buffer generates upcalls when free space
                              threshold crossed (from above or below)
                bits 4-31    reserved for future expansion, should be set
                              to zero on creation

        r1  = size of buffer to be created
        r2  = buffer handle to assign to buffer, -1 for does not matter

  out:  V =0 => r0  = buffer handle
        V =1 => r0 -> error block

This routine claims an area of memory from the RMA and links it into the
buffer list, if r2 =-1 then the buffer manager will attempt to find a unique
handle, if r2 <>-1 then the buffer manager will check that the handle
specified is unique and then if it is assign it to that buffer.

The flags word is used to indicate what should happen when data is being
inserted and removed from the buffer.

Bit 0 is used to indicate if the device attached to the buffer has
been woken up, when =0 then the device is dormant and needs to be woken.
When a device is attached and data is put into the buffer this bit is
checked, if it is =0 then the wake up code for the device will be called
allowing any device to wake up any hardware it may be driving and to start
processing data within the buffer.

Bit 1 is used to indicate if "output buffer empty" events should be issued for this buffer.

Bit 2 is used to indicate if "input buffer full" events should be issued for this buffer.

Bit 3 is used to indicate if buffer threshold UpCalls should be issued for this buffer.

On exit r0 contains the buffer handle being used or a pointer to an error
block.


Buffer_Remove
-------------

  in:   r0  = handle of buffer to be removed

  out:  V =1 => r0 -> error block, else preserved

This call should only be made on buffers created using Buffer_Create.

It attempts to de-register the buffer from the active list and assuming that
worked ok it will attempt to free the memory relating to that buffer.


Buffer_Register
---------------

  in:   r0  = flags for buffer (see above)
        r1 -> start of memory for buffer
        r2 -> end of buffer (+1)
        r3  = handle to be assigned to buffer (-1 if to be generated)

  out:  V =0 => r0  = handle for buffer
        V =1 => r0 -> error block

This call registers an area of memory as a buffer, the routine accepts
similar parameters to the Buffer_Create SWI, but instead of the call
claiming tha area of memory for you, you must actually specify the buffer's
start and end addresses.

It is not advisable to put buffers in application workspace, this
area of memory can be switched out when someone else tries to access it.  It
is however possible for your task if it is going to be the only one using
this buffer, and it will only be accessed whilst the task is currently paged
in to register a buffer within its workspace.

For further details about the flags word and the specified buffer handle
see the Buffer_Create call.


Buffer_Deregister
-----------------

  in:   r0  = handle of buffer to be deregistered.

  out:  V =0 => all preserved.
        V =1 => r0 -> error block.

This call will simply unlink a buffer from the active list, the data within
the buffer will be purged and any access to this buffer via INSV, REMV and
CNPV will be ignored.

Do not use this call if you have created the buffer using Buffer_Create,
instead use Buffer_Remove which releases any memory that may have been
claimed.


Buffer_ModifyFlags
------------------

  in:   r0  = handle of buffer to be modified
        r1  = EOR mask
        r2  = AND mask

  out:  r1  = old value
        r2  = new value

This call allows you to modify the flags word stored with each buffer, the
SWI allows two registers to be ANDed and then EORed with the current flags
word, on exit the old and new values of this word are returned to the
caller.

r1, r2 are applied as follows:

        new = (old AND r2) EOR r1

The caller should not modify reserved flag bits when issuing this call, ie
bits 4 to 31 should be set in r2 and clear in r1.


Buffer_LinkDevice
-----------------

  in:   r0  = buffer handle,
        r1 -> code to wake up device when needed      (0 => none)
        r2 -> code to call when device to be detached (0 => cannot be detached)
        r3  = private word to be passed in
        r4 -> workspace for above routines

  out:  V =1 => r0 -> error block, else all preserved.

This call links a set of routines to the specified device, the caller
supplies two routines, one to be called when data enters the buffer and
another to be called when someone else attempts to link to the buffer.

r1 this contains a pointer to the routine to be called when data enters the
buffer and it is currently marked dormant, the routine can be entered in any
mode and with FIQs or IRQs enabled / disabled, the mode should be preserved
as should the interrupt state.

The registers to the wake up code are setup as follows:

  in:   r0   = buffer handle
        r8   = private word          (specified in r3 in SWI Buffer_LinkDevice)
        r12 -> workspace for routine (specified in r4 in SWI Buffer_LinkDevice)

  out:  all should be preserved, including PSR.

The buffer manager automatically marks the buffer as active (non-dormant)
before calling the wake up code.

If the caller to Buffer_LinkDevice specifies a routine pointer equal to zero
then no wake up call is made.

The second routine supplied is a routine to be called whenever the owner of
the buffer is about to change; if this value is zero then the device is
indicating that the owner can never be changed and changing it will result
in an error.

The routine if supplied gets called as follows:

  in:   r0   = buffer handle
        r8   = private word
        r12 -> workspace for the calls

  out:  V =1 => r0 -> error block
        V =0 => all preserved

On return from this routine the routine can return an error, any errors
returned halt the detach process.  The detach routines are called when
someone attempts to kill the buffer manager module, this results in an error
and the buffer manager refuses to die.

When attaching to a buffer it is possible that the SWI will fail, this is
likely to be because the current owner is refusing to detach itself.


Buffer_UnlinkDevice
-------------------

  in:   r0  = buffer handle

  out:  V =0 => all preserved and device detached.
        V =1 => r0 -> error block.

This routine will unlink a device from a buffer, no warning if given of the
detach and the data that is currently stored within the buffer is purged.

This call should only be used by the actual device that called
Buffer_LinkDevice, anyone else calling this SWI could confuse the system.


Buffer_GetInfo
--------------

  in:   r0  = buffer handle

  out:  V =1 => r0 -> error block
        V =0 => r0  = flags relating to buffer
                r1 -> start of buffer in memory
                r2 -> end of buffer in memory (+1)
                r3  = insert index for buffer
                r4  = remove index for buffer
                r5  = remaining free space in buffer
                r6  = number of characters in buffer

This call returns data about the buffer, its position in memory, flags,
insert and remove offsets and the amount of free space.



Buffer_Threshold
----------------

  in:   r0  = buffer handle
        r1  = threshold / 0 none / -1 to read

  out:  r1  = previous value

This call is used to set/read the warning threshold of the buffer.  This is
used to trigger UpCalls if bit 3 of the buffer flags is set.

The UpCalls are issued when the amount of free space in the buffer
crosses the threshold value (see the UpCalls section below)



Vector calls
============

The SWIs for the buffer manager module allow you to modify and tinker with
the actual buffer itself, they do not however supply a way of inserting and
removing data from these buffers.

Extensions have been made to the three vectors; InsV, RemV and CnpV to
handle the inserting and removing of data from the buffers, these calls have
also been extended to allow block inserts.

For compatibility marking a block operation is done by setting bit 31 of the
buffer handle.  This changes the specification for calling these vectors as
follows:

InsV
----

  in:   r0  = byte to be inserted
        r1  = buffer handle (bit 31 is clear)

  out:  r0, r1 preserved
        r2 corrupt

or:-

  in:   r1  = buffer handle (bit 31 is set)
        r2 -> first byte of data to be inserted
        r3  = number of bytes to insert

  out:  r0, r1 preserved
        r2 -> remaining data to be inserted
        r3  = number of bytes still to be inserted

On both calls C is used to indicate if the insertion failed, if C=1 then it
was not possible to insert all the specified data, or the specified byte.


RemV
----

  in:   r1  = buffer handle (bit 31 clear)

  out:  r0  = next byte to be removed (for examine only)
        r1  = preserved
        r2  = byte removed (for remove only)

or:-

  in:   r1  = buffer handle (bit 31 set)
        r2 -> buffer to be filled
        r3  = number of bytes to place into buffer

  out:  r0, r1 preserved
        r2 -> updated buffer position
        r3  = number of bytes still to be removed

On both of the above calls V =1 on entry indicates that the data should be
copied out (examine) and V =0 indicates that the data should actually be
removed.

On exit C is used to indicate if the calls actually worked and if a byte or
the requested block of data could be obtained.


CnpV
----

Unchanged, except it copes with buffer manager buffers.


Events
======

With the changes required to InsV, RemV and CnpV calls to cope with the new
buffers and block transfers some of the events have been extended to cope
with indicating that a block transfer occurred.

For further details of the events and when they are generated consult the
PRM, as this remains unchanged.


Event_OutputEmpty
-----------------

  in:   r0  = Event_OutputEmpty (0)
        r1  = buffer handle

  out:  all preserved.

This is issued when the last character is removed from a buffer which has
output empty events enabled (see description of buffer flags).


Event_InputFull
---------------

  in:   r0  = Event_InputFull (1)
        r1  = buffer handle (bit 31 clear)
        r2  = character not inserted

or:-
        r0  = Event_InputFull (1)
        r1  = buffer handle (bit 31 set)
        r2 -> data not inserted
        r3  = number of bytes not inserted

  out:  all preserved.

This event is generated when a character or block is inserted into a buffer
which has input full events enabled (see description of buffer flags), and
the insertion failed.


Service calls
=============

Service_BufferStarting (&6F)
----------------------------

  in:   r1  = Service_BufferStarting (&6F)

  out:  all preserved.

This call is passed around after the module has been initialised or reset.
It allows module which wish to register buffers with the buffer manager to
do so.

When the service is received all SWIs are valid.



UpCalls
=======

UpCall_BufferFilling (8)
------------------------

in:     r0  = 8
        r1  = Buffer handle
        r2  = 0

out:    -

This is issued when data is inserted into the buffer and the free space
becomes less than the specified threshold.


UpCall_BufferEmptying (9)
-------------------------

in:     r0  = 9
        r1  = Buffer handle
        r2  = -1

out:    -

This is issued when data is removed from the buffer and the free space
becomes greater than or equal to the current threshold.
