
    file : /dsgn/tranpdoc.text
    date : 18-July-1983   kb

    This document describes the Transporter Driver for Concept.

    The Transporter driver has three (3) main functions :
       1) "strobe in" transporter commands,
       2) handle Transporter generated interrupts,
       3) make sure only one command and one receive on each socket is
          attempted at the same time.

    Access to the driver is through the Unitstatus mechanism of the Concept
    OS.


    Interface to Transporter Driver :

    The Pascal defined Unitstatus call is as follows :

       UnitStatus (Unit#,ParameterBlock,function code);

    where Unit# is the unit number of the Transporter driver, ParameterBlock
    is the Transporter driver's parameter block, and the function code is
    one of the 9 valid codes for the driver.

    The ParameterBlock has the form :

                  record CommandAddress : Pbytes;
                         ProcedurePointer : Pbytes;
                         UserData : LongWord;
                         end;

    where CommandAddress is the pointer to the Transporter Control Block
    the caller wants the driver to "strobe" into the Transporter.
    ProcedurePointer is the address of the global level procedure the
    Transporter driver should call when the Transporter interrupt occurs.
    UserData is a 4 byte long word data field which use and specific type
    are user-defined.

    The command address must point at a valid Transporter Control Block
    above the address $80000, except for the clear receive socket function
    where it can be nil.  The procedure address must point at a valid user
    interrupt service routine or may be nil.  A nil procedure pointer means
    there is NO user interrupt service routine to call when the operation
    is complete.  The procedure pointed at by the procedure pointer must
    take 5 parameters.  They are the dequeue call flag word, the dequeue
    error code, the result and buffer pointers from the Transporter Control
    Block, and a long word user data parameter from the user's unitstatus
    parameter block (see description in interrupt routine discussion).  The
    dequeue flag signifies if the interrupt routine is called for a
    operation start attempt (non-zero) or an operation complete (zero). If
    the dequeue flag is (non-zero) then the error parameter describes the
    ioresult code for the operation start attempt.  If the error code is
    not 0 (zero) then the control block specified failed to get "strobed
    in".  The dequeue operation start call to the interrupt routine will be
    made only if the Transporter Control Block was queued up by the driver
    because the Current Command entry was in use.

    The user interrupt procedure interface is :

    Procedure Done ( Dequeue   : Integer;
                     Error     : Integer;
                     ResultPtr : Pbytes;    {User can use any pointer type}
                     BufferPtr : Pbytes;    {for either pointers.         }
                     UserData  : LongInt ); {Can be any long word type.   }

    Failure to comply with these rules will result in catastrophic
    consequences.

    The user data parameter is available for any purpose the user
    determines.  It's value is not examined or used for any purpose
    internal to the driver.  It can be used to return to the user's
    interrrupt procedure any type of information the user needs.  For
    example, it can be a pointer to an operation control block, a
    transaction code, or an index into an array.

    The function codes are :

            1) 0 for Current Command.

            2) 1, 2, 3, and 4 for a receive socket setup.  The function
               code specifies which socket, where 1 is socket $80, 2 is
               socket $90 and so on.

            3) $81, $82, $83, $84, for clear a receive socket.  The high
               order bit being set specifies the clear operation.  The
               socket to be cleared is specified by the rest of the
               function code, where 1 is socket $80, 2 is socket $90 and
               so on.

    Each of the functions uses the same parameter block.  If any other
    function codes are used the driver returns an error code indicating
    what was wrong (see section on error and warning codes).

    The functions :

    The driver's 3 functions use a table internal to the driver to control
    the operations.  This table has 5 entries.  1 for the Current Command
    and 4 for each of the receive sockets.  The Current Command entry is
    used for send, peek, poke, init, echo, and other immediate Transporter
    commands sent to the driver via the Current Command function interface.
    The Clear a Receive Socket function will use the Current Command entry
    if the command address is not nil.  This should be used to send a end
    receive command to the Transporter.  The Receive Socket Setup function
    will also use the Current Command entry to transmit to the Transporter
    the receive socket setup command.  It of course will use the receive
    socket entry if the command is successfully strobed into the
    transporter.

    Each entry in the table can be in use for only one command at a time.
    The 4 receives sockets may each have only one receive pending at a
    time.  If a receive setup is requested on a socket with a receive
    pending then an in use error code is returned to the caller and the
    driver takes no action.  The current command entry may have only one
    command pending on it.  However, if a current command request is made
    while one is currently pending then the driver will queue up the new
    request if there is room on the queue.  The function returns a warning
    code if it queues up a request (see error and warning code section).
    The receive socket setup function will not setup the socket entry if
    the current command is queued up.  When the request is de-queued the
    receive will be setup, if possible.  If the driver cannot setup the
    receive then the user's interrupt procedure will be called with the
    dequeue word not equal to zero and the error parameter defining the I/O
    error.  If it worked the interrupt procedure will be called with the
    dequeue word not equal to zero and the error parameter equal to zero,
    showing no error on dequeue.

    The receive socket setup function does special processing on the result
    code of the current command if it is successfully transmitted to the
    Transporter.  The function will busy wait on the change of the receive
    setup result code instead of depending on the driver's interrupt
    service routine to release the current command entry.  This is
    neccesary because of a bug in the version 6.4 Transporter which does
    not generate an interrupt when the receive socket is set up.  If the
    result code does not change within a certain time then the driver will
    return the Transporter Not Ready error code.  It will also clear both
    the current command and receive socket entries.  However, if the
    Transporter changes the result code to an error state the function does
    NOT release the socket entry.  It assumes the receive is setup.
    Therefore, the caller must do a clear a receive socket function with
    the command address nil to free up the receive socket entry.

    The driver has attempted to correct another bug in the Transporter
    design.  For the peek command, the Transporter returns the data as the
    result code.  Since the driver determines which command and therefore
    which entry caused the interrupt by the result code, a peek response of
    $FF will cause the driver to miss the interrupt for the peek
    completion.  Consequently, the driver would not release the current
    command entry.  To prevent this, the driver does a busy wait on the
    completion of the peek command.  If the result code does not change
    within a certain time length the driver assumes that the peek command
    returned an $FF and releases the current command entry.  Unfortunately,
    this means that a user should not busy wait on an in use error response
    from the driver in an interrupt routine if it is possible that a peek
    command is pending in the current command entry.  For this last case,
    if the peek response is $FF then the current command entry will not be
    released.

    Interrupt Routine :

    For all the driver functions, if the user has an interrupt service
    routine then this routine must be resident in memory the entire time the
    Transporter command is active.  Furthermore, if the code is Pascal then
    the routine must be a global level procedure.  A global level procedure
    is only nested under the MAIN level program.  It is not a sub-procedure
    of a sub-procedure.

    The procedure must do 2 types of processing.  The first is when the
    dequeue parameter is zero (0).  This means the operation is complete
    and the procedure should do it's normal operation completion
    processing.  Normal processing can entail calling the Transporter
    driver to setup the command again.  The second processing type is when
    the dequeue parameter is non-zero.  This means that a previously queued
    command has been dequeued and processed by the driver to start-up the
    Transporter operation.  The interrupt procedure must check the error
    parameter.  The error code describes what went wrong with setting up
    the command when it was removed from the queue.  If it is zero then the
    set up was successful.  If it is non-zero then the set up failed.  The
    error code will usually be a Transporter Not Ready error.  This means
    there is a good probability of a hardware malfunction with the
    Transporter.  However, it can be the inuse error if the operation
    requested was a receive setup.  If the setup succeeded then the
    interrupt procedure will be called again when the operation is
    complete.  If it failed then the interrupt procedure will NOT be called
    for an operation completion.

    Normally, the procedure is called after the command has been performed
    and the entry has been released.  Prior to the procedure call the
    driver restores the interrupt level to the state when the Transporter
    (OmniNet) interrupt occurred.  Upon return, the driver resets the
    interrupt level to disable Transporter interrupts.  For the dequeue
    call, the command has not been completed, the current command entry was
    not released, and the entry was not removed from the queue, therefore,
    the user's normal processing may cause problems.  After the procedure
    returns from the dequeue call, the current command entry is released
    and the entry is removed from the queue.

    The user's interrupt service routine must be very careful about
    reentrancy problems, such as changing global variables from within the
    interrupt procedure or calling non-reentrant system functions.  This
    procedure may call other procedures and functions within the user's
    program.  It should not call the display or keyboard drivers because of
    reentrancy problems.  The driver's interrupt routine saves and restores
    IORESULT, a potential source of reentrancy problems in the system.
    This protects the user's interrupt routines which call the driver from
    damaging I/O error reporting from the system after the interrupt call
    is completed.

    The user interrupt routine is never called for a receive setup
    interrupt.  The receive socket setup routine forces the current command
    entry's procedure pointer to nil when it calls the current command
    function.  This is part of the fix for the 6.4 Tranpsorter bug
    mentioned in the function section.

    Error and Warning codes :

    The following is a list of the error and warning codes returned by the
    driver to the calling routine.  It also includes the reasons the driver
    has returned the error or warning code.

          3  - invalid I/O request error code.   The driver returns this
               code if the user requests a type of I/O the driver does not
               support or if the command code is invalid.  The command
               codes defined by the Concept OS are in the range of 0 to 6,
               inclusive.  The driver performs only unitinstall (command
               code = 0), unitstatus (cc = 5), and unitunmount (cc = 6).
               The commands unitread (cc = 1), unitwrite (cc = 2),
               unitclear (cc = 3), and unitbusy (cc = 4) are not supported.

         21  - transporter not ready error code.  The driver returns this
               code if the transporter fails to respond ready in time when
               trying to "strobe in" the command.  It also responds with
               this code when it times out waiting for the receive setup
               response from the Transporter.

         30  - queued request warning code.  The driver responds with this
               code whenever it queues up a request.  This can occur for
               current command and receive socket setup function calls.

         52  - entry in use error code.  This error code is returned
               whenever the entry specified or implied has a command
               pending on it.  The clear a receive socket function will
               return this if the current command entry is in use.  The
               receive socket setup function will return it if the
               specified receive socket entry is in use or the current
               command entry is in use and the queue was full.  The current
               command function will return it only if the current command
               entry is in use and the queue is full.

         56  - invalid function code error code.  The driver returns this
               code if the user passes a function code to the unitstatus
               command that is not 0, 1, 2, 3, 4, $81, $82, $83, or $84.
