head     56.3;
access   paws bayes jws quist brad dew jwh;
symbols  ;
locks    ; strict;
comment  @# @;


56.3
date     93.01.27.13.24.32;  author jwh;  state Exp;
branches ;
next     56.2;

56.2
date     93.01.27.12.04.01;  author jwh;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.05.09.44.08;  author jwh;  state Exp;
branches ;
next     55.1;

55.1
date     91.08.25.10.22.15;  author jwh;  state Exp;
branches ;
next     54.1;

54.1
date     91.03.18.15.26.06;  author jwh;  state Exp;
branches ;
next     53.1;

53.1
date     91.03.11.19.27.16;  author jwh;  state Exp;
branches ;
next     52.1;

52.1
date     91.02.19.09.11.15;  author jwh;  state Exp;
branches ;
next     51.1;

51.1
date     91.01.30.16.10.49;  author jwh;  state Exp;
branches ;
next     50.1;

50.1
date     90.10.29.16.25.39;  author jwh;  state Exp;
branches ;
next     49.1;

49.1
date     90.08.14.14.09.57;  author jwh;  state Exp;
branches ;
next     48.1;

48.1
date     90.07.26.11.16.00;  author jwh;  state Exp;
branches ;
next     47.1;

47.1
date     90.05.14.10.58.12;  author dew;  state Exp;
branches ;
next     46.1;

46.1
date     90.05.07.08.45.24;  author jwh;  state Exp;
branches ;
next     45.1;

45.1
date     90.04.19.15.53.06;  author jwh;  state Exp;
branches ;
next     44.1;

44.1
date     90.04.01.22.10.24;  author jwh;  state Exp;
branches ;
next     43.1;

43.1
date     90.03.20.14.01.50;  author jwh;  state Exp;
branches ;
next     42.1;

42.1
date     90.01.23.17.46.40;  author jwh;  state Exp;
branches ;
next     41.1;

41.1
date     89.12.22.11.29.12;  author jwh;  state Exp;
branches ;
next     40.1;

40.1
date     89.09.29.11.51.10;  author jwh;  state Exp;
branches ;
next     39.1;

39.1
date     89.09.26.16.35.29;  author dew;  state Exp;
branches ;
next     38.1;

38.1
date     89.08.29.11.27.19;  author jwh;  state Exp;
branches ;
next     37.1;

37.1
date     89.05.12.11.39.46;  author dew;  state Exp;
branches ;
next     36.1;

36.1
date     89.02.06.10.18.15;  author dew;  state Exp;
branches ;
next     35.1;

35.1
date     89.02.02.13.32.35;  author dew;  state Exp;
branches ;
next     34.1;

34.1
date     89.01.23.16.07.44;  author jwh;  state Exp;
branches ;
next     33.1;

33.1
date     89.01.16.11.40.15;  author dew;  state Exp;
branches ;
next     32.1;

32.1
date     89.01.10.11.48.19;  author bayes;  state Exp;
branches ;
next     31.1;

31.1
date     88.12.14.18.09.29;  author bayes;  state Exp;
branches ;
next     30.1;

30.1
date     88.12.09.13.46.44;  author dew;  state Exp;
branches ;
next     29.1;

29.1
date     88.10.31.15.31.27;  author bayes;  state Exp;
branches ;
next     28.1;

28.1
date     88.10.06.10.58.49;  author dew;  state Exp;
branches ;
next     27.1;

27.1
date     88.09.29.11.31.07;  author bayes;  state Exp;
branches ;
next     26.1;

26.1
date     88.09.28.13.12.08;  author bayes;  state Exp;
branches ;
next     25.1;

25.1
date     88.03.02.09.28.32;  author bayes;  state Exp;
branches ;
next     24.1;

24.1
date     87.08.31.09.48.31;  author jws;  state Exp;
branches ;
next     23.1;

23.1
date     87.08.26.10.25.45;  author bayes;  state Exp;
branches ;
next     22.1;

22.1
date     87.08.17.11.11.35;  author bayes;  state Exp;
branches ;
next     21.1;

21.1
date     87.08.12.13.54.19;  author bayes;  state Exp;
branches ;
next     20.1;

20.1
date     87.07.30.11.07.43;  author bayes;  state Exp;
branches ;
next     19.1;

19.1
date     87.06.01.08.23.27;  author jws;  state Exp;
branches ;
next     18.1;

18.1
date     87.05.20.15.22.02;  author bayes;  state Exp;
branches ;
next     17.1;

17.1
date     87.04.30.10.34.15;  author jws;  state Exp;
branches ;
next     16.1;

16.1
date     87.04.26.15.46.22;  author jws;  state Exp;
branches ;
next     15.1;

15.1
date     87.04.13.09.21.00;  author jws;  state Exp;
branches ;
next     14.1;

14.1
date     87.04.01.15.25.36;  author jws;  state Exp;
branches ;
next     13.1;

13.1
date     87.02.28.18.31.51;  author jws;  state Exp;
branches ;
next     12.1;

12.1
date     87.02.02.13.22.31;  author jws;  state Exp;
branches ;
next     11.1;

11.1
date     87.01.19.09.48.48;  author jws;  state Exp;
branches ;
next     10.1;

10.1
date     86.12.24.10.56.39;  author jws;  state Exp;
branches ;
next     9.1;

9.1
date     86.12.12.14.37.25;  author bayes;  state Exp;
branches ;
next     8.1;

8.1
date     86.11.27.11.54.50;  author jws;  state Exp;
branches ;
next     7.1;

7.1
date     86.11.20.13.44.12;  author hal;  state Exp;
branches ;
next     6.1;

6.1
date     86.11.04.17.56.29;  author paws;  state Exp;
branches ;
next     5.1;

5.1
date     86.10.28.16.46.09;  author hal;  state Exp;
branches ;
next     4.1;

4.1
date     86.09.30.19.45.19;  author hal;  state Exp;
branches ;
next     3.1;

3.1
date     86.09.01.11.56.06;  author hal;  state Exp;
branches ;
next     2.1;

2.1
date     86.07.30.14.42.31;  author hal;  state Exp;
branches ;
next     1.1;

1.1
date     86.06.30.15.00.24;  author danm;  state tmp;
branches ;
next     ;


desc
@Base file for PWS 3.2 release.

@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@	TTL IOLIB EXTDC - DATA COMM DRIVERS
	PAGE
********************************************************************************
*
*       COPYRIGHT (C) 1985 BY HEWLETT-PACKARD COMPANY
*
********************************************************************************
*
*
*       IOLIB     EXTDC
*
*
********************************************************************************
*
*
*
*       Library - IOLIB
*       Authors - Carl Dierschow / Tim Mikkelsen
*       Phone   - 303-226-3800  ext. 2910
*
*       Purpose - This set of assembly language code is intended to be used as
*                 a PASCAL module for I/O drivers for use by the external I/O
*                 procedures library.
*
*                 This set of assembly language drivers was written
*                 by Carl Dierschow 303-226-3800 ext. 3136.  The code
*                 was taken almost directly from the 9826 BASIC data comm
*                 code.
*
*       Date    - 10/26/81
*       Update  - 05/03/84 BY J Schmidt
*       Release - 7/12/85
*
*
*       Source  - IOLIB:DC.TEXT
*       Object  - IOLIB:DC.CODE
*
*
********************************************************************************
*
*
*       RELEASED
*       VERSION         3.1
*
*
********************************************************************************
	 PAGE
****************************************************************************
*                                                                          *
*                                                                          *
*      BUG FIX HISTORY         - after release 1.0                         *
*                                                                          *
*                                                                          *
*      BUG #   BY  / ON        LOC             DESCRIPTION                 *
*      -----   -----------     --------------  ----------------------      *
*                                                                          *
*      1249    T Mikkelsen     file DC_INTER   tfr count is off by one     *
*              01/08/82        inxex1          byte for overlap tfrs.      *
*                                                                          *
*      SPRyyy  T Mikkelsen     file DC_COMM    missing instruction in the  *
*              06/15/82        alvinit         reset code - not a problem  *
*                                              for current use - but for   *
*                                              future smart card intrfcs.  *
*                                                                          *
*      185     T Mikkelsen     file DC_INTER   eot and user isr's were     *
*              07/30/82        try_hook        not getting a parameter.    *
*                              try_hook_P                                  *
*                              inxdn1                                      *
*                              outxdn1                                     *
*                                                                          *
*      475     T Mikkelsen     no where        Change BSRs into JSRs to    *
*              09/17/82                        allow re-placement of the   *
*                                              modules.  Also in GPIO and  *
*                                              HPIB.  No refs were used    *
*                                              in the data comm modules.   *
*                                                                          *
*      tttt    J Schmidt       gain_access     Timing/exception fixes for  *
*              08/11/83        direct_control  680xx processors.           *
*              05/03/84        direct_command                              *
*                              wait_outxfrdone                             *
*                              output_data                                 *
*                              putctrlblk                                  *
*                              release_access                              *
*                                                                          *
****************************************************************************
	PAGE
*************************************************
*                                               *
*                                               *
*       ****     ***    *****    ***            *
*       *   *   *   *     *     *   *           *
*       *   *   *   *     *     *   *           *
*       *   *   *****     *     *****           *
*       *   *   *   *     *     *   *           *
*       *   *   *   *     *     *   *           *
*       ****    *   *     *     *   *           *
*                                               *
*                                               *
*        ***     ***    *   *   *   *           *
*       *   *   *   *   ** **   ** **           *
*       *       *   *   * * *   * * *           *
*       *       *   *   *   *   *   *           *
*       *       *   *   *   *   *   *           *
*       *   *   *   *   *   *   *   *           *
*        ***     ***    *   *   *   *           *
*                                               *
*                                               *
*************************************************
*
*       dc_doc
*       comdcl
*       dc_decls
*       dc_buff
*       dc_comm
*       dc_inter
*       dc_rxbuf
*       dc_trans
*       dc_txbuf

    sprint
    llen    132
    page
********************************************************************************
*
*
*       The following lines are used to tell the LINKER/LOADER what this module
*       looks like in PASCAL terms.
*
*       Note that it is possible to create assembly modules that are functions.
*       These routines are called through an indirect pointer using the CALL
*       facility which does NOT permit functions.
*
*       This module is called 'EXTDC' ( upper or lower case - doesn't matter )
*       independent of the file name ( by use of the MNAME pseudo-op ).
*
*       All the externally used procedures are called 'EXTDC_@@@@@@@@@@@@@@@@' in
*       this module.  If you are using assembly to access them use the
*       'EXTDC_@@@@@@@@@@@@@@' name.  If you are using Pascal use the '@@@@@@@@@@@@@@'
*       name.
*
********************************************************************************
	MNAME EXTDC
	SRC MODULE EXTDC;
	SRC IMPORT iodeclarations;
	SRC EXPORT
	SRC
	SRC        PROCEDURE alvinit        ( temp : ANYPTR );
	SRC        PROCEDURE alvinisr       ( temp : PISRIB );
	SRC        PROCEDURE enter_data     ( temp : ANYPTR ;  x     : ANYPTR ;
	SRC                                                    VAR c : INTEGER );
	SRC        PROCEDURE output_data    ( temp : ANYPTR ;  x     : ANYPTR ;
	SRC                                                    cnt   : INTEGER );
	SRC        PROCEDURE output_end     ( temp : ANYPTR );
	SRC        PROCEDURE direct_status  ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    VAR x : io_word);
	SRC        PROCEDURE direct_control ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    val   : io_word );
	SRC        PROCEDURE control_bfd    ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    val   : io_word );
	SRC        PROCEDURE start_tfr_out  ( temp : ANYPTR );
	SRC        PROCEDURE start_tfr_in   ( temp : ANYPTR );
	SRC END; { of extdc }
	PAGE
********************************************************************************
*
*       SYMBOLS FOR EXPORT AS PROCEDURE NAMES
*
********************************************************************************
	DEF EXTDC_EXTDC

	DEF EXTDC_ALVINIT
	DEF EXTDC_ALVINISR
	DEF EXTDC_ENTER_DATA
	DEF EXTDC_OUTPUT_DATA
	DEF EXTDC_OUTPUT_END
	DEF EXTDC_DIRECT_STATUS
	DEF EXTDC_DIRECT_CONTROL
	DEF EXTDC_CONTROL_BFD
	DEF EXTDC_START_TFR_IN
	DEF EXTDC_START_TFR_OUT

********************************************************************************
*
*       SYMBOLS FOR IMPORT - not used currently in data comm
*                            EXCEPT FOR CHECK_TIMER,M68KTYPE   tttt JS 8/11/83
*                            if they are ever used - use a JSR to call them
*
********************************************************************************
* REFA STBSY
* REFA STCLR
* REFA ITXFR
* REFA ABORT_IO
* REFA LOGINT
* REFA GETDMA
* REFA DROPDMA
* REFA TESTDMA
* REFA DMA_STBSY
  REFA CHECK_TIMER                                             tttt JS 8/11/83
  REFA M68KTYPE
*
*       change references to allow long jumps when the I/O      475 TM 9/17/82
*       modules get moved                                       475 TM 9/17/82
* LMODE STBSY
* LMODE STCLR
* LMODE ITXFR
* LMODE ABORT_IO
* LMODE LOGINT
* LMODE GETDMA
* LMODE DROPDMA
* LMODE TESTDMA
* LMODE DMA_STBSY
  LMODE CHECK_TIMER                                            tttt JS 8/11/83
	TTL IOLIB EXTDC - PASCAL ENTRY POINTS
	PAGE
********************************************************************************
*
*         PASCAL DRIVER ENTRY POINTS FOR GPIO CARDS
*
********************************************************************************

*
*         MODULE initialization
*
EXTDC_EXTDC             EQU *
			RTS
*
*         ENTRY POINTS
*
EXTDC_ALVINIT           BRA ALVINIT
EXTDC_ALVINISR          BRA TOP_ISR
EXTDC_ENTER_DATA        BRA ENTER_DATA
EXTDC_OUTPUT_DATA       BRA OUTPUT_DATA
EXTDC_OUTPUT_END        BRA OUTPUT_END
EXTDC_DIRECT_STATUS     BRA DIRECT_STATUS
EXTDC_DIRECT_CONTROL    BRA DIRECT_CONTROL
EXTDC_CONTROL_BFD       BRA CONTROL_BFD
EXTDC_START_TFR_IN      BRA START_TRANSFER_IN
EXTDC_START_TFR_OUT     BRA START_TRANSFER_OUT

    ttl     dc_doc: documentation info
    page
*************************************************
*                                               *
*   The following escapes are possible:         *
*                                               *
*       EOD_SEEN - on ENTER_DATA only,          *
*          signifies termination with control   *
*          block when too few bytes have been   *
*          read.                                *
*                                               *
*       TMO_ERR - on ENTER_DATA if Rx queue     *
*          was empty for too long               *
*               - on OUTPUT_DATA if Tx queue    *
*          goto blocked up for too long         *
*               - on CONTROL_BFD if Tx control  *
*          queue got blocked up for too long    *
*               - on OUTPUT_END if Tx control   *
*          queue got blocked up for too long    *
*                                               *
*                                               *
*       CRD_DWN - on every routine if card      *
*          was totally locked up for more than  *
*          one second.                          *
*                                               *
*   There are no checks for nested I/O.         *
*                                               *
*************************************************








* module: DC_COMM
*************************************************
*                                               *
*   procedure DIRECT_CONTROL (                  *
*               var SCT:  select_code_table;    *
*               REG:      1..127;               *
*               VAL:      0..255  );            *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*************************************************
	nosyms
	page
* module: DC_COMM
*************************************************
*                                               *
*   procedure DIRECT_STATUS (                   *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               var VAL:  word    );            *
*                                               *
*   These registers are intercepted:            *
*       0:  Gives value from RESET_ID           *
*       1:  Returns true if hardware interrupts *
*       2:  Returns 0                           *
*       5:  Returns 2 bits saying state of Rx   *
*           buffer                              *
*       9:  Returns last ENTER TERM             *
*       10: Returns last ENTER MODE             *
*       11: Returns # bytes available in Tx     *
*           queue, or 0 if there's not 3        *
*           control block positions available   *
*                                               *
*   The range of REG is not checked for         *
*   validity.                                   *
*                                               *
*************************************************










* module: DC_TRANS
*************************************************
*                                               *
*   procedure OUTPUT_DATA (                     *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               COUNT:    longword       );     *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*************************************************
	page
* module: DC_INTER
*************************************************
*                                               *
*   procedure START_TRANSFER_IN (               *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*************************************************







* module: DC_INTER
*************************************************
*                                               *
*   procedure START_TRANSFER_OUT (              *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*************************************************
	page
* module: DC_TRANS
*************************************************
*                                               *
*   procedure ENTER_DATA (                      *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               var COUNT:longword       );     *
*                                               *
*  COUNT initially passes the number of bytes   *
*  which the upper level wants to read.  THE    *
*  ROUTINE DOES NOT NECESSARILY READ THIS MANY! *
*  Upon exit COUNT will be reflect the number   *
*  of data bytes entered, whether or not there  *
*  is an escape.                                *
*                                               *
*  escape(EOD): Terminated by reaching a control*
*     block when not enough bytes have been     *
*     entered.  TERM&MODE may be read with      *
*     STATUS 9 and 10.                          *
*                                               *
*************************************************







* module: DC_TRANS
*************************************************
*                                               *
*   procedure OUTPUT_END (                      *
*               var SCT:  select_code_table );  *
*                                               *
*   Equivalent to the BASIC OUTPUT Sc;END.      *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*************************************************
	page
* module: DC_TRANS
*************************************************
*                                               *
*   procedure CONTROL_BFD (                     *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               VAL:      0..255);              *
*                                               *
*   Control register 0 is intercepted and       *
*   if MODE=0 no action is performed, otherwise *
*   the card is reset IMMEDIATELY.              *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*************************************************




*************************************************
*
*   Unresolved problems:
*
*       How is the hardware ISR linked in?
*
*       How are registers saved/restored on int?
*
*       How does the ISR find the select code &
*           select_code_record?
*
*       Should we do busybits?
*
*       How are overlapped transfers implemented?
*
*************************************************
	page
*************************************************
*
*   This code is required to check the validity
*   of a 98628/9 card:
*
*   var DSDP: 0..65535;
*       ATTR: 0..255;
*
*   if binand(readio(SC,1),60)=52 then begin
*       DSDP := readio(SC,16395) * 256
*               + readio(SC,16393);
*       if (DSDP<32768) then begin
*           ATTR := readio(SC,DSDP*2+1);
*           if binand(ATTR,127)=1 then
*               (*>>> CLAIM CARD! <<<*)  ;
*       end;
*   end;
*
*   Remember that the readio operations above
*   can bus error!
*
*************************************************



*************************************************
*
*   One of the arguments to all routines is a
*   structure I call SCT:select_code_table.
*   This is a structure allocated by the higher
*   level Modcal code, the last 34 bytes of
*   which I INITIALIZE AFTER MODCAL HAS
*   INITIALIZED THE FRONT PART.
*
*   THE C_ADR FIELD MUST BE INITIALIZED BEFORE
*   CALLING THIS ROUTINE:
*
*       procedure ALVINIT (
*                   var SCT: select_code_table );
*
*   This routine also resets the card.  This
*   routine should be used at INITIALIZE time
*   but not at RESET (that's CONTROL 0;1).
*
*************************************************
	page
*************************************************
*
*   Equivalences:
*
*       set_serial, clear_serial
*               CONTROL_BFD(REG<=8)
*
*       serial_line - DIRECT_STATUS(REG<=8)
*
*       set_baud_rate
*
*           ID := DIRECT_STATUS(REG<=3);
*           DIRECT_CONTROL(REG<=20,VAL<=speed);
*           if ID=1 then
*               DIRECT_CONTROL(REG<=21,VAL<=speed);
*
*           ('speed' must go through a mapping!)
*
*       set_char_length - CONTROL_BFD(REG<=34)
*
*       set_stop_bits - CONTROL_BFD(REG<=35)
*
*       set_parity - CONTROL_BFD(REG<=36)
*
*       break - DIRECT_CONTROL(REG<=6)
*
*       abort - DIRECT_CONTROL(REG<=125,VAL<=0)
*               this also aborts transfers!
*
*       clear - DIRECT_CONTROL(REG<=101,VAL<=0)
*
*       ioreset - CONTROL_BFD(REG<=0,VAL<=1)
*
*       readchar - ENTER_DATA(COUNT<=1)
*               (ENTER_DATA will terminate on
*               a control block!!!)
*
*       writechar - OUTPUT_DATA(COUNT<=1)
*
*       set_timeout - write to value in
*               select_code_table (units=1ms)
*
*       LEVEL 2 functions - supersets of readchar
*               & writechar
*
*       handshake transfer - ENTER_DATA or
*               OUTPUT_DATA (ENTER_DATA will
*               terminate on a control block!!!)
*
*       outbound transfer_end - OUTPUT_DATA then
*               OUTPUT_END
*
*       inbound transfer_end - ENTER_DATA
*
*       overlapped transfers - set up the transfer
*               control block and then call
*               START_TRANSFER_IN or
*               START_TRANSFER_OUT.
*
*************************************************

    list
    ttl     comdcl: common I/O declarations
    page
    include COMDCL
    list
    ttl     dc_decls: common Data Comm declarations
    page


********************************************************************************
*                        Data Comm card RAM locations                          *
*                      (byte offsets from base address)                        *

RESET_ID        equ     $000000
INT_DMA         equ     $000002
SEMAPHORE       equ     $000004
INT_COND        equ     $004000
COMMAND         equ     $004002
DATA_REG        equ     $004004
PRIMARY_ADDR    equ     $004006
DSDP            equ     $004008
ERROR_CODE      equ     $00400C

************************** Data Structures Descriptor **************************

ATTRIBUTES      equ     $000000
TR_QUEUE_ADDR   equ     $000002
PRIM_0_ADDR     equ     $000006

****************************** Queue ******************************************

TXENDBLOCKSPACE equ     $000000
RXDATABUFF_NUMB equ     $000001
TXBUFF          equ     $000004
RXBUFF          equ     $000024

CTRL_AREA       equ     $000000
DATA_AREA       equ     $000010

****************************** Buffer record **********************************

ADDR            equ     $000000
SIZE            equ     $000004
FILL            equ     $000008
EMPTY           equ     $00000C

****************************** Control block **********************************

POINTER         equ     $000000
TERMFIELD       equ     $000004
MODEFIELD       equ     $000006
CTRLBLKSIZE     equ     $000008

****************************** select_code_table ******************************

ovrlaper        equ AVAIL_OFF+00 .. 1   ; word
usr0mask        equ AVAIL_OFF+02        ; byte
which_RXbuf     equ AVAIL_OFF+03        ; byte
last_enter_term equ AVAIL_OFF+04        ; byte
last_enter_mode equ AVAIL_OFF+05        ; byte
intbits         equ AVAIL_OFF+06        ; 8 bits
* unused                      07
* The following 26 bytes are saved at interrupt
term_and_mode   equ AVAIL_OFF+08 .. 09  ; Encompasses the two below
term            equ AVAIL_OFF+08        ; byte
mode            equ AVAIL_OFF+09        ; byte
data_address    equ AVAIL_OFF+10 .. 13  ; pointer
data_number     equ AVAIL_OFF+14 .. 17  ; integer
outer_tx_count  equ AVAIL_OFF+18 .. 21  ; integer
timeout_counter equ AVAIL_OFF+22 .. 25  ; integer
inner_counter   equ AVAIL_OFF+26 .. 29  ; integer
inner_tx_count  equ AVAIL_OFF+30 .. 33  ; integer
* This is where they are saved:
int_savespace   equ AVAIL_OFF+34 .. 59
SR_image        equ AVAIL_OFF+60 .. 61  ; word
RCR_hook        equ AVAIL_OFF+62 .. 69  ; procedure
err_hook        equ AVAIL_OFF+70 .. 77  ; procedure
trc_hook        equ AVAIL_OFF+78 .. 85  ; procedure
bt6_hook        equ AVAIL_OFF+86 .. 93  ; procedure
bt7_hook        equ AVAIL_OFF+94 .. 101 ; procedure



sctablebytes    equ AVAIL_OFF+102       ; size of the entire table for allocation

error_int       equ 0   ; Bits for interrupt
rx_int          equ 1   ; register
tx_int          equ 2
ON_INTR_int     equ 3
RC_reset_int    equ 4
trace_int       equ 5

********************************************************************************

    list
    ttl     dc_buff: buffer utilities
    page


*       ****    *   *   *****   *****   *****   ****     ***
*       *   *   *   *   *       *       *       *   *   *   *
*       *   *   *   *   *       *       *       *   *   *
*       ****    *   *   *****   *****   *****   ****     ***
*       *   *   *   *   *       *       *       *  *        *
*       *   *   *   *   *       *       *       *   *   *   *
*       ****     ***    *       *       *****   *   *    ***




********************************************************************************
*                                                                              *
*       routine gain_access: gets access to SEMAPHORE on card for buffer       *
*               ===========  utilities.  If access is not gained in a          *
*                            preset time, an escape is performed.              *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon normal exit:                                                      *
*           If escape performed then                                           *
*               Timeout occurred                                               *
*           Otherwise                                                          *
*               Access was gained                                              *
*               SR has been set to disable all but level 7 interrupt.  The     *
*               SR has been pushed on the stack and RELEASE_ACCESS MUST BE     *
*               CALLED AT THE SAME LEVEL ON THE STACK!!!!!                     *
*                                                                              *
*       This bashes d2.l.                                                      *
*                                                                              *
********************************************************************************

gain_access equ *
	move.l  (sp)+,d2                ; Get return address
	trap    #11                     get into supervisor, save SR    scs
* scs   move    sr,-(sp)                ; Push on old SR
	move.l  d2,-(sp)                ; and push on return address
	ori     #$2700,sr               lock out all interrupts         scs
* scs   move.w  4(sp),d2                ; Now get old SR into d2
* scs   and.w   #$F0FF,d2               ; Strip off old int level
* scs   or.w    #$0600,d2               ; Set interrupt level 6
* scs   move    d2,sr                   ; and put into SR
	btst    #timer_present,sysflag2   check if timer present     tttt JS
	beq.s   gatimed                   if so then go use it       tttt JS
	move.l  #157500,d2 [CALIBRATED 1 SEC] ; Initialize counter
galoop  tst.b   SEMAPHORE(a3)           ; Fetch semaphore bit in bit 7 (sign)
	bpl.s   gadone                  ; If bit 7 true then done!
	subq.l  #1,d2                   ; Loop for preset time
	bne.s   galoop

*               Timed out: escape, but first...
gaterr  addq    #4,sp                   pop return addres               scs
	move    (sp)+,sr                restore user mode               scs
* scs   move    4(sp),sr                ; Get old SR back
	bra     lunched                 ; Now escape
*
gatimed tst.b   semaphore(a3)          first do quick test          tttt JS
	bpl.s   gadone                 before timing                tttt JS
	move.b  #1,-(sp)               set up timing record         tttt JS
	move.l  #1000,-(sp)            MS followed by boolean       tttt JS
gatlp1  move.l  #254,d2                quick loop -- 1 ms @@ 16 MHz  tttt JS
gatlp2  tst.b   semaphore(a3)          check semaphore              tttt JS
	bpl.s   gatexit                if ok then get out           tttt JS
	subq.l  #1,d2                  else hang in tight loop      tttt JS
	bne     gatlp2                                              tttt JS
	pea     (sp)                   now check the timer          tttt JS
	jsr     check_timer            parameter is ptr to record   tttt JS
	bpl     gatlp1                 if not timeout do tight loop tttt JS
	addq    #6,sp                  else fix the stack           tttt JS
	bra     gaterr                 and do timeout escape        tttt JS
gatexit addq    #6,sp                  normal exit is here          tttt JS
	rts                                                         tttt JS
	page
********************************************************************************
*                                                                              *
*       routine release_access: releases access to SEMAPHORE on card which     *
*               ==============  was previously gained with gain_access.        *
*                               Read the notes with the above routine to       *
*                               see description of stack funnies.              *
*                               THIS MUST BE CALLED WITH A BSR INSTRUCTION!    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon normal exit:                                                      *
*               no registers are bashed.                                       *
*                                                                              *
********************************************************************************

release_access equ *
	move.b  d0,SEMAPHORE(a3)        ; Store don't-care into semaphore.

	move.w  4(sp),-(sp)             switch SR and return address    scs
	tst.b   m68ktype                is this a 68000?         tttt JS
	bne.s   release_10or12          br if not                tttt JS
	move.l  2(sp),4(sp)                                             scs
	move.w  (sp)+,(sp)                                              scs
	rte                             restore user mode, return       scs
*
release_10or12 equ *
	clr.w   6(sp)           fake vector offset word where SR was tttt JS
	rte                       and do an rte back to user mode    tttt JS

gadone  rts                             ; Now return to the return address.
	page
********************************************************************************
*                                                                              *
*       routine find_TRBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's TRBUFF structure.        *
*                                                                              *
*       routine find_TXBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's TXBUFF structure.        *
*                                                                              *
*       routine find_RXBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's RXBUFF structure.        *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon exit:                                                             *
*               a2.l =  buffer record base address (CTRLBUFF_ADDR,             *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF_ADDR, etc).  (shifted, +1+selectcode)         *
*               This bashes a1, d4 and d5.                                     *
*                                                                              *
********************************************************************************

find_TRBUF equ *
	moveq   #0,d5
	movea.l #TR_QUEUE_ADDR,a2
	bra.s   findTR

find_TXBUF equ *
	moveq   #TXBUFF,d5
	bra.s   find

find_RXBUF equ *
	moveq   #RXBUFF,d5
find    movea.l #PRIM_0_ADDR,a2

findTR  clr.l   d4
	movep.w DSDP(a3),d4
	ror.w   #7,d4
	add.l   a3,d4
	movea.l d4,a1                   ; a1 points to Data Struct Descriptor

	clr.l   d4
	adda.l  a2,a1                   ; add offset to which queue table
	movep.w 0(a1),d4
	ror.w   #7,d4
	add.l   a3,d4
	add.l   d5,d4
	movea.l d4,a2                   ; a2 points to buffer record
	rts
	page
********************************************************************************
*                                                                              *
*       routine find_RX_DATA:   Sets up pointers to point to the appropriate   *
*               ============    receive data buffer.  This is to be used after *
*                               the routine find_RXBUF which sets up the       *
*                               pointer (in a2) to the receive control buffer  *
*                               descriptor record structure.                   *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a2.l =  Buffer record base address (CTRLBUFF_ADDR,             *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF0_ADDR, etc).  (shifted, +1+selectcode)        *
*               a4.l =  pointer to select_code_table structure                 *
*                                                                              *
*       Upon exit:                                                             *
*               a1.l =  data area base address (shifted, +1+selectcode)        *
*               d4.l =  address of first byte PAST data area (shifted, +1+sc)  *
*               d5.l =  XXxxxxBUFF_SIZE (unshifted, not adjusted)              *
*                                                                              *
********************************************************************************

find_RX_DATA equ *
	movea.l #DATA_AREA,a1
	clr.l   d5                      ; compute offset for WHICH rx data
	move.b  which_RXbuf(a4),d5      ; buffer we are using
	asl.l   #4,d5
	adda.l  d5,a1

	bra.s   findare                 ; Now go do the rest of it!
	page
********************************************************************************
*                                                                              *
*       routine find_DATA_AREA: Sets up pointers to point to the data buffer.  *
*               ==============  This is to be used in conjunction with the     *
*                               routines find_XXBUF which will set up the      *
*                               pointer (in a2) to the buffer we are using.    *
*                               THIS SHOULD NOT BE USED WITH THE RECEIVE       *
*                               BUFFER!  USE THE PREVIOUS ROUTINE INSTEAD!     *
*                                                                              *
*       routine find_CTRL_AREA: Sets up pointers to point to the ctrl buffer.  *
*               ==============  This is to be used in conjunction with the     *
*                               routines find_XXBUF which will set up the      *
*                               pointer (in a2) to the buffer we are using.    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a2.l =  Data buffer record base address (CTRLBUFF_ADDR,        *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF_ADDR, etc).  (shifted, +1+selectcode)         *
*                                                                              *
*       Upon exit:                                                             *
*               a1.l =  data area base address (shifted, +1+selectcode)        *
*               d4.l =  address of first byte PAST data area (shifted, +1+sc)  *
*               d5.l =  XXxxxxBUFF_SIZE (unshifted, not adjusted)              *
*                                                                              *
********************************************************************************

find_DATA_AREA equ *
	movea.l #DATA_AREA,a1
	bra.s   findare

find_CTRL_AREA equ *
	movea.l #CTRL_AREA,a1

findare adda.l  a2,a1                   ; a1 points to data/ctrl part of record
	clr.l   d5
	movep.w SIZE(a1),d5
	ror.w   #8,d5                   ; d5 = SIZE in bytes

	clr.l   d4
	movep.w ADDR(a1),d4
	ror.w   #7,d4
	add.l   a3,d4
	movea.l d4,a1                   ; a1 points to front of buffer area
	add.l   d5,d4
	add.l   d5,d4                   ; d4 points past end of buffer area

	rts

    ttl     dc_comm: command module
    page


*        ***     ***    *   *   *   *    ***    *   *   ****
*       *   *   *   *   ** **   ** **   *   *   **  *   *   *
*       *       *   *   * * *   * * *   *   *   * * *   *   *
*       *       *   *   *   *   *   *   *****   *  **   *   *
*       *       *   *   *   *   *   *   *   *   *   *   *   *
*       *   *   *   *   *   *   *   *   *   *   *   *   *   *
*        ***     ***    *   *   *   *   *   *   *   *   ****





********************************************************************************
*                                                                              *
*   procedure ALVINIT(var SCT: select_code_table)                              *
*                                                                              *
********************************************************************************

alvinit equ     *
	movea.l (sp)+,a0
	movea.l (sp)+,a4
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  #sctablebytes-1-AVAIL_OFF,d2
clrloop clr.b   AVAIL_OFF(a4,d2)
	dbf     d2,clrloop

	move.b  INT_DMA(a3),d0  ; This SR is used to
	andi.w  #$0030,d0       ; set the interrupt level
	addi.w  #$0230,d0       ; equal to that of the
	asl.w   #4,d0           ; card.
	move.w  d0,SR_image(a4)

	CLR.B   WHICH_RXBUF(A4) ;                               ( SPRyyy TM 6/15/82 )

	bsr     chk_err         ; See if card is giving
*                               ; overlapped error
	bsr     do_reset        ; This can escape if card bad

	bra     check_ov_error  ; Escape if any error
	page
********************************************************************************
*                                                                              *
*       routine eir:    Enables interrupts on this card only.                  *
*               ===                                                            *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card's base address ($00xx0001)                        *
*                                                                              *
*       Upon normal exit:                                                      *
*               No registers are changed.                                      *
*                                                                              *
********************************************************************************

eir     equ     *
	move.b  #$80,INT_DMA(a3)                ; Set enable-interrupt bit true
	rts


********************************************************************************
*                                                                              *
*       routine dir:    Disables interrupts on this card only.                 *
*               ===                                                            *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card's base address ($00xx0001)                        *
*                                                                              *
*       Upon normal exit:                                                      *
*               No registers are changed.                                      *
*                                                                              *
********************************************************************************

dir     equ     *
	clr.b   INT_DMA(a3)                     ; Clear enable-interrupt bit
	rts
	page
*************************************************
*                                               *
*   procedure DIRECT_CONTROL (                  *
*               var SCT:  select_code_table;    *
*               REG:      1..127 & 256 & 257;   *
*               VAL:      0..255  );            *
*                                               *
*************************************************

direct_control equ *
	movea.l (sp)+,a0
	move.w  (sp)+,d1        ; VAL
	move.w  (sp)+,d2        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if any error

	move.b  d1,DATA_REG(a3) ; Send VAL
	move.b  d2,COMMAND(a3)  ; then REG
	cmp.b   #125,d2
	bne.s   not125
	bsr     outxfr_done     ; For ctrl 125 (abort)
	bsr     inxfr_done      ; abort transfers
not125  equ   *
*                               (tm) mod - 12/02/81 Tim Mikkelsen
	CMP.W   #256,D2         (tm) CHECK FOR ABORT TFR IN
	BEQ     INXFR_DONE      (tm)
	CMP.W   #257,D2         (tm) CHECK FOR ABORT TFR OUT
	BEQ     OUTXFR_DONE     (tm)

	btst    #timer_present,sysflag2   check if timer present  tttt JS
	beq.s   ctltime                   if so then go use it    tttt JS

	move.l  #181851,d0 [CALIBRATED 1 SEC]   ; Now start counter for timeout
ctloop  tst.b   COMMAND(a3)
	beq.s   ctldun          ; Done when COMMAND=0
	subq.l  #1,d0
	bne.s   ctloop                          ; Otherwise decrement counter
	bra     lunched                         ; & escape

ctldun  bra     check_ov_error

ctltime move.b  #1,-(sp)        set up timer record            tttt JS 8/11/83
	move.l  #1000,-(sp)                                    tttt JS 8/11/83
ctltlop tst.b   command(a3)     see if done                    tttt JS 8/11/83
	beq.s   ctlexit         if so then return              tttt JS 8/11/83
	pea     (sp)            else push pointer to time rec  tttt JS 8/11/83
	jsr     check_timer     and see if timed out yet       tttt JS 8/11/83
	bpl     ctltlop         no -- keep trying              tttt JS 8/11/83
	addq    #6,sp           yes, give one more try         tttt JS 5/3/84
	moveq   #10,d0          using short count              tttt JS 5/3/84
	bra     ctloop          in normal timing loop          tttt JS 5/3/84
ctlexit addq    #6,sp           normal exit -- clean stack     tttt JS 8/11/83
	bra     check_ov_error  and go check errors            tttt JS 8/11/83
	page
*************************************************
*                                               *
*   procedure DIRECT_STATUS (                   *
*               var SCT:  select_code_table;    *
*               REG:      1..127;               *
*               var VAL:  word    );            *
*                                               *
*   These registers are intercepted:            *
*       0:  Gives value from RESET_ID           *
*       1:  Returns true if hardware interrupts *
*       2:  Returns bit 2 = in xfr active;      *
*                   bit 3 = out xfr active      *
*       5:  Returns 2 bits saying state of Rx   *
*           buffer                              *
*       9:  Returns last ENTER TERM             *
*       10: Returns last ENTER MODE             *
*       11: Returns # bytes available in Tx     *
*           queue, or 0 if there's not 3        *
*           control block positions available   *
*                                               *
*************************************************

direct_status equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a1        ; addr(VAL)
	move.w  (sp)+,d0        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if any error

	clr.w   d1              ; d1 will hold result
	move.l  a1,-(sp)

	tst.b   d0
	beq.s   sts0
	cmpi.b  #2,d0           ; Check for intercepted regs
	blt.s   sts1
	beq.s   sts2
	cmpi.b  #5,d0
	beq.s   sts5
	cmpi.b  #9,d0
	beq.s   sts9
	cmpi.b  #10,d0
	beq.s   sts10
	cmpi.b  #11,d0
	beq.s   sts11
	add.b   #128,d0
	move.b  d0,term(a4)     ; Send TERM

	bsr     direct_command
	move.b  mode(a4),d1

gotsts  movea.l (sp)+,a1
	move.w  d1,(a1)                 ; Return value
	bra     check_ov_error

*
*  Special intercepted registers
*

sts0    move.b  RESET_ID(a3),d1
	bra.s   gotsts

sts1    btst    #7,INT_DMA(a3)
	sne     d1
	and.w   #$0001,d1
	bra.s   gotsts

sts2    movea.l BUFI_OFF(a4),a2
	move.l  a2,d0
	beq.s   sts2a
	bset    #2,d1
sts2a   movea.l BUFO_OFF(a4),a2
	move.l  a2,d0
	beq.s   gotsts
	bset    #3,d1
	bra.s   gotsts

sts5    bsr     find_RXBUF
	bsr     dir
	bsr     RX_stuff_avail
	move.w  d0,d1
	bsr     eir
	bra.s   gotsts

sts9    move.b  last_enter_term(a4),d1
	bra.s   gotsts

sts10   move.b  last_enter_mode(a4),d1
	bra.s   gotsts

sts11   bsr     find_TXBUF
	bsr     dir
	bsr     find_CTRL_AREA
	bsr     TXCTRLBUFFroom
	clr.w   d1
	subi.l  #12,d3
	blt.s   gotsts
	bsr     find_DATA_AREA
	bsr     TXDATABUFFroom
	move.w  d3,d1
	bsr     eir
	bra     gotsts
	page
********************************************************************************
*                                                                              *
*       routine put_INTMASK:    Sends the value in usr0mask to the card.       *
*               ===========                                                    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of sc_subtabletype structure                   *
*               sc_subtabletype.usr0mask has value to send to card.            *
*                                                                              *
*       This bashes term and mode in the select code subtable.                 *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

put_INTMASK equ *
	move.b  #121,term(a4)           ; Send the new driver interrupt mask
	move.b  usr0mask(a4),mode(a4)   ; down with control #121
***     bra     direct_command

********************************************************************************
*                                                                              *
*   routine direct_command                                                     *
*           ==============                                                     *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

direct_command equ *
	move.b  mode(a4),DATA_REG(a3)
	move.b  term(a4),COMMAND(a3)    ; Send TERM

	btst    #timer_present,sysflag2   is timer available?  tttt JS 8/11/83
	beq.s   dctime                    if so go use it      tttt JS 8/11/83

	move.l  #181851,d0 [CALIBRATED 1 SEC]   ; Now start counter for timeout
dcloop  tst.b   COMMAND(a3)
	beq.s   dcdone                         ; Done when COMMAND=0
	subq.l  #1,d0
	bne.s   dcloop                         ; Otherwise decrement counter
	bra     lunched                         ; & escape

dcdone  move.b  DATA_REG(a3),mode(a4)
	rts

dctime  move.b  #1,-(sp)                  set up timer record  tttt JS 8/11/83
	move.l  #1000,-(sp)               for 1 sec wait       tttt JS 8/11/83
dctloop tst.b   command(a3)               see if done          tttt JS 8/11/83
	beq.s   dctexit                   if so then return    tttt JS 8/11/83
	pea     (sp)                      check timer          tttt JS 8/11/83
	jsr     check_timer                                    tttt JS 8/11/83
	bpl     dctloop                   if not timeout, br   tttt JS 8/11/83
	addq    #6,sp                     timeout, clean stk   tttt JS 5/3/84
	moveq   #10,d0                    and try once more    tttt JS 5/3/84
	bra     dcloop                    with short count     tttt JS 5/3/84
dctexit addq    #6,sp                     normal exit, cleanup tttt JS 8/11/83
	bra     dcdone                    and return           tttt JS 8/11/83

	page
********************************************************************************
*                                                                              *
*       routine get_INTMASK:    Reads the value of usr0mask from the card.     *
*               ===========                                                    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of sc_subtabletype structure                   *
*                                                                              *
*       At exit:                                                               *
*               sc_subtabletype.usr0mask has value from the card.              *
*                                                                              *
*       This bashes term and mode in the select code subtable.                 *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

get_INTMASK equ *
	move.b  #121+128,term(a4)       ; Get the current interrupt mask
	bsr     direct_command
	move.b  mode(a4),usr0mask(a4)   ; from register #121
	rts


********************************************************************************
*                                                                              *
*       do_reset:  resets the card, waits for it to complete powerup and       *
*       ========   then gets INTMASK again.                                    *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************


do_reset equ    *
	bsr     outxfr_done     ; Abort transfers
	bsr     inxfr_done
	bsr     dir                     ; Disable card interrupts to prevent
*                                       ; conflicts
	move.b  #$80,RESET_ID(a3)       ; Send reset ($80) to card
	bsr     gain_access             ; Wait until SEMAPHORE is freed
	bsr     release_access          ; and then give it back
	bsr     get_INTMASK
	bra     eir
	page
********************************************************************************
*                                                                              *
*   routine check_ov_error:  If the 'ovrlaper' location is nonzero then        *
*           ==============   this escapes with that error.                     *
*                                                                              *
*       Uses:   a3.l =  Base address of card ($00xx0001)                       *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
********************************************************************************


check_ov_error equ *
	bsr     dir
	move.l  d0,-(sp)
	clr.l   d0
	move.w  ovrlaper(a4),d0
	clr.w   ovrlaper(a4)
	bsr     eir
	tst.w   d0
	bne.s   escape
	move.l  (sp)+,d0
	rts


****************************** Escapes *****************************************

lunched equ     *
	moveq   #crd_dwn,d0
	bra.s   escape

time_err equ    *
	moveq   #tmo_err,d0

********************************************************************************
*                                                                              *
*       routine escape: performs Pascal "escape" function.  Error exit         *
*               ======  number is to be passed in d0.                          *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*               a5.l =  Global pointer for escape arguments                    *
*               d0.l =  Escape number                                          *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
********************************************************************************

escape  equ     *               ; Escape point for errors
	move.l  d0,IOE_RSLT(a5)
	clr.l   d5              ; Tim's magic escape stuff
	move.b  IO_SC(a4),d5
	move.l  d5,IOE_SC(a5)
	move.w  #IOE_ERROR,ESC_CODE(a5)
	move.b  #$80,INT_DMA(a3) ;Re-enable card interrupts if off
	trap    #10

    ttl     dc_inter: hardware interrupt handler
    page


*       *****   *   *   *****   *****   ****    ****    *   *   ****    *****
*         *     **  *     *     *       *   *   *   *   *   *   *   *     *
*         *     * * *     *     *       *   *   *   *   *   *   *   *     *
*         *     *  **     *     ***     ****    ****    *   *   ****      *
*         *     *   *     *     *       *  *    *  *    *   *   *         *
*         *     *   *     *     *       *   *   *   *   *   *   *         *
*       *****   *   *     *     *****   *   *   *   *    ***    *         *





********************************************************************************
*                                                                              *
*                 DATA COMM CARD TOP LEVEL INTERRUPT SERVICE ROUTINE           *
*                                                                              *
*       This is reached thru the softpoll table for the appropriate            *
*       interrupt level.                                                       *
*                                                                              *
*       This handles a hardware interrupt from the data comm card.  First it   *
*       enquires to find out what interrupt conditions are pending, then it    *
*       calls the appropriate routines to handle the conditions.               *
*                                                                              *
*       At entry:                                                              *
*               a5.l =  pointer to globals area                                *
*                                                                              *
*       During this routine:                                                   *
*               a3.l =  card's base address ($00xx0001)                        *
*               a4.l =  address of sc_subtabletype structure                   *
*                                                                              *
********************************************************************************

top_isr equ     *
	movea.l (sp)+,a0        ; Save return addr
	movea.l (sp)+,a4        ; Get sc_subtabletype
	pea     (a0)            ; Replace ret addr

	movea.l C_ADR(a4),a3    ; Get card base addr

	addq.l  #1,a3           ; Now a3.l = OUR base address of card

**********  TRY SECTION: RECOVER IS AT END OF ISR

	movem.l a3/a4,-(sp)
	move.l  RCVR_BLK(a5),-(sp)
	move.l  a6,-(sp)
	pea     recover_section
	move.l  sp,RCVR_BLK(a5)

**********  END OF 'TRY' keyword

	move.w  term_and_mode(a4),int_savespace(a4)
	movem.l term_and_mode+2(a4),d0-d5
	movem.l d0-d5,int_savespace+2(a4)

	move.b  INT_COND(a3),intbits(a4) ;Get all the interrupt condition bits

*   From now on, each handler routine checks for its particular interrupting
*   condition and then jumps to the next.  This is done primarily for speed.
	page
********************************************************************************
*                                                                              *
*       routine remcont_reset_isr:      Takes care of communicating a          *
*               =================       card's remote-control-reset to the     *
*                                       operating system                       *
*                                                                              *
********************************************************************************

remcont_reset_isr equ *
	btst    #RC_reset_int,intbits(a4) ; Test for bit #4 for this condition
	beq.s   error_isr
	lea     RCR_hook(a4),a1
	bsr     try_hook



********************************************************************************
*                                                                              *
*       routine error_isr:   Handles the communication of an error from the    *
*               =========    interface card back to BASIC, or the hook.        *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of SCT: select_code_table                      *
*                                                                              *
*       Upon normal exit:                                                      *
*                                                                              *
*       The 'chk_err' routine is used also at powerup time.                    *
*                                                                              *
********************************************************************************

error_isr equ *
	btst    #error_int,intbits(a4)  ; Test for bit #0 for this condition
	beq.s   data_rx_isr

	bsr     chk_err
	bra.s   data_rx_isr

chk_err clr.w   d0
	move.b  ERROR_CODE(a3),d0       ; fetch error number
	beq.s   errdone                 ; ignore ERROR_CODE=0
	clr.b   ERROR_CODE(a3)
	add.w   #300,d0                 ; add offset

	move.w  d0,ovrlaper(a4)
	lea     err_hook(a4),a1
	bsr     try_hook

errdone rts
	page
********************************************************************************
*                                                                              *
*       routine data_rx_isr: Handles moving received data to the user's        *
*               ===========  buffer for an inbound TRANSFER.                   *
*                                                                              *
********************************************************************************

data_rx_isr equ *
	btst    #rx_int,intbits(a4)     ; Test for bit #1 for this condition
	beq.s   data_tx_isr
	bsr     do_inxfr

********************************************************************************
*                                                                              *
*       routine data_tx_isr: Handles moving transmit data from the user's      *
*               ===========  buffer to the card for an outbound TRANSFER.      *
*                                                                              *
********************************************************************************

data_tx_isr equ *
	btst    #tx_int,intbits(a4)     ; Test for bit #2 for this condition
	beq.s   ON_INTR_isr
	bsr     do_outxfr

********************************************************************************
*                                                                              *
*       routine ON_INTR_isr: Handles the communication of an ON INTR trigger   *
*               ===========  from the interface card back to BASIC.            *
*                                                                              *
********************************************************************************

ON_INTR_isr equ *
	btst    #ON_INTR_int,intbits(a4) ; Test for bit #3 for this condition
	beq     trace_isr

	bclr    #ON_INTR_int,usr0mask(a4)
	beq.s   OIisr1          ; If already 0 don't send again
	bsr     put_INTMASK

OIisr1  lea     USER_ISR(a4),a1
	bsr     try_hook_P              (TM)    7/30/82 bug 158

trace_isr equ *
	btst    #trace_int,intbits(a4)  ; Test for bit #5 for this condition
	beq.s   bit_6_isr
	lea     trc_hook(a4),a1
	bsr     try_hook

bit_6_isr equ *
	btst    #6,intbits(a4)          ; Test for bit #6 for this condition
	beq.s   bit_7_isr
	lea     bt6_hook(a4),a1
	bsr     try_hook
	page
bit_7_isr equ *
	btst    #7,intbits(a4)          ; Test for bit #7 for this condition
	beq.s   end_isr
	lea     bt7_hook(a4),a1
	bsr     try_hook


* -------------------------- End of the ISR ------------------------------------

end_isr equ     *

********** RECOVER SECTION FROM 'TRY' ABOVE *****

	move.l  8(sp),RCVR_BLK(a5)
	adda.l  #12,sp
	bra.s   rcvdone

recover_section equ *           ; On escape, flag overlapped error
	movea.l (sp)+,a6        ; to background
	move.l  (sp)+,RCVR_BLK(a5)

* Body of 'RECOVER' block:
	cmpi.w  #IOE_ERROR,ESC_CODE(a5)
	bne.s   rcvdone         ; Throw away non-I/O errors
	move.b  IO_SC(a4),d0
	cmp.b   IOE_SC(a5),d0
	bne.s   rcvdone
	move.w  IOE_RSLT(a5),ovrlaper(a4)
* That was it!

rcvdone movem.l (sp)+,a3/a4
	bsr     eir
	move.w  int_savespace(a4),term_and_mode(a4)
	movem.l int_savespace+2(a4),d0-d5
	movem.l d0-d5,term_and_mode+2(a4)
	rts             ; Return from ISR


try_hook move.l (a1),d0
	beq.s   hook1
	movem.l a3/a4,-(sp)
	movea.l d0,a0
HOOK4   move.l  4(a1),d0                (tm)    12/03/81
	beq.s   hook3                   (tm)    If there is static link - push it
	move.l  d0,-(sp)                (tm)    Roger Ison said this is okay
hook3   jsr     (a0)
hook2   movem.l (sp)+,a3/a4
hook1   rts


try_hook_P move.l (a1),d0               (TM)    7/30/82 bug 158
	beq.s   hook1
	movem.l a3/a4,-(sp)
	movea.l d0,a0
	MOVE.L  8(A1),-(SP)             (TM)    7/30/82 bug 158
	BRA     HOOK4                   (TM)    7/30/82 bug 158
	page
*************************************************
*                                               *
*   routine do_inxfr:  Transfers data in until: *
*               - User buffer filled;           *
*               - Card buffer empty; or         *
*               - Control block reached.        *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

do_inxfr equ    *
	movea.l BUFI_OFF(a4),a2
	beq     inxdone

	move.l  TCNT_OFF(a2),data_number(a4)
	beq     inxdn1
	move.l  TFIL_OFF(a2),data_address(a4)

inxfr1  bsr     find_RXBUF      ; Set up a2.l = buffer descriptor record
*                                                       base address
inxfr4  bsr     RX_stuff_avail  ; See if buffer is empty
	tst.b   d0              ; If so, just sit here & wait
	beq     inxexit

	bsr     ctrlblknext     ; If a control block is next, then
	tst.b   d0
	bne.s   inxfr3

	tst.l   data_number(a4) ; see if chars to transfer
	beq.s   inxdone         ; yes, go do it

	movea.l BUFI_OFF(a4),a1
	move.w  TCHR_OFF(a1),d0 ; Check for term char desired
	bge.s   inxfr5          ; Yes - goto slow section

	bsr     getchars        ; move some data
*                               ; & go back to check for ctrl blk
	bra.s   inxfr1

inxfr5  equ     *       ; SLOW ENTER - search for char
	move.b  d0,-(sp)        ; Save search char
	move.l  data_number(a4),-(sp)
	move.l  #1,data_number(a4)
	bsr     getchars
	move.l  (sp)+,data_number(a4)
	subq.l  #1,data_number(a4)
	move.b  (sp)+,d0        ; Check for term chr
	movea.l data_address(a4),a0
	cmp.b   -1(a0),d0       ; If equal, exit
	beq.s   inxdone
	bra.s   inxfr1

inxfr3  bsr     getctrlblk      ; Get it, and check for the special
	cmpi.b  #255,term(a4)   ; case TERM=255
	bne.s   inxfr2
	move.b  mode(a4),which_RXbuf(a4) ;If so, do the buffer switch
	bra.s   inxfr1          ; And go back for more

inxfr2  move.w  term_and_mode(a4),last_enter_term(a4)
*                               ; Otherwise save the control block & leave
	movea.l BUFI_OFF(a4),a2
	tst.b   TEND_OFF(a2)    ; If EOI term bit set tghen
	beq.s   inxfr1          ; leave else ignore

inxdone movea.l BUFI_OFF(a4),a2
	move.l  data_address(a4),TFIL_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
inxdn1  bsr     inxfr_done
	move.l  a2,d0
	beq.s   inxex1
	lea     T_PR_OFF(a2),a1
	bra     try_hook_P                      (TM)    7/30/82 bug 158

inxexit equ     *
	movea.l BUFI_OFF(a4),a2
	move.l  data_address(a4),TFIL_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
	beq.s   inxdn1                          BUG 1249   TM 01/08/82
inxex1  rts
	page
*************************************************
*                                               *
*   routine do_outxfr:  Transfers data out til: *
*               - User buffer emptied; or       *
*               - Card buffer filled.           *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*   During execution:                           *
*       a2.l =  address of xfr record           *
*                                               *
*************************************************

do_outxfr equ   *
	movea.l BUFO_OFF(a4),a2
	move.l  a2,d0
	beq.s   outxex1

	move.l  TCNT_OFF(a2),data_number(a4)
	beq.s   outxd0
	move.l  TEMP_OFF(a2),data_address(a4)

	bsr     find_TXBUF      ; a2 = buff descr rec addr

outx1   move.l  data_number(a4),-(sp)
	bsr     putchars        ; Send some chars
	move.l  (sp)+,d0
	cmp.l   data_number(a4),d0
	beq.s   outxit          ; If no chars transferred
	tst.l   data_number(a4) ; then exit
	bne.s   outx1           ; Check buffer empty

outxdun movea.l BUFO_OFF(a4),a2
	move.l  data_address(a4),TEMP_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
outxd0  movea.l BUFO_OFF(a4),a2
	tst.b   TEND_OFF(a2)    ; Check for END termination
	beq.s   outxdn1
	bsr     find_TXBUF      ; a2 = buff descr rec addr
	bsr     try_sending_EOF
	tst.b   d0              ; If couldn't send it then
	beq.s   outxex1         ; return, wait for next interrupt

outxdn1 bsr     outxfr_done
	move.l  a2,d0
	beq.s   outxex1
	lea     T_PR_OFF(a2),a1
	bra     try_hook_P                   (TM)    7/30/82 bug 158

outxit  movea.l BUFO_OFF(a4),a2
	move.l  data_address(a4),TEMP_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
outxex1 rts
	page
*************************************************
*                                               *
*   routine outxfr_done:  Terminates the        *
*               outbound transfer, if any.      *
*                                               *
*   routine inxfr_done:  Terminates the inbound *
*               transfer, if any.               *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

outxfr_done equ *
	bclr    #tx_int,usr0mask(a4)
	beq.s   outxd1          ; If already 0 don't send again
	bsr     put_INTMASK
outxd1  lea     BUFO_OFF(a4),a0
	bra.s   xfrdun


inxfr_done equ *
	bclr    #rx_int,usr0mask(a4)
	beq.s   inxd1           ; If already 0 don't send again
	bsr     put_INTMASK
inxd1   lea     BUFI_OFF(a4),a0

xfrdun  movea.l (a0),a2
	move.l  a2,d0
	beq.s   rtsin
	move.b  #255,T_SC_OFF(a2)
	clr.b   TACT_OFF(a2)
	clr.l   (a0)
rtsin   rts
	page
*************************************************
*                                               *
*   routine wait_outxfrdone: waits until an     *
*               outbound transfer is complete   *
*               (if any).  Also has timeout     *
*               escape.                         *
*                                               *
*   routine wait_inxfrdone: waits until an      *
*               inbound transfer is complete    *
*               (if any).  Also has timeout     *
*               escape.                         *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*   This bashes nothing.                        *
*                                               *
*   This routine may escape!                    *
*                                               *
*   MODIFIED by Tim Mikkelsen 12/02/81          *
*            from 12/01/81 code to 11/23/81     *
*                                               *
*************************************************

wait_outxfrdone equ *
	movem.l d0/d2/a0,-(sp)
	movea.l BUFO_OFF(a4),a0
	bra.s   wait

wait_inxfrdone equ *
	movem.l d0/d2/a0,-(sp)
	movea.l BUFO_OFF(a4),a0

wait    move.l  a0,d2           ; 0=no xfr block
	beq.s   waitdun
	cmpi.b  #5,TUSR_OFF(A0) ; >4 = interrupt
	blt.s   waitdun
	move.l  timeout(a4),d2
	btst    #timer_present,sysflag2   is timer available ? tttt JS 8/11/83
	beq.s   wait_timer                if so then use it    tttt JS 8/11/83

wait1   move.l  #256,d0         [UNCALIBRATED] - guess based upon check_tfr loop
wait2   tst.b   TACT_OFF(a0)    ; 0=inactive            (tm)  tst.l -> tst.b
	beq.s   waitdun

	subq.l  #1,d0           ; Timeout computation
	bne.s   wait2
	tst.l   d2
	beq.s   wait1
	subq.l  #1,d2        bug fix -- was d0                 tttt JS 8/11/83
	bne.s   wait1
	bra     time_err

waitdun movem.l (sp)+,d0/d2/a0
	rts

wait_timer equ *
	tst.l   d2             check for infinite timeout    tttt JS 8/11/83
	beq     wait1          use loops if infinite         tttt JS 8/11/83
	move.b  #1,-(sp)          set up timer record        tttt JS 8/11/83
	move.l  d2,-(sp)          d2 has ms to wait          tttt JS 8/11/83
wait3   tst.b   tact_off(a0)      xfr done?                  tttt JS 8/11/83
	beq.s   wait4             if so then exit loop       tttt JS 8/11/83
	pea     (sp)              push ptr to time rec       tttt JS 8/11/83
	jsr     check_timer       and check the timer        tttt JS 8/11/83
	bpl     wait3             if no timeout, keep trying tttt JS 8/11/83
	bra     time_err          timeout -- go escape       tttt JS 8/11/83
wait4   addq    #6,sp             normal exit -- clean stack tttt JS 8/11/83
	bra     waitdun           and return                 tttt JS 8/11/83

	page
*************************************************
*                                               *
*   procedure START_TRANSFER_IN (               *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*   During use:                                 *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

START_TRANSFER_IN equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	trap    #11             get into supervisor mode                scs
* scs   move    sr,-(sp)        ; Funny code to disable
	move    SR_image(a4),sr ; interrupts
	bset    #rx_int,usr0mask(a4)
	bsr     put_INTMASK
	bsr     do_inxfr
	move    (sp)+,sr
	bra     check_ov_error  ; Will enable ints
	page
*************************************************
*                                               *
*   procedure START_TRANSFER_OUT (              *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*   During use:                                 *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

START_TRANSFER_OUT equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	trap    #11                                                     scs
* scs   move    sr,-(sp)        ; Funny code to disable
	move    SR_image(a4),sr ; interrupts
	bset    #tx_int,usr0mask(a4)
	bsr     put_INTMASK
	bsr     do_outxfr
	move    (sp)+,sr
	bra     check_ov_error  ; Will enable ints

    ttl     dc_rxbuf: Rx buffer utilities
    page


*       ****    *   *   ****    *   *   *****   *****   *****   ****
*       *   *   *   *   *   *   *   *   *       *       *       *   *
*       *   *    * *    *   *   *   *   *       *       *       *   *
*       ****      *     ****    *   *   *****   *****   *****   ****
*       *  *     * *    *   *   *   *   *       *       *       *  *
*       *   *   *   *   *   *   *   *   *       *       *       *   *
*       *   *   *   *   ****     ***    *       *       *****   *   *





********************************************************************************
*                                                                              *
*       routine set_RXBUF_a6:   Routine to set a6 as the base address          *
*               ============    pointer to whichever Rx buffer is being used.  *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  data buffer base address (shifted, +1+selectcode)      *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               a6.l =  Base address of DATA_BUFFERS[WHICH_RXBUF]              *
*               This also bashes d0.                                           *
*                                                                              *
********************************************************************************

set_RXBUF_a6 equ *
	clr.l   d0                      ; Setup d0.l=offset
	move.b  which_RXbuf(a4),d0      ; to which Rx buffer
	asl.l   #4,d0                   ; being used
	lea     DATA_AREA(a2,d0),a6
	rts
	page
********************************************************************************
*                                                                              *
*       routine RX_BUFF_bytes:  Function which returns the number of           *
*               =============   characters until the first control block in    *
*                               the Receive Buffer.  If there are no control   *
*                               blocks, this just returns the number of        *
*                               characters in the buffer.  This only works     *
*                               on the current Rx data buffer, and does not    *
*                               extract TERM=255 control blocks!               *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  data buffer base address (shifted, +1+selectcode)      *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  Number of characters.                                  *
*               a1, d4 and d5 are left with values from find_RX_DATA.          *
*               This also bashes a0, d1 and d2.                                *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and find_RX_DATA.      *
*                                                                              *
********************************************************************************

RX_BUFF_bytes equ *
	bsr     find_RX_DATA            ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  a6,-(sp)
	bsr     set_RXBUF_a6

	clr.l   d0                      ; Get garbage out of top of d0, d1
	clr.l   d1
	movep.w CTRL_AREA+EMPTY(a2),d1  ; Fetch pointers (bytes in wrong order)
	bsr     gain_access             ; Need access to FILL pointers
	movep.w FILL(a6),d0
	movep.w CTRL_AREA+FILL(a2),d2
	bsr     release_access
	cmp.w   d2,d1                   ; If the two ctrl block pointers are not
	beq.s   RBb1                    ; equal, then we want to use the pointer
	ror.w   #7,d1                   ; field from the next control block to
	add.l   a3,d1                   ; indicate how much data may be removed
	movea.l d1,a0
	movep.w POINTER(a0),d0          ; --- Use it as the "FILL" pointer

RBb1    ror.w   #8,d0                   ; Switch bytes for FILL
	movep.w EMPTY(a6),d1            ; and get EMPTY and switch bytes
	ror.w   #8,d1                   ; d0="FILL", d1=EMPTY

	sub.w   d1,d0                   ; Compute d0 := FILL-EMPTY
	bge.s   RBb2
	add.w   d5,d0                   ; If negative, add data buffer size
RBb2    movea.l (sp)+,a6
	rts     ; Now d0 = ("FILL"-EMPTY) mod SIZE --- of data buffer
	page
********************************************************************************
*                                                                              *
*       routine getctrlblk:     Routine which gets a control block from the    *
*               ==========      Receive buffer.  It must have already been     *
*                               determined that there is a control block at    *
*                               the front of the buffer, since this routine    *
*                               does NOT check for that condition.  The TERM   *
*                               and MODE fields of the removed block are left  *
*                               in the appropriate (.term and .mode) in the    *
*                               sc_subtabletype structure.                     *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               sc_subtabletype.term =  TERM field of control block (8 bits)   *
*               sc_subtabletype.mode =  MODE field of control block (8 bits)   *
*               a1, d4 and d5 are left with the values from find_CTRL_AREA.    *
*               This bashes d0, d2, and a0.                                    *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and find_CTRL_AREA.    *
*                                                                              *
********************************************************************************

getctrlblk equ  *
	bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TRCTRLBUFF_SIZE

	clr.l   d0                      ; Clear top of d0
	movep.w CTRL_AREA+EMPTY(a2),d0  ; Get control buffer EMPTY pointer
	ror.w   #7,d0                   ; Now make it into a 68000 pointer
	add.l   a3,d0
	movea.l d0,a0                   ; Move to a0 so we can use it

	move.b  TERMFIELD(a0),term(a4)  ; Store term & mode fields
	move.b  MODEFIELD(a0),mode(a4)

	add.w   #CTRLBLKSIZE,d0         ; Bump pointer by control block size
	cmp.w   d0,d4                   ; and check for wraparound.
	bne.s   gcb1
	move.w  a1,d0                   ; If so, set to front of buffer
gcb1    bclr    #0,d0                   ; Make it into a Z80
	rol.w   #7,d0                   ; type pointer with bytes reversed
	bsr     gain_access             ; Now store the updated EMPTY pointer
	movep.w d0,CTRL_AREA+EMPTY(a2)
	bsr     release_access
	rts     ;<<<CAN'T COMBINE WITH ABOVE!!!!!
	page
********************************************************************************
*                                                                              *
*       routine getchars:       Routine which takes characters from the        *
*               ========        Receive buffer and puts them in the area       *
*                               pointed to by sc_subtabletype.data_address     *
*                               and sized by sc_subtabletype.data_number.      *
*                               The number of characters                       *
*                               actually transfered is the minimum of:         *
*                               (1) the number of characters available before  *
*                               the first Receive buffer control block;        *
*                               (2) sc_subtabletype.data_number;               *
*                               and (3) the number of characters               *
*                               available until the Receive buffer wraparound  *
*                               point.  THIS NUMBER MAY BE ZERO!               *
*                               This alters data_address and data_number to    *
*                               reflect where to start going next time this    *
*                               is called.  The criteria for ending the        *
*                               transfer at a higher level must be determined  *
*                               by data_number, RX_stuff_avail and             *
*                               ctrl_blk_next/getctrlblk.                      *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               data_address and data_number are updated, plus the EMPTY       *
*               pointer in the card's Receive data buffer.                     *
*               In sc_subtabletype last_enter_term and last_enter_mode are     *
*               zeroed if any data is moved.                                   *
*               a1 and d4 are left with the values from find_RX_DATA.          *
*               This bashes d0, d1, d2, d3, d4, d5, a0, and a1.                *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and RX_BUFF_bytes.     *
*                                                                              *
********************************************************************************

getchars equ    *
	bsr     RX_BUFF_bytes           ; Setup a1 = data buffer base addr
*                                               d3 = offset to which Rxbuff used
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  d0,d3                   ; d3.l = available characters

	movem.l a2/a6,-(sp)             ; Saved for local use
	bsr     set_RXBUF_a6

	clr.l   d0
	movep.w EMPTY(a6),d0            ; Get RXDATABUFF_EMPTY and make
	ror.w   #7,d0                   ; it into a 68000 pointer
	add.l   a3,d0
	movea.l d0,a2                   ; Save EMPTY for later!

	sub.l   d4,d0
	neg.l   d0                      ; d0 = wraparound address - EMPTY
	and.l   #$0000FFFE,d0
	ror.w   #1,d0                   ; d0.l = number of bytes till wraparound

	cmp.l   d0,d3                   ; If d0>d3 then set d0 := d3
	bgt.s   gc1
	move.l  d3,d0

gc1     move.l  data_number(a4),d2      ; Fetch number of positions available
	cmp.l   d0,d2                   ; If d0>d2 then set d0 := d2
	bgt.s   gc2
	move.l  d2,d0

gc2     move.l  d0,d3                   ; d3.l saves number of chars actually
*                                       ; transferred below
	beq.s   gcdone                  ; If zero, no work to be done
	clr.w   last_enter_term(a4)     ; This also clears last_enter_mode.
	subq.w  #1,d0                   ; Make offset correct for dbf instr.
	movea.l data_address(a4),a0     ; Get character pointer into a0

gcloop  move.b  (a2),(a0)+              ; Transfer a character & bump dest ptr
	addq.w  #2,a2                   ; Bump source pointer (odd bytes)
	dbf     d0,gcloop               ; Then decrement d0 & loop

	sub.l   d3,d2                   ; Decrement datacnt by # bytes
	move.l  d2,data_number(a4)      ; Now store adjusted address and
	move.l  a0,data_address(a4)     ; number fields

	move.l  a2,d1                   ; Store pointer for computations
	cmp.l   a2,d4                   ; Now check to see if EMPTY was moved
	bne.s   gc3                     ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
gc3     bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,EMPTY(a6)            ; Remember d1 = card's EMPTY pointer.
	bsr     release_access
gcdone  movem.l (sp)+,a6/a2
	rts
	page
********************************************************************************
*                                                                              *
*       routine RX_stuff_avail: Routine which determines whether there is      *
*               ==============  ANYTHING (data or control blocks) in the       *
*                               Receive buffer.  This consumes any TERM=255    *
*                               control blocks before returning the function.  *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  $00 if buffer is empty,                                *
*                       $01 if ctrl buffer is empty and data buffer is not,    *
*                       $02 if data buffer is empty and ctrl buffer is not,    *
*                       $03 if both data and ctrl buffers are not empty.       *
*               a1 and d4 are left with the values from find_RX_DATA.          *
*               This bashes d0, d1, d2, d3, d4, d5, a0 and a1.                 *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access and release_access.                     *
*                                                                              *
********************************************************************************

RX_stuff_avail equ *
	bsr     find_RX_DATA            ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  a6,-(sp)
	bsr     set_RXBUF_a6

	bsr     gain_access
	movep.w FILL(a6),d3             ; Fetch FILL & EMPTY (bytes reversed but
	movep.w CTRL_AREA+FILL(a2),d1
	bsr     release_access          ; we're just checking equality)
	clr.l   d2
	clr.l   d0
	movep.w CTRL_AREA+EMPTY(a2),d2
	cmp.w   d1,d2                   ; Compare ctrl buff FILL & EMPTY
	bne.s   setbit1                 ; If not equal, then set bit 1
chkdata movep.w EMPTY(a6),d2
	cmp.w   d3,d2                   ; Compare data buff FILL & EMPTY
	beq.s   return
	addq.b  #1,d0                   ; And set bit 0 if not equal
return  movea.l (sp)+,a6
	rts

setbit1 addq.b  #2,d0                   ; Set "ctrl not empty" bit
	ror.w   #7,d2                   ; Something in control buffer - see if
*                                       ; this control block is at the head of
	add.l   a3,d2                   ; the queue (bytes reversed!)
	movea.l d2,a0
	movep.w POINTER(a0),d1
	movep.w EMPTY(a6),d2
	cmp.w   d2,d1                   ; if POINTER field<>DATABUFF_EMPTY
	bne.s   chkdata                 ;   then go check data buff
	cmpi.b  #255,TERMFIELD(a0)      ; else if it's a TERM=255 control block
	bne.s   chkdata                 ; No, go back and check data buff

	bsr     getctrlblk              ; Otherwise consume the control block
	move.b  mode(a4),which_RXbuf(a4) ;and switch to new data buffer
	movea.l (sp)+,a6
	bra.s   RX_stuff_avail          ; And go back and re-compute result
	page
********************************************************************************
*                                                                              *
*       routine ctrlblknext:    Routine which determines whether the next      *
*               ===========     thing to be consumed from the Receive buffer   *
*                               is a control block.  THE RESULT OF THIS        *
*                               FUNCTION IS NOT VALID UNLESS RX_BUFFER_empty   *
*                               RETURNS FALSE!!!                               *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon exit:                                                             *
*               d0.b =  $FF if control block is next, $00 if data is next.     *
*               This bashes d2, d5 and a0.                                     *
*                                                                              *
********************************************************************************

ctrlblknext equ *
	bsr     gain_access
	movep.w CTRL_AREA+FILL(a2),d2   ; Check if ctrl buffer is empty
	bsr     release_access
	clr.l   d0
	movep.w CTRL_AREA+EMPTY(a2),d0  ; Fetch ctrl buffer EMPTY pointer
	cmp.w   d0,d2                   ; If equal then return d0.b=$00
	beq.s   cbn1
	ror.w   #7,d0
	add.l   a3,d0
	movea.l d0,a0
	movep.w POINTER(a0),d0          ; Fetch the POINTER field from the

	clr.l   d5                      ; Setup d5.l=offset
	move.b  which_RXbuf(a4),d5      ; to which Rx buffer
	asl.l   #4,d5                   ; being used

	movem.l d0/a6,-(sp)
	bsr     set_RXBUF_a6
	movep.w EMPTY(a6),d2            ; first ctrl block and compare to the
	movem.l (sp)+,d0/a6

	cmp.w   d0,d2                   ; data buffer EMPTY pointer
	seq     d0                      ; Then set d0 if equal
	rts

cbn1    clr.l   d0
	rts

    ttl     dc_trans: Handshake transfer code
    page


*       *****   ****     ***    *   *    ***    *****   *****   ****
*         *     *   *   *   *   **  *   *   *   *       *       *   *
*         *     *   *   *   *   * * *   *       *       *       *   *
*         *     ****    *****   *  **    ***    ***     ***     ****
*         *     *  *    *   *   *   *       *   *       *       *  *
*         *     *   *   *   *   *   *   *   *   *       *       *   *
*         *     *   *   *   *   *   *    ***    *       *****   *   *




in_timeout      equ     6  [UNCALIBRATED 1 MS]
out_timeout     equ     7  [UNCALIBRATED 1 MS]


*************************************************
*                                               *
*   procedure OUTPUT_DATA (                     *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               COUNT:    longword       );     *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   This routine calls find_TXBUF and putchars. *
*                                               *
*************************************************

output_data equ *
	movea.l (sp)+,a0
	move.l  (sp)+,d1        ; COUNT
	movea.l (sp)+,a1        ; PTR
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  a1,data_address(a4)     ; initialize address/count
	move.l  d1,data_number(a4)

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_outxfrdone

	move.l  timeout(a4),timeout_counter(a4)
	move.l  #out_timeout,inner_counter(a4)

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	beq.s   outdone

	btst    #timer_present,sysflag2   check for timer      tttt JS 8/11/83
	beq.s   outtimer                  if got it, use it    tttt JS 8/11/83

out_2   tst.l   data_number(a4)         ; And transfer characters until done
	beq.s   outdone
	bsr     putchars
	subq.l  #1,inner_counter(a4)    ; Test for timeout condition
	bne.s   out_2
	move.l  #out_timeout,inner_counter(a4)
	tst.l   timeout_counter(a4)
	beq.s   out_2
	subq.l  #1,timeout_counter(a4)
	beq     time_err                ; if so, escape
	bra.s   out_2

outdone rts
*
outtimer tst.l  timeout(a4)           see if infinit timeout  tttt JS 8/11/83
	beq     out_2                 if so don't use this    tttt JS 8/11/83
	move.b  #1,-(sp)             else setup timer record  tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                             tttt JS 8/11/83
outtloop tst.l  data_number(a4)      check if all done        tttt JS 8/11/83
	beq.s   outtexit             if so then get out       tttt JS 8/11/83
	bsr     putchars             else send chars          tttt JS 8/11/83
	pea     (sp)                 push ptr to time rec     tttt JS 8/11/83
	jsr     check_timer          and check the timer      tttt JS 8/11/83
	bpl     outtloop             if not timeout keep going tttt JS 8/11/83
	bra     time_err             else do timeout escape   tttt JS 8/11/83
outtexit addq   #6,sp                normal exit -- cleanup   tttt JS 8/11/83
	rts                          and return               tttt JS 8/11/83

	page
*************************************************
*                                               *
*   procedure ENTER_DATA (                      *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               var COUNT:longword       );     *
*                                               *
*  COUNT initially passes the number of bytes   *
*  which the upper level wants to read.  THE    *
*  ROUTINE DOES NOT NECESSARILY READ THIS MANY! *
*  Upon exit COUNT will be reflect the number   *
*  of data bytes entered, whether or not there  *
*  is an escape.                                *
*                                               *
*  escape(EOD): Terminated by reaching a control*
*     block.  TERM&MODE may be read with STATUS *
*     9 and 10.                                 *
*                                               *
*       This routine calls find_RXBUF,          *
*       getctrlblk, getchars, ctrlblknext, and  *
*       RX_BUFFER_EMPTY.                        *
*                                               *
*************************************************

enter_data equ  *
	movea.l (sp)+,a0
	movea.l (sp)+,a2        ; addr(COUNT)
	movea.l (sp)+,a1        ; PTR
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  a1,data_address(a4)     ; initialize address

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_inxfrdone

	move.l  timeout(a4),timeout_counter(a4)
	move.l  #in_timeout,inner_counter(a4)

	move.l  (a2),data_number(a4)
	move.l  a2,-(sp)

	btst    #timer_present,sysflag2   is timer present?  tttt JS 8/11/83
	bne.s   in_1                     if not, continue    tttt JS 8/11/83
	move.b  #1,-(sp)              else stack time rec    tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                            tttt JS 8/11/83

	bra.s   in_1

in_0    bsr     eir
	tst.l   data_number(a4)         ; See if all characters transferred
	beq.s   in_exit                 ; If so, leave

in_1    bsr     find_RXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	btst    #timer_present,sysflag2  using timer?         tttt JS 8/11/83
	bne.s   in_1b                    if not then skip     tttt JS 8/11/83
	tst.l   timeout(a4)              infinite timeout?    tttt JS 8/11/83
	beq.s   in_4                     then skip checking   tttt JS 8/11/83
	pea     (sp)                   push ptr to time re    tttt JS 8/11/83
	jsr     check_timer            and check timer        tttt JS 8/11/83
	bpl.s   in_4            if not timeout, keep trying   tttt JS 8/11/83
	addq    #6,sp           else clean stack              tttt JS 8/11/83
	bra.s   in_1c           and do timeout stuff          tttt JS 8/11/83

in_1b   subq.l  #1,inner_counter(a4)    ; Test for timeout condition
	bne.s   in_4
	move.l  #in_timeout,inner_counter(a4)
	tst.l   timeout_counter(a4)
	beq.s   in_4
	subq.l  #1,timeout_counter(a4)
	bne.s   in_4
in_1c   movea.l (sp)+,a0
	move.l  (a0),d0
	sub.l   data_number(a4),d0
	move.l  d0,(a0)
	bra     time_err

in_4    bsr     dir
	bsr     RX_stuff_avail          ; See if buffer is empty
	tst.b   d0                      ; If so, just sit here & wait
	beq.s   in_0

	bsr     ctrlblknext             ; If a control block is next, then
	tst.b   d0
	beq.s   in_3

	bsr     getctrlblk              ; Get it, and check for the special
	cmpi.b  #255,term(a4)           ; case TERM=255
	bne.s   in_2
	move.b  mode(a4),which_RXbuf(a4) ;If so, do the buffer switch
	bra.s   in_1                    ; And go back for more

in_2    move.w  term_and_mode(a4),last_enter_term(a4)
*                                       ; Otherwise save the control block & leave
in_exit btst    #timer_present,sysflag2  using timer?        tttt JS 8/11/83
	bne.s   in_ex2                   no -- skip ahead    tttt JS 8/11/83
	addq.l  #6,sp                    else clean stack    tttt JS 8/11/83
in_ex2  bsr     eir
	movea.l (sp)+,a0
	move.l  (a0),d0
	sub.l   data_number(a4),d0
	move.l  d0,(a0)
	tst.l   data_number(a4)
	beq     outdone                 ; If nonzero then early EOI; escape
	moveq   #EOD_SEEN,d0
	bra     escape

in_3    tst.l   data_number(a4)         ; see if chars to transfer
	beq.s   in_exit                 ; yes, go do it

	bsr     getchars                ; move some data
	bra     in_0                    ; & go back to check for ctrl blk
	page
*************************************************
*                                               *
*   procedure OUTPUT_END (                      *
*               var SCT:  select_code_table );  *
*                                               *
*   Equivalent to the BASIC OUTPUT Sc;END.      *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   This routine calls find_TXBUF and           *
*   try_sending_EOF.                            *
*                                               *
*************************************************

output_end equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_outxfrdone

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	move.l  timeout(a4),outer_tx_count(a4)
	move.l  #sEtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)             infinite loop? tttt JS 5/3/84
	beq.s   trysend                     yes, normal loop  tttt JS 5/3/84
	btst    #timer_present,sysflag2        timer avail?   tttt JS 5/3/84
	beq.s   try_timer                      if so, use it  tttt JS 5/3/84

trysend bsr     try_sending_EOF
	tst.b   d0
	bne.s   sentEOF

	subq.l  #1,inner_tx_count(a4)
	bne.s   trysend
	move.l  #sEtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)
	beq.s   trysend
	subq.l  #1,outer_tx_count(a4)
	bne.s   trysend
	bra     time_err

sentEOF rts

try_timer move.b #1,-(sp)                  setup timer record  tttt JS 5/3/84
	move.l  timeout(a4),-(sp)                              tttt JS 5/3/84
try_timer2 bsr     try_sending_EOF                             tttt JS 5/3/84
	tst.b   d0                         successful?         tttt JS 5/3/84
	bne.s   try_timer3                 yes, get out        tttt JS 5/3/84
	pea     (sp)                     point to timer rec    tttt JS 5/3/84
	jsr     check_timer              and check timer       tttt JS 5/3/84
	bpl     try_timer2               if no timeout, loop   tttt JS 5/3/84
	addq    #6,sp                    timeout, one more try tttt JS 5/3/84
	move.l  #1,outer_tx_count(a4)    with short count      tttt JS 5/3/84
	bra     trysend                                        tttt JS 5/3/84
try_timer3 addq   #6,sp                  clean stack           tttt JS 5/3/84
	rts                              and return            tttt JS 5/3/84

	page
*************************************************
*                                               *
*   procedure CONTROL_BFD (                     *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               VAL:      0..255);              *
*                                               *
*   Control register 0 is intercepted and       *
*   if MODE=0 no action is performed, otherwise *
*   the card is reset IMMEDIATELY.              *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*   This routine calls find_TXBUF and putctrlblk*
*                                               *
*************************************************

control_bfd equ *
	movea.l (sp)+,a0
	move.w  (sp)+,d1        ; VAL
	move.w  (sp)+,d2        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if o/v error
*                               (tm) moved by Tim Mikkelsen 12/02/81
	move.b  d2,term(a4)     (tm) ; Intercept CONTROL 0
	beq.s   ctrl0           (tm)

	bsr     wait_outxfrdone

	move.b  d1,mode(a4)

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
	bra     putctrlblk              ;               base address

ctrl0   tst.b   d1
	beq.s   ctrldun
	bsr     wait_inxfrdone
	bra     do_reset
ctrldun rts

    ttl     dc_txbuf: Tx buffer utilities
    page


*       *****   *   *   ****    *   *   *****   *****   *****   ****
*         *     *   *   *   *   *   *   *       *       *       *   *
*         *      * *    *   *   *   *   *       *       *       *   *
*         *       *     ****    *   *   *****   *****   *****   ****
*         *      * *    *   *   *   *   *       *       *       *  *
*         *     *   *   *   *   *   *   *       *       *       *   *
*         *     *   *   ****     ***    *       *       *****   *   *



sEtimeout       equ     11   [UNCALIBRATED]
pcbtimeout      equ     11   [CALIBRATED 1 MS]


********************************************************************************
*                                                                              *
*       routine TXCTRLBUFFroom: Function which returns the number of byte      *
*               ==============  positions as yet unused in the Transmit ctrl   *
*                               Buffer.                                        *
*                                                                              *
*       routine TXDATABUFFroom: Function which returns the number of byte      *
*               ==============  positions as yet unused in the Transmit data   *
*                               Buffer.                                        *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  TXBUFF base address (shifted, +1+selectcode)           *
*               a3.l =  card base address ($00xx0001)                          *
*               d5.l =  TXDATABUFF_SIZE or TXCTRLBUFF_SIZE                     *
*                       (unshifted, not adjusted)                              *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  TXDATABUFF_FILL or TXCTRLBUFF_FILL (unshifted)         *
*               d3.l =  Number of bytes left                                   *
*               This also bashes d2.                                           *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access and release_access.                     *
*                                                                              *
********************************************************************************

TXCTRLBUFFroom equ *
	clr.l   d0                      ; Get garbage out of top of d0&d3
	clr.l   d3
	movep.w CTRL_AREA+FILL(a2),d0
	bsr     gain_access             ; Need access to EMPTY
	movep.w CTRL_AREA+EMPTY(a2),d3  ; Fetch pointers (bytes in wrong order)
	bra.s   room1

TXDATABUFFroom equ *
	clr.l   d0                      ; Get garbage out of top of d0&d3
	clr.l   d3
	movep.w DATA_AREA+FILL(a2),d0
	bsr     gain_access             ; Need access to EMPTY
	movep.w DATA_AREA+EMPTY(a2),d3  ; Fetch pointers (bytes in wrong order)
room1   bsr     release_access

	ror.w   #8,d0                   ; Switch bytes in d0 & d3
	ror.w   #8,d3

	sub.w   d0,d3                   ; Compute d3 := EMPTY-FILL
	subq.w  #1,d3                   ; (EMPTY-FILL-1)
	bge.s   room2
	add.w   d5,d3                   ; If negative, add size

room2   rts                             ; Return (EMPTY-FILL-1) mod SIZE
	page
********************************************************************************
*                                                                              *
*       routine putchars:       Routine which takes characters from the        *
*               ========        area sc_subtabletype.data_address sized by     *
*                               sc_subtabletype.data_number and moves          *
*                               them to the Transmit buffer.  The number of    *
*                               characters actually transfered is the minimum  *
*                               of: (1) the number of characters available;    *
*                               (2) the number of byte positions left in the   *
*                               Transmit buffer; and (3) the number of byte    *
*                               positions in the Transmit buffer until the     *
*                               wraparound point.  THIS NUMBER CAN BE ZERO.    *
*                               This alters data_address and data_number to    *
*                               reflect where to start going next time this    *
*                               is called.  The entire transfer is done when   *
*                               data_number goes to zero.                      *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  TX buffer record base address (shifted, +1+selectcode) *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               data_number and data_address are updated, plus FILL in the     *
*               card's Transmit buffer.                                        *
*               a1, d4 and d5 are left with the values from find_DATA_AREA.    *
*               This bashes d0, d1, d2, d3, d4, d5, a0, and a1.                *
*                                                                              *
*       Interrupts:                                                            *
*               This does its own enabling/disabling.  Interrupts are left ON. *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, TXDATABUFFroom,        *
*       and find_DATA_AREA.                                                    *
*                                                                              *
********************************************************************************

putchars equ    *
	bsr     find_DATA_AREA          ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = TXDATABUFF_SIZE
	bsr     dir
	bsr     TXDATABUFFroom          ; d3.l = available buffer positions
	move.l  d0,d1                   ; d0.l = d1.l = TXDATABUFF_FILL
	move.l  d4,d0
	andi.l  #$0000FFFE,d0
	asr.l   #1,d0                   ; d0.l = unshifted TXDATABUFF_END
	sub.l   d1,d0                   ; d0.l = remaining positions to wrap

	cmp.l   d0,d3                   ; If d0>d3 then set d0 := d3
	bgt.s   pc1
	move.l  d3,d0

pc1     move.l  data_number(a4),d2      ; Fetch number of chars avail into d2
	cmp.l   d0,d2                   ; If d0>d2 then set d0 := d2
	bgt.s   pc2
	move.l  d2,d0

pc2     move.l  d0,d3                   ; d3.l saves number of chars actually
*                                       ; transferred below
	beq.s   pcdone                  ; If zero, no work to be done
	subq.w  #1,d0                   ; Make offset correct for dbf instr.
	movea.l data_address(a4),a0     ; Get character pointer into a0

	lsl.w   #1,d1
	add.l   a3,d1
	movem.l a1,-(sp)                ; Save a1 so we can use the register
	movea.l d1,a1                   ; Now a1 is useable pointer

pcloop  move.b  (a0)+,(a1)              ; Transfer a character & bump source ptr
	addq.w  #2,a1                   ; Bump destination pointer (odd bytes)
	dbf     d0,pcloop               ; Then decrement d0 & loop

	sub.l   d3,d2
	move.l  d2,data_number(a4)      ; Now store adjusted number and
	move.l  a0,data_address(a4)     ; address fields

	move.l  a1,d1                   ; Move 68000 FILL pointer into d1
	movem.l (sp)+,a1                ; Restore a1 before we forget!
	cmp.l   d1,d4                   ; Now check to see if FILL was moved
	bne.s   pc3                     ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
pc3     bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,DATA_AREA+FILL(a2)   ; Remember d1 = card's FILL pointer.
	bsr     release_access
pcdone  bra     eir
	page
********************************************************************************
*                                                                              *
*       routine putctrlblk:     Routine which puts a control block into the    *
*               ==========      Transmit buffer area of the card.  The         *
*                               appropriate pointers are updated to reflect    *
*                               the control block.  This routine also contains *
*                               a timeout mechanism which will be adjusted     *
*                               to the proper values later.  If a timeout      *
*                               occurs, an escape is done with NO DAMAGE to    *
*                               the buffer.  The only thing that can cause the *
*                               timeout is < 4 positions left in the control   *
*                               buffer.  SEMAPHORE timeout is not handled      *
*                               by this routine.                               *
*                                                                              *
*       At entry:                                                              *
*               sc_subtabletype.term =  TERM field for control block (8 bits)  *
*               sc_subtabletype.mode =  MODE field for control block (8 bits)  *
*               a2.l =  TX buffer record base address (shifted, +1+selectcode) *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               FILL in the card's transmit control buffer is updated.         *
*               a1, d4 and d5 are left with the values from find_CTRL_AREA.    *
*               This bashes d0, d1, d2, d3, d4, d5, a0 and a1.                 *
*               This uses inner/outer_tx_count for computing timeouts.         *
*                                                                              *
*       Interrupts:                                                            *
*               This does its own enabling/disabling.  Interrupts are left ON. *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls TXCTRLBUFFroom, escape, gain_access, find_CTRL_AREA,*
*       eir, dir and release_access.                                           *
*                                                                              *
********************************************************************************

putctrlblk equ  *
	bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TXCTRLBUFF_SIZE
	move.l  timeout(a4),outer_tx_count(a4)
	move.l  #pcbtimeout,inner_tx_count(a4) ; Load timeout value
*
	btst    #timer_present,sysflag2      timer present?    tttt JS 8/11/83
	beq.s   pcbtime                   if so then use it    tttt JS 8/11/83
*
pcbwait bsr     dir
	bsr     TXCTRLBUFFroom          ; Get d3 = #bytes available in buffer
	cmpi.l  #4,d3                   ; and d0 = CTRLBUFF_FILL (unshifted)
	bge.s   roomok                  ; If >=4 bytes, can go ahead!
	bsr     eir
	subq.l  #1,inner_tx_count(a4)
	bne.s   pcbwait                 ; Loop, then if it times out give an
	move.l  #pcbtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)
	beq.s   pcbwait
	subq.l  #1,outer_tx_count(a4)
	bne.s   pcbwait
	bra     time_err                ; escape(timeout).

roomok  lsl.w   #1,d0                   ; Make CTRLBUFF_FILL into a 68000
	add.l   a3,d0                   ; pointer
	movea.l d0,a0                   ; Put in a0 to use it.

	movep.w DATA_AREA+FILL(a2),d0   ; Get the DATA_FILL pointer to put
	movep.w d0,POINTER(a0)          ; into the POINTER FIELD
	move.w  term_and_mode(a4),d0
	movep.w d0,TERMFIELD(a0)
	adda.l  #CTRLBLKSIZE,a0         ; Bump pointer by TWO bytes

	move.l  a0,d1                   ; Move 68000 FILL pointer into d1
	cmp.l   d1,d4                   ; Now check to see if FILL was moved
	bne.s   pcb1                    ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
pcb1    bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,CTRL_AREA+FILL(a2)
	bsr     release_access
	bra     eir
*
pcbtime tst.l   timeout(a4)          see if infinite timeout   tttt JS 8/11/83
	beq     pcbwait              if so use other loops     tttt JS 8/11/83
	move.b  #1,-(sp)             else setup time record    tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                              tttt JS 8/11/83
pcbtloop bsr    dir                  loop checks copied from   tttt JS 8/11/83
	bsr     TXCTRLBUFFroom       code above                tttt JS 8/11/83
	cmpi.l  #4,d3                                          tttt JS 8/11/83
	bge.s   troomok              ok -- leave               tttt JS 8/11/83
	bsr     eir                                            tttt JS 8/11/83
	pea     (sp)                push ptr to time rec       tttt JS 8/11/83
	jsr     check_timer         timeout?                   tttt JS 8/11/83
	bpl     pcbtloop            no, do loop again          tttt JS 8/11/83
	addq    #6,sp               yes, clean stack and do    tttt JS 5/3/84
	move.l  #1,outer_tx_count(a4)  quick final check       tttt JS 5/3/84
	bra     pcbwait                                        tttt JS 5/3/84
troomok addq    #6,sp               normal exit -- cleanup stk tttt JS 8/11/83
	bra     roomok              and return                 tttt JS 8/11/83
	page
*************************************************
*                                               *
*   routine try_sending_EOF:  tries to send EOF *
*               and returns immediately if      *
*               unsuccessful.                   *
*                                               *
*   At entry:                                   *
*       a2.l =  TX buffer-record base addr      *
*       a3.l =  card base address               *
*       a4.l =  pointer to sc_subtabletype      *
*                                               *
*   Upon exit:                                  *
*       d0.l = 0 if unsuccessful;               *
*              1 if successful.                 *
*                                               *
*   This bashes d0,d1,d2,d3,d4,d5,a0 & a1       *
*                                               *
*************************************************

try_sending_EOF equ *
	moveq   #4,d1
	clr.l   d0
	move.b  TXENDBLOCKSPACE-TXBUFF(a2),d0
	beq.s   sE3                     ; If it's zero jump down & wait for 4
	move.l  d0,d1                   ; bytes in the control queue
sE1     bsr     find_DATA_AREA          ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = TXDATABUFF_SIZE
sE1loop bsr     dir
	bsr     TXDATABUFFroom          ; Now hang until enough space becomes
	cmp.l   d1,d3                   ; available in the data queue
	bge.s   sE2
	bsr     eir
noroom  clr.l   d0
	rts

sE2     moveq   #8,d1                   ; if TXENDBLOCKSPACE#0 then wait for
*                                       ; 8 bytes, not 4.
sE3     bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TXCTRLBUFF_SIZE
sE3loop bsr     dir
	bsr     TXCTRLBUFFroom          ; Now hang until enough space becomes
	cmp.l   d1,d3                   ; available in the ctrl queue
	bge.s   sE4
	bsr     eir
	bra.s   noroom

sE4     tst.b   TXENDBLOCKSPACE-TXBUFF(a2)  ; There's enough room now!! If zero
	beq.s   sE6                         ; then just send 1 block below
	move.w  #$0501,term_and_mode(a4)
	bsr     putctrlblk
	clr.l   data_number(a4)             ; Followed by some space
	move.b  TXENDBLOCKSPACE-TXBUFF(a2),data_number+3(a4)
	move.l  #$FFFF0000,data_address(a4) ; kluge so it isn't left pointing
*                                           to nowhere & get bus error!
sE5     bsr     putchars
	tst.l   data_number(a4)             ; Hang until all sent
	bne.s   sE5
sE6     move.w  #$0500,term_and_mode(a4)
	bsr     putctrlblk
	moveq   #1,d0
	rts


	end

@


56.2
log
@
pws2rcs automatic delta on Wed Jan 27 11:57:27 MST 1993
@
text
@d1 2843
@


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@a0 2843
	TTL IOLIB EXTDC - DATA COMM DRIVERS
	PAGE
********************************************************************************
*
*       COPYRIGHT (C) 1985 BY HEWLETT-PACKARD COMPANY
*
********************************************************************************
*
*
*       IOLIB     EXTDC
*
*
********************************************************************************
*
*
*
*       Library - IOLIB
*       Authors - Carl Dierschow / Tim Mikkelsen
*       Phone   - 303-226-3800  ext. 2910
*
*       Purpose - This set of assembly language code is intended to be used as
*                 a PASCAL module for I/O drivers for use by the external I/O
*                 procedures library.
*
*                 This set of assembly language drivers was written
*                 by Carl Dierschow 303-226-3800 ext. 3136.  The code
*                 was taken almost directly from the 9826 BASIC data comm
*                 code.
*
*       Date    - 10/26/81
*       Update  - 05/03/84 BY J Schmidt
*       Release - 7/12/85
*
*
*       Source  - IOLIB:DC.TEXT
*       Object  - IOLIB:DC.CODE
*
*
********************************************************************************
*
*
*       RELEASED
*       VERSION         3.1
*
*
********************************************************************************
	 PAGE
****************************************************************************
*                                                                          *
*                                                                          *
*      BUG FIX HISTORY         - after release 1.0                         *
*                                                                          *
*                                                                          *
*      BUG #   BY  / ON        LOC             DESCRIPTION                 *
*      -----   -----------     --------------  ----------------------      *
*                                                                          *
*      1249    T Mikkelsen     file DC_INTER   tfr count is off by one     *
*              01/08/82        inxex1          byte for overlap tfrs.      *
*                                                                          *
*      SPRyyy  T Mikkelsen     file DC_COMM    missing instruction in the  *
*              06/15/82        alvinit         reset code - not a problem  *
*                                              for current use - but for   *
*                                              future smart card intrfcs.  *
*                                                                          *
*      185     T Mikkelsen     file DC_INTER   eot and user isr's were     *
*              07/30/82        try_hook        not getting a parameter.    *
*                              try_hook_P                                  *
*                              inxdn1                                      *
*                              outxdn1                                     *
*                                                                          *
*      475     T Mikkelsen     no where        Change BSRs into JSRs to    *
*              09/17/82                        allow re-placement of the   *
*                                              modules.  Also in GPIO and  *
*                                              HPIB.  No refs were used    *
*                                              in the data comm modules.   *
*                                                                          *
*      tttt    J Schmidt       gain_access     Timing/exception fixes for  *
*              08/11/83        direct_control  680xx processors.           *
*              05/03/84        direct_command                              *
*                              wait_outxfrdone                             *
*                              output_data                                 *
*                              putctrlblk                                  *
*                              release_access                              *
*                                                                          *
****************************************************************************
	PAGE
*************************************************
*                                               *
*                                               *
*       ****     ***    *****    ***            *
*       *   *   *   *     *     *   *           *
*       *   *   *   *     *     *   *           *
*       *   *   *****     *     *****           *
*       *   *   *   *     *     *   *           *
*       *   *   *   *     *     *   *           *
*       ****    *   *     *     *   *           *
*                                               *
*                                               *
*        ***     ***    *   *   *   *           *
*       *   *   *   *   ** **   ** **           *
*       *       *   *   * * *   * * *           *
*       *       *   *   *   *   *   *           *
*       *       *   *   *   *   *   *           *
*       *   *   *   *   *   *   *   *           *
*        ***     ***    *   *   *   *           *
*                                               *
*                                               *
*************************************************
*
*       dc_doc
*       comdcl
*       dc_decls
*       dc_buff
*       dc_comm
*       dc_inter
*       dc_rxbuf
*       dc_trans
*       dc_txbuf

    sprint
    llen    132
    page
********************************************************************************
*
*
*       The following lines are used to tell the LINKER/LOADER what this module
*       looks like in PASCAL terms.
*
*       Note that it is possible to create assembly modules that are functions.
*       These routines are called through an indirect pointer using the CALL
*       facility which does NOT permit functions.
*
*       This module is called 'EXTDC' ( upper or lower case - doesn't matter )
*       independent of the file name ( by use of the MNAME pseudo-op ).
*
*       All the externally used procedures are called 'EXTDC_@@@@@@@@@@@@@@@@' in
*       this module.  If you are using assembly to access them use the
*       'EXTDC_@@@@@@@@@@@@@@' name.  If you are using Pascal use the '@@@@@@@@@@@@@@'
*       name.
*
********************************************************************************
	MNAME EXTDC
	SRC MODULE EXTDC;
	SRC IMPORT iodeclarations;
	SRC EXPORT
	SRC
	SRC        PROCEDURE alvinit        ( temp : ANYPTR );
	SRC        PROCEDURE alvinisr       ( temp : PISRIB );
	SRC        PROCEDURE enter_data     ( temp : ANYPTR ;  x     : ANYPTR ;
	SRC                                                    VAR c : INTEGER );
	SRC        PROCEDURE output_data    ( temp : ANYPTR ;  x     : ANYPTR ;
	SRC                                                    cnt   : INTEGER );
	SRC        PROCEDURE output_end     ( temp : ANYPTR );
	SRC        PROCEDURE direct_status  ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    VAR x : io_word);
	SRC        PROCEDURE direct_control ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    val   : io_word );
	SRC        PROCEDURE control_bfd    ( temp : ANYPTR ;  reg   : io_word;
	SRC                                                    val   : io_word );
	SRC        PROCEDURE start_tfr_out  ( temp : ANYPTR );
	SRC        PROCEDURE start_tfr_in   ( temp : ANYPTR );
	SRC END; { of extdc }
	PAGE
********************************************************************************
*
*       SYMBOLS FOR EXPORT AS PROCEDURE NAMES
*
********************************************************************************
	DEF EXTDC_EXTDC

	DEF EXTDC_ALVINIT
	DEF EXTDC_ALVINISR
	DEF EXTDC_ENTER_DATA
	DEF EXTDC_OUTPUT_DATA
	DEF EXTDC_OUTPUT_END
	DEF EXTDC_DIRECT_STATUS
	DEF EXTDC_DIRECT_CONTROL
	DEF EXTDC_CONTROL_BFD
	DEF EXTDC_START_TFR_IN
	DEF EXTDC_START_TFR_OUT

********************************************************************************
*
*       SYMBOLS FOR IMPORT - not used currently in data comm
*                            EXCEPT FOR CHECK_TIMER,M68KTYPE   tttt JS 8/11/83
*                            if they are ever used - use a JSR to call them
*
********************************************************************************
* REFA STBSY
* REFA STCLR
* REFA ITXFR
* REFA ABORT_IO
* REFA LOGINT
* REFA GETDMA
* REFA DROPDMA
* REFA TESTDMA
* REFA DMA_STBSY
  REFA CHECK_TIMER                                             tttt JS 8/11/83
  REFA M68KTYPE
*
*       change references to allow long jumps when the I/O      475 TM 9/17/82
*       modules get moved                                       475 TM 9/17/82
* LMODE STBSY
* LMODE STCLR
* LMODE ITXFR
* LMODE ABORT_IO
* LMODE LOGINT
* LMODE GETDMA
* LMODE DROPDMA
* LMODE TESTDMA
* LMODE DMA_STBSY
  LMODE CHECK_TIMER                                            tttt JS 8/11/83
	TTL IOLIB EXTDC - PASCAL ENTRY POINTS
	PAGE
********************************************************************************
*
*         PASCAL DRIVER ENTRY POINTS FOR GPIO CARDS
*
********************************************************************************

*
*         MODULE initialization
*
EXTDC_EXTDC             EQU *
			RTS
*
*         ENTRY POINTS
*
EXTDC_ALVINIT           BRA ALVINIT
EXTDC_ALVINISR          BRA TOP_ISR
EXTDC_ENTER_DATA        BRA ENTER_DATA
EXTDC_OUTPUT_DATA       BRA OUTPUT_DATA
EXTDC_OUTPUT_END        BRA OUTPUT_END
EXTDC_DIRECT_STATUS     BRA DIRECT_STATUS
EXTDC_DIRECT_CONTROL    BRA DIRECT_CONTROL
EXTDC_CONTROL_BFD       BRA CONTROL_BFD
EXTDC_START_TFR_IN      BRA START_TRANSFER_IN
EXTDC_START_TFR_OUT     BRA START_TRANSFER_OUT

    ttl     dc_doc: documentation info
    page
*************************************************
*                                               *
*   The following escapes are possible:         *
*                                               *
*       EOD_SEEN - on ENTER_DATA only,          *
*          signifies termination with control   *
*          block when too few bytes have been   *
*          read.                                *
*                                               *
*       TMO_ERR - on ENTER_DATA if Rx queue     *
*          was empty for too long               *
*               - on OUTPUT_DATA if Tx queue    *
*          goto blocked up for too long         *
*               - on CONTROL_BFD if Tx control  *
*          queue got blocked up for too long    *
*               - on OUTPUT_END if Tx control   *
*          queue got blocked up for too long    *
*                                               *
*                                               *
*       CRD_DWN - on every routine if card      *
*          was totally locked up for more than  *
*          one second.                          *
*                                               *
*   There are no checks for nested I/O.         *
*                                               *
*************************************************








* module: DC_COMM
*************************************************
*                                               *
*   procedure DIRECT_CONTROL (                  *
*               var SCT:  select_code_table;    *
*               REG:      1..127;               *
*               VAL:      0..255  );            *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*************************************************
	nosyms
	page
* module: DC_COMM
*************************************************
*                                               *
*   procedure DIRECT_STATUS (                   *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               var VAL:  word    );            *
*                                               *
*   These registers are intercepted:            *
*       0:  Gives value from RESET_ID           *
*       1:  Returns true if hardware interrupts *
*       2:  Returns 0                           *
*       5:  Returns 2 bits saying state of Rx   *
*           buffer                              *
*       9:  Returns last ENTER TERM             *
*       10: Returns last ENTER MODE             *
*       11: Returns # bytes available in Tx     *
*           queue, or 0 if there's not 3        *
*           control block positions available   *
*                                               *
*   The range of REG is not checked for         *
*   validity.                                   *
*                                               *
*************************************************










* module: DC_TRANS
*************************************************
*                                               *
*   procedure OUTPUT_DATA (                     *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               COUNT:    longword       );     *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*************************************************
	page
* module: DC_INTER
*************************************************
*                                               *
*   procedure START_TRANSFER_IN (               *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*************************************************







* module: DC_INTER
*************************************************
*                                               *
*   procedure START_TRANSFER_OUT (              *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*************************************************
	page
* module: DC_TRANS
*************************************************
*                                               *
*   procedure ENTER_DATA (                      *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               var COUNT:longword       );     *
*                                               *
*  COUNT initially passes the number of bytes   *
*  which the upper level wants to read.  THE    *
*  ROUTINE DOES NOT NECESSARILY READ THIS MANY! *
*  Upon exit COUNT will be reflect the number   *
*  of data bytes entered, whether or not there  *
*  is an escape.                                *
*                                               *
*  escape(EOD): Terminated by reaching a control*
*     block when not enough bytes have been     *
*     entered.  TERM&MODE may be read with      *
*     STATUS 9 and 10.                          *
*                                               *
*************************************************







* module: DC_TRANS
*************************************************
*                                               *
*   procedure OUTPUT_END (                      *
*               var SCT:  select_code_table );  *
*                                               *
*   Equivalent to the BASIC OUTPUT Sc;END.      *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*************************************************
	page
* module: DC_TRANS
*************************************************
*                                               *
*   procedure CONTROL_BFD (                     *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               VAL:      0..255);              *
*                                               *
*   Control register 0 is intercepted and       *
*   if MODE=0 no action is performed, otherwise *
*   the card is reset IMMEDIATELY.              *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*************************************************




*************************************************
*
*   Unresolved problems:
*
*       How is the hardware ISR linked in?
*
*       How are registers saved/restored on int?
*
*       How does the ISR find the select code &
*           select_code_record?
*
*       Should we do busybits?
*
*       How are overlapped transfers implemented?
*
*************************************************
	page
*************************************************
*
*   This code is required to check the validity
*   of a 98628/9 card:
*
*   var DSDP: 0..65535;
*       ATTR: 0..255;
*
*   if binand(readio(SC,1),60)=52 then begin
*       DSDP := readio(SC,16395) * 256
*               + readio(SC,16393);
*       if (DSDP<32768) then begin
*           ATTR := readio(SC,DSDP*2+1);
*           if binand(ATTR,127)=1 then
*               (*>>> CLAIM CARD! <<<*)  ;
*       end;
*   end;
*
*   Remember that the readio operations above
*   can bus error!
*
*************************************************



*************************************************
*
*   One of the arguments to all routines is a
*   structure I call SCT:select_code_table.
*   This is a structure allocated by the higher
*   level Modcal code, the last 34 bytes of
*   which I INITIALIZE AFTER MODCAL HAS
*   INITIALIZED THE FRONT PART.
*
*   THE C_ADR FIELD MUST BE INITIALIZED BEFORE
*   CALLING THIS ROUTINE:
*
*       procedure ALVINIT (
*                   var SCT: select_code_table );
*
*   This routine also resets the card.  This
*   routine should be used at INITIALIZE time
*   but not at RESET (that's CONTROL 0;1).
*
*************************************************
	page
*************************************************
*
*   Equivalences:
*
*       set_serial, clear_serial
*               CONTROL_BFD(REG<=8)
*
*       serial_line - DIRECT_STATUS(REG<=8)
*
*       set_baud_rate
*
*           ID := DIRECT_STATUS(REG<=3);
*           DIRECT_CONTROL(REG<=20,VAL<=speed);
*           if ID=1 then
*               DIRECT_CONTROL(REG<=21,VAL<=speed);
*
*           ('speed' must go through a mapping!)
*
*       set_char_length - CONTROL_BFD(REG<=34)
*
*       set_stop_bits - CONTROL_BFD(REG<=35)
*
*       set_parity - CONTROL_BFD(REG<=36)
*
*       break - DIRECT_CONTROL(REG<=6)
*
*       abort - DIRECT_CONTROL(REG<=125,VAL<=0)
*               this also aborts transfers!
*
*       clear - DIRECT_CONTROL(REG<=101,VAL<=0)
*
*       ioreset - CONTROL_BFD(REG<=0,VAL<=1)
*
*       readchar - ENTER_DATA(COUNT<=1)
*               (ENTER_DATA will terminate on
*               a control block!!!)
*
*       writechar - OUTPUT_DATA(COUNT<=1)
*
*       set_timeout - write to value in
*               select_code_table (units=1ms)
*
*       LEVEL 2 functions - supersets of readchar
*               & writechar
*
*       handshake transfer - ENTER_DATA or
*               OUTPUT_DATA (ENTER_DATA will
*               terminate on a control block!!!)
*
*       outbound transfer_end - OUTPUT_DATA then
*               OUTPUT_END
*
*       inbound transfer_end - ENTER_DATA
*
*       overlapped transfers - set up the transfer
*               control block and then call
*               START_TRANSFER_IN or
*               START_TRANSFER_OUT.
*
*************************************************

    list
    ttl     comdcl: common I/O declarations
    page
    include COMDCL
    list
    ttl     dc_decls: common Data Comm declarations
    page


********************************************************************************
*                        Data Comm card RAM locations                          *
*                      (byte offsets from base address)                        *

RESET_ID        equ     $000000
INT_DMA         equ     $000002
SEMAPHORE       equ     $000004
INT_COND        equ     $004000
COMMAND         equ     $004002
DATA_REG        equ     $004004
PRIMARY_ADDR    equ     $004006
DSDP            equ     $004008
ERROR_CODE      equ     $00400C

************************** Data Structures Descriptor **************************

ATTRIBUTES      equ     $000000
TR_QUEUE_ADDR   equ     $000002
PRIM_0_ADDR     equ     $000006

****************************** Queue ******************************************

TXENDBLOCKSPACE equ     $000000
RXDATABUFF_NUMB equ     $000001
TXBUFF          equ     $000004
RXBUFF          equ     $000024

CTRL_AREA       equ     $000000
DATA_AREA       equ     $000010

****************************** Buffer record **********************************

ADDR            equ     $000000
SIZE            equ     $000004
FILL            equ     $000008
EMPTY           equ     $00000C

****************************** Control block **********************************

POINTER         equ     $000000
TERMFIELD       equ     $000004
MODEFIELD       equ     $000006
CTRLBLKSIZE     equ     $000008

****************************** select_code_table ******************************

ovrlaper        equ AVAIL_OFF+00 .. 1   ; word
usr0mask        equ AVAIL_OFF+02        ; byte
which_RXbuf     equ AVAIL_OFF+03        ; byte
last_enter_term equ AVAIL_OFF+04        ; byte
last_enter_mode equ AVAIL_OFF+05        ; byte
intbits         equ AVAIL_OFF+06        ; 8 bits
* unused                      07
* The following 26 bytes are saved at interrupt
term_and_mode   equ AVAIL_OFF+08 .. 09  ; Encompasses the two below
term            equ AVAIL_OFF+08        ; byte
mode            equ AVAIL_OFF+09        ; byte
data_address    equ AVAIL_OFF+10 .. 13  ; pointer
data_number     equ AVAIL_OFF+14 .. 17  ; integer
outer_tx_count  equ AVAIL_OFF+18 .. 21  ; integer
timeout_counter equ AVAIL_OFF+22 .. 25  ; integer
inner_counter   equ AVAIL_OFF+26 .. 29  ; integer
inner_tx_count  equ AVAIL_OFF+30 .. 33  ; integer
* This is where they are saved:
int_savespace   equ AVAIL_OFF+34 .. 59
SR_image        equ AVAIL_OFF+60 .. 61  ; word
RCR_hook        equ AVAIL_OFF+62 .. 69  ; procedure
err_hook        equ AVAIL_OFF+70 .. 77  ; procedure
trc_hook        equ AVAIL_OFF+78 .. 85  ; procedure
bt6_hook        equ AVAIL_OFF+86 .. 93  ; procedure
bt7_hook        equ AVAIL_OFF+94 .. 101 ; procedure



sctablebytes    equ AVAIL_OFF+102       ; size of the entire table for allocation

error_int       equ 0   ; Bits for interrupt
rx_int          equ 1   ; register
tx_int          equ 2
ON_INTR_int     equ 3
RC_reset_int    equ 4
trace_int       equ 5

********************************************************************************

    list
    ttl     dc_buff: buffer utilities
    page


*       ****    *   *   *****   *****   *****   ****     ***
*       *   *   *   *   *       *       *       *   *   *   *
*       *   *   *   *   *       *       *       *   *   *
*       ****    *   *   *****   *****   *****   ****     ***
*       *   *   *   *   *       *       *       *  *        *
*       *   *   *   *   *       *       *       *   *   *   *
*       ****     ***    *       *       *****   *   *    ***




********************************************************************************
*                                                                              *
*       routine gain_access: gets access to SEMAPHORE on card for buffer       *
*               ===========  utilities.  If access is not gained in a          *
*                            preset time, an escape is performed.              *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon normal exit:                                                      *
*           If escape performed then                                           *
*               Timeout occurred                                               *
*           Otherwise                                                          *
*               Access was gained                                              *
*               SR has been set to disable all but level 7 interrupt.  The     *
*               SR has been pushed on the stack and RELEASE_ACCESS MUST BE     *
*               CALLED AT THE SAME LEVEL ON THE STACK!!!!!                     *
*                                                                              *
*       This bashes d2.l.                                                      *
*                                                                              *
********************************************************************************

gain_access equ *
	move.l  (sp)+,d2                ; Get return address
	trap    #11                     get into supervisor, save SR    scs
* scs   move    sr,-(sp)                ; Push on old SR
	move.l  d2,-(sp)                ; and push on return address
	ori     #$2700,sr               lock out all interrupts         scs
* scs   move.w  4(sp),d2                ; Now get old SR into d2
* scs   and.w   #$F0FF,d2               ; Strip off old int level
* scs   or.w    #$0600,d2               ; Set interrupt level 6
* scs   move    d2,sr                   ; and put into SR
	btst    #timer_present,sysflag2   check if timer present     tttt JS
	beq.s   gatimed                   if so then go use it       tttt JS
	move.l  #157500,d2 [CALIBRATED 1 SEC] ; Initialize counter
galoop  tst.b   SEMAPHORE(a3)           ; Fetch semaphore bit in bit 7 (sign)
	bpl.s   gadone                  ; If bit 7 true then done!
	subq.l  #1,d2                   ; Loop for preset time
	bne.s   galoop

*               Timed out: escape, but first...
gaterr  addq    #4,sp                   pop return addres               scs
	move    (sp)+,sr                restore user mode               scs
* scs   move    4(sp),sr                ; Get old SR back
	bra     lunched                 ; Now escape
*
gatimed tst.b   semaphore(a3)          first do quick test          tttt JS
	bpl.s   gadone                 before timing                tttt JS
	move.b  #1,-(sp)               set up timing record         tttt JS
	move.l  #1000,-(sp)            MS followed by boolean       tttt JS
gatlp1  move.l  #254,d2                quick loop -- 1 ms @@ 16 MHz  tttt JS
gatlp2  tst.b   semaphore(a3)          check semaphore              tttt JS
	bpl.s   gatexit                if ok then get out           tttt JS
	subq.l  #1,d2                  else hang in tight loop      tttt JS
	bne     gatlp2                                              tttt JS
	pea     (sp)                   now check the timer          tttt JS
	jsr     check_timer            parameter is ptr to record   tttt JS
	bpl     gatlp1                 if not timeout do tight loop tttt JS
	addq    #6,sp                  else fix the stack           tttt JS
	bra     gaterr                 and do timeout escape        tttt JS
gatexit addq    #6,sp                  normal exit is here          tttt JS
	rts                                                         tttt JS
	page
********************************************************************************
*                                                                              *
*       routine release_access: releases access to SEMAPHORE on card which     *
*               ==============  was previously gained with gain_access.        *
*                               Read the notes with the above routine to       *
*                               see description of stack funnies.              *
*                               THIS MUST BE CALLED WITH A BSR INSTRUCTION!    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon normal exit:                                                      *
*               no registers are bashed.                                       *
*                                                                              *
********************************************************************************

release_access equ *
	move.b  d0,SEMAPHORE(a3)        ; Store don't-care into semaphore.

	move.w  4(sp),-(sp)             switch SR and return address    scs
	tst.b   m68ktype                is this a 68000?         tttt JS
	bne.s   release_10or12          br if not                tttt JS
	move.l  2(sp),4(sp)                                             scs
	move.w  (sp)+,(sp)                                              scs
	rte                             restore user mode, return       scs
*
release_10or12 equ *
	clr.w   6(sp)           fake vector offset word where SR was tttt JS
	rte                       and do an rte back to user mode    tttt JS

gadone  rts                             ; Now return to the return address.
	page
********************************************************************************
*                                                                              *
*       routine find_TRBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's TRBUFF structure.        *
*                                                                              *
*       routine find_TXBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's TXBUFF structure.        *
*                                                                              *
*       routine find_RXBUF:     Sets up pointer in a2 to point to the record   *
*               ===========     describing the card's RXBUFF structure.        *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon exit:                                                             *
*               a2.l =  buffer record base address (CTRLBUFF_ADDR,             *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF_ADDR, etc).  (shifted, +1+selectcode)         *
*               This bashes a1, d4 and d5.                                     *
*                                                                              *
********************************************************************************

find_TRBUF equ *
	moveq   #0,d5
	movea.l #TR_QUEUE_ADDR,a2
	bra.s   findTR

find_TXBUF equ *
	moveq   #TXBUFF,d5
	bra.s   find

find_RXBUF equ *
	moveq   #RXBUFF,d5
find    movea.l #PRIM_0_ADDR,a2

findTR  clr.l   d4
	movep.w DSDP(a3),d4
	ror.w   #7,d4
	add.l   a3,d4
	movea.l d4,a1                   ; a1 points to Data Struct Descriptor

	clr.l   d4
	adda.l  a2,a1                   ; add offset to which queue table
	movep.w 0(a1),d4
	ror.w   #7,d4
	add.l   a3,d4
	add.l   d5,d4
	movea.l d4,a2                   ; a2 points to buffer record
	rts
	page
********************************************************************************
*                                                                              *
*       routine find_RX_DATA:   Sets up pointers to point to the appropriate   *
*               ============    receive data buffer.  This is to be used after *
*                               the routine find_RXBUF which sets up the       *
*                               pointer (in a2) to the receive control buffer  *
*                               descriptor record structure.                   *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a2.l =  Buffer record base address (CTRLBUFF_ADDR,             *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF0_ADDR, etc).  (shifted, +1+selectcode)        *
*               a4.l =  pointer to select_code_table structure                 *
*                                                                              *
*       Upon exit:                                                             *
*               a1.l =  data area base address (shifted, +1+selectcode)        *
*               d4.l =  address of first byte PAST data area (shifted, +1+sc)  *
*               d5.l =  XXxxxxBUFF_SIZE (unshifted, not adjusted)              *
*                                                                              *
********************************************************************************

find_RX_DATA equ *
	movea.l #DATA_AREA,a1
	clr.l   d5                      ; compute offset for WHICH rx data
	move.b  which_RXbuf(a4),d5      ; buffer we are using
	asl.l   #4,d5
	adda.l  d5,a1

	bra.s   findare                 ; Now go do the rest of it!
	page
********************************************************************************
*                                                                              *
*       routine find_DATA_AREA: Sets up pointers to point to the data buffer.  *
*               ==============  This is to be used in conjunction with the     *
*                               routines find_XXBUF which will set up the      *
*                               pointer (in a2) to the buffer we are using.    *
*                               THIS SHOULD NOT BE USED WITH THE RECEIVE       *
*                               BUFFER!  USE THE PREVIOUS ROUTINE INSTEAD!     *
*                                                                              *
*       routine find_CTRL_AREA: Sets up pointers to point to the ctrl buffer.  *
*               ==============  This is to be used in conjunction with the     *
*                               routines find_XXBUF which will set up the      *
*                               pointer (in a2) to the buffer we are using.    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a2.l =  Data buffer record base address (CTRLBUFF_ADDR,        *
*                       CTRLBUFF_SIZE, CTRLBUFF_FILL, CTRLBUFF_EMPTY,          *
*                       DATABUFF_ADDR, etc).  (shifted, +1+selectcode)         *
*                                                                              *
*       Upon exit:                                                             *
*               a1.l =  data area base address (shifted, +1+selectcode)        *
*               d4.l =  address of first byte PAST data area (shifted, +1+sc)  *
*               d5.l =  XXxxxxBUFF_SIZE (unshifted, not adjusted)              *
*                                                                              *
********************************************************************************

find_DATA_AREA equ *
	movea.l #DATA_AREA,a1
	bra.s   findare

find_CTRL_AREA equ *
	movea.l #CTRL_AREA,a1

findare adda.l  a2,a1                   ; a1 points to data/ctrl part of record
	clr.l   d5
	movep.w SIZE(a1),d5
	ror.w   #8,d5                   ; d5 = SIZE in bytes

	clr.l   d4
	movep.w ADDR(a1),d4
	ror.w   #7,d4
	add.l   a3,d4
	movea.l d4,a1                   ; a1 points to front of buffer area
	add.l   d5,d4
	add.l   d5,d4                   ; d4 points past end of buffer area

	rts

    ttl     dc_comm: command module
    page


*        ***     ***    *   *   *   *    ***    *   *   ****
*       *   *   *   *   ** **   ** **   *   *   **  *   *   *
*       *       *   *   * * *   * * *   *   *   * * *   *   *
*       *       *   *   *   *   *   *   *****   *  **   *   *
*       *       *   *   *   *   *   *   *   *   *   *   *   *
*       *   *   *   *   *   *   *   *   *   *   *   *   *   *
*        ***     ***    *   *   *   *   *   *   *   *   ****





********************************************************************************
*                                                                              *
*   procedure ALVINIT(var SCT: select_code_table)                              *
*                                                                              *
********************************************************************************

alvinit equ     *
	movea.l (sp)+,a0
	movea.l (sp)+,a4
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  #sctablebytes-1-AVAIL_OFF,d2
clrloop clr.b   AVAIL_OFF(a4,d2)
	dbf     d2,clrloop

	move.b  INT_DMA(a3),d0  ; This SR is used to
	andi.w  #$0030,d0       ; set the interrupt level
	addi.w  #$0230,d0       ; equal to that of the
	asl.w   #4,d0           ; card.
	move.w  d0,SR_image(a4)

	CLR.B   WHICH_RXBUF(A4) ;                               ( SPRyyy TM 6/15/82 )

	bsr     chk_err         ; See if card is giving
*                               ; overlapped error
	bsr     do_reset        ; This can escape if card bad

	bra     check_ov_error  ; Escape if any error
	page
********************************************************************************
*                                                                              *
*       routine eir:    Enables interrupts on this card only.                  *
*               ===                                                            *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card's base address ($00xx0001)                        *
*                                                                              *
*       Upon normal exit:                                                      *
*               No registers are changed.                                      *
*                                                                              *
********************************************************************************

eir     equ     *
	move.b  #$80,INT_DMA(a3)                ; Set enable-interrupt bit true
	rts


********************************************************************************
*                                                                              *
*       routine dir:    Disables interrupts on this card only.                 *
*               ===                                                            *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card's base address ($00xx0001)                        *
*                                                                              *
*       Upon normal exit:                                                      *
*               No registers are changed.                                      *
*                                                                              *
********************************************************************************

dir     equ     *
	clr.b   INT_DMA(a3)                     ; Clear enable-interrupt bit
	rts
	page
*************************************************
*                                               *
*   procedure DIRECT_CONTROL (                  *
*               var SCT:  select_code_table;    *
*               REG:      1..127 & 256 & 257;   *
*               VAL:      0..255  );            *
*                                               *
*************************************************

direct_control equ *
	movea.l (sp)+,a0
	move.w  (sp)+,d1        ; VAL
	move.w  (sp)+,d2        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if any error

	move.b  d1,DATA_REG(a3) ; Send VAL
	move.b  d2,COMMAND(a3)  ; then REG
	cmp.b   #125,d2
	bne.s   not125
	bsr     outxfr_done     ; For ctrl 125 (abort)
	bsr     inxfr_done      ; abort transfers
not125  equ   *
*                               (tm) mod - 12/02/81 Tim Mikkelsen
	CMP.W   #256,D2         (tm) CHECK FOR ABORT TFR IN
	BEQ     INXFR_DONE      (tm)
	CMP.W   #257,D2         (tm) CHECK FOR ABORT TFR OUT
	BEQ     OUTXFR_DONE     (tm)

	btst    #timer_present,sysflag2   check if timer present  tttt JS
	beq.s   ctltime                   if so then go use it    tttt JS

	move.l  #181851,d0 [CALIBRATED 1 SEC]   ; Now start counter for timeout
ctloop  tst.b   COMMAND(a3)
	beq.s   ctldun          ; Done when COMMAND=0
	subq.l  #1,d0
	bne.s   ctloop                          ; Otherwise decrement counter
	bra     lunched                         ; & escape

ctldun  bra     check_ov_error

ctltime move.b  #1,-(sp)        set up timer record            tttt JS 8/11/83
	move.l  #1000,-(sp)                                    tttt JS 8/11/83
ctltlop tst.b   command(a3)     see if done                    tttt JS 8/11/83
	beq.s   ctlexit         if so then return              tttt JS 8/11/83
	pea     (sp)            else push pointer to time rec  tttt JS 8/11/83
	jsr     check_timer     and see if timed out yet       tttt JS 8/11/83
	bpl     ctltlop         no -- keep trying              tttt JS 8/11/83
	addq    #6,sp           yes, give one more try         tttt JS 5/3/84
	moveq   #10,d0          using short count              tttt JS 5/3/84
	bra     ctloop          in normal timing loop          tttt JS 5/3/84
ctlexit addq    #6,sp           normal exit -- clean stack     tttt JS 8/11/83
	bra     check_ov_error  and go check errors            tttt JS 8/11/83
	page
*************************************************
*                                               *
*   procedure DIRECT_STATUS (                   *
*               var SCT:  select_code_table;    *
*               REG:      1..127;               *
*               var VAL:  word    );            *
*                                               *
*   These registers are intercepted:            *
*       0:  Gives value from RESET_ID           *
*       1:  Returns true if hardware interrupts *
*       2:  Returns bit 2 = in xfr active;      *
*                   bit 3 = out xfr active      *
*       5:  Returns 2 bits saying state of Rx   *
*           buffer                              *
*       9:  Returns last ENTER TERM             *
*       10: Returns last ENTER MODE             *
*       11: Returns # bytes available in Tx     *
*           queue, or 0 if there's not 3        *
*           control block positions available   *
*                                               *
*************************************************

direct_status equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a1        ; addr(VAL)
	move.w  (sp)+,d0        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if any error

	clr.w   d1              ; d1 will hold result
	move.l  a1,-(sp)

	tst.b   d0
	beq.s   sts0
	cmpi.b  #2,d0           ; Check for intercepted regs
	blt.s   sts1
	beq.s   sts2
	cmpi.b  #5,d0
	beq.s   sts5
	cmpi.b  #9,d0
	beq.s   sts9
	cmpi.b  #10,d0
	beq.s   sts10
	cmpi.b  #11,d0
	beq.s   sts11
	add.b   #128,d0
	move.b  d0,term(a4)     ; Send TERM

	bsr     direct_command
	move.b  mode(a4),d1

gotsts  movea.l (sp)+,a1
	move.w  d1,(a1)                 ; Return value
	bra     check_ov_error

*
*  Special intercepted registers
*

sts0    move.b  RESET_ID(a3),d1
	bra.s   gotsts

sts1    btst    #7,INT_DMA(a3)
	sne     d1
	and.w   #$0001,d1
	bra.s   gotsts

sts2    movea.l BUFI_OFF(a4),a2
	move.l  a2,d0
	beq.s   sts2a
	bset    #2,d1
sts2a   movea.l BUFO_OFF(a4),a2
	move.l  a2,d0
	beq.s   gotsts
	bset    #3,d1
	bra.s   gotsts

sts5    bsr     find_RXBUF
	bsr     dir
	bsr     RX_stuff_avail
	move.w  d0,d1
	bsr     eir
	bra.s   gotsts

sts9    move.b  last_enter_term(a4),d1
	bra.s   gotsts

sts10   move.b  last_enter_mode(a4),d1
	bra.s   gotsts

sts11   bsr     find_TXBUF
	bsr     dir
	bsr     find_CTRL_AREA
	bsr     TXCTRLBUFFroom
	clr.w   d1
	subi.l  #12,d3
	blt.s   gotsts
	bsr     find_DATA_AREA
	bsr     TXDATABUFFroom
	move.w  d3,d1
	bsr     eir
	bra     gotsts
	page
********************************************************************************
*                                                                              *
*       routine put_INTMASK:    Sends the value in usr0mask to the card.       *
*               ===========                                                    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of sc_subtabletype structure                   *
*               sc_subtabletype.usr0mask has value to send to card.            *
*                                                                              *
*       This bashes term and mode in the select code subtable.                 *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

put_INTMASK equ *
	move.b  #121,term(a4)           ; Send the new driver interrupt mask
	move.b  usr0mask(a4),mode(a4)   ; down with control #121
***     bra     direct_command

********************************************************************************
*                                                                              *
*   routine direct_command                                                     *
*           ==============                                                     *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

direct_command equ *
	move.b  mode(a4),DATA_REG(a3)
	move.b  term(a4),COMMAND(a3)    ; Send TERM

	btst    #timer_present,sysflag2   is timer available?  tttt JS 8/11/83
	beq.s   dctime                    if so go use it      tttt JS 8/11/83

	move.l  #181851,d0 [CALIBRATED 1 SEC]   ; Now start counter for timeout
dcloop  tst.b   COMMAND(a3)
	beq.s   dcdone                         ; Done when COMMAND=0
	subq.l  #1,d0
	bne.s   dcloop                         ; Otherwise decrement counter
	bra     lunched                         ; & escape

dcdone  move.b  DATA_REG(a3),mode(a4)
	rts

dctime  move.b  #1,-(sp)                  set up timer record  tttt JS 8/11/83
	move.l  #1000,-(sp)               for 1 sec wait       tttt JS 8/11/83
dctloop tst.b   command(a3)               see if done          tttt JS 8/11/83
	beq.s   dctexit                   if so then return    tttt JS 8/11/83
	pea     (sp)                      check timer          tttt JS 8/11/83
	jsr     check_timer                                    tttt JS 8/11/83
	bpl     dctloop                   if not timeout, br   tttt JS 8/11/83
	addq    #6,sp                     timeout, clean stk   tttt JS 5/3/84
	moveq   #10,d0                    and try once more    tttt JS 5/3/84
	bra     dcloop                    with short count     tttt JS 5/3/84
dctexit addq    #6,sp                     normal exit, cleanup tttt JS 8/11/83
	bra     dcdone                    and return           tttt JS 8/11/83

	page
********************************************************************************
*                                                                              *
*       routine get_INTMASK:    Reads the value of usr0mask from the card.     *
*               ===========                                                    *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of sc_subtabletype structure                   *
*                                                                              *
*       At exit:                                                               *
*               sc_subtabletype.usr0mask has value from the card.              *
*                                                                              *
*       This bashes term and mode in the select code subtable.                 *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************

get_INTMASK equ *
	move.b  #121+128,term(a4)       ; Get the current interrupt mask
	bsr     direct_command
	move.b  mode(a4),usr0mask(a4)   ; from register #121
	rts


********************************************************************************
*                                                                              *
*       do_reset:  resets the card, waits for it to complete powerup and       *
*       ========   then gets INTMASK again.                                    *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
*   This bashes d0.                                                            *
*                                                                              *
********************************************************************************


do_reset equ    *
	bsr     outxfr_done     ; Abort transfers
	bsr     inxfr_done
	bsr     dir                     ; Disable card interrupts to prevent
*                                       ; conflicts
	move.b  #$80,RESET_ID(a3)       ; Send reset ($80) to card
	bsr     gain_access             ; Wait until SEMAPHORE is freed
	bsr     release_access          ; and then give it back
	bsr     get_INTMASK
	bra     eir
	page
********************************************************************************
*                                                                              *
*   routine check_ov_error:  If the 'ovrlaper' location is nonzero then        *
*           ==============   this escapes with that error.                     *
*                                                                              *
*       Uses:   a3.l =  Base address of card ($00xx0001)                       *
*               a4.l =  Address of SCT: select_code_table                      *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
********************************************************************************


check_ov_error equ *
	bsr     dir
	move.l  d0,-(sp)
	clr.l   d0
	move.w  ovrlaper(a4),d0
	clr.w   ovrlaper(a4)
	bsr     eir
	tst.w   d0
	bne.s   escape
	move.l  (sp)+,d0
	rts


****************************** Escapes *****************************************

lunched equ     *
	moveq   #crd_dwn,d0
	bra.s   escape

time_err equ    *
	moveq   #tmo_err,d0

********************************************************************************
*                                                                              *
*       routine escape: performs Pascal "escape" function.  Error exit         *
*               ======  number is to be passed in d0.                          *
*                                                                              *
*       Uses:   a3.l =  Base address of card                                   *
*               a4.l =  Address of SCT: select_code_table                      *
*               a5.l =  Global pointer for escape arguments                    *
*               d0.l =  Escape number                                          *
*                                                                              *
*   This leaves interrupts ENABLED                                             *
*                                                                              *
********************************************************************************

escape  equ     *               ; Escape point for errors
	move.l  d0,IOE_RSLT(a5)
	clr.l   d5              ; Tim's magic escape stuff
	move.b  IO_SC(a4),d5
	move.l  d5,IOE_SC(a5)
	move.w  #IOE_ERROR,ESC_CODE(a5)
	move.b  #$80,INT_DMA(a3) ;Re-enable card interrupts if off
	trap    #10

    ttl     dc_inter: hardware interrupt handler
    page


*       *****   *   *   *****   *****   ****    ****    *   *   ****    *****
*         *     **  *     *     *       *   *   *   *   *   *   *   *     *
*         *     * * *     *     *       *   *   *   *   *   *   *   *     *
*         *     *  **     *     ***     ****    ****    *   *   ****      *
*         *     *   *     *     *       *  *    *  *    *   *   *         *
*         *     *   *     *     *       *   *   *   *   *   *   *         *
*       *****   *   *     *     *****   *   *   *   *    ***    *         *





********************************************************************************
*                                                                              *
*                 DATA COMM CARD TOP LEVEL INTERRUPT SERVICE ROUTINE           *
*                                                                              *
*       This is reached thru the softpoll table for the appropriate            *
*       interrupt level.                                                       *
*                                                                              *
*       This handles a hardware interrupt from the data comm card.  First it   *
*       enquires to find out what interrupt conditions are pending, then it    *
*       calls the appropriate routines to handle the conditions.               *
*                                                                              *
*       At entry:                                                              *
*               a5.l =  pointer to globals area                                *
*                                                                              *
*       During this routine:                                                   *
*               a3.l =  card's base address ($00xx0001)                        *
*               a4.l =  address of sc_subtabletype structure                   *
*                                                                              *
********************************************************************************

top_isr equ     *
	movea.l (sp)+,a0        ; Save return addr
	movea.l (sp)+,a4        ; Get sc_subtabletype
	pea     (a0)            ; Replace ret addr

	movea.l C_ADR(a4),a3    ; Get card base addr

	addq.l  #1,a3           ; Now a3.l = OUR base address of card

**********  TRY SECTION: RECOVER IS AT END OF ISR

	movem.l a3/a4,-(sp)
	move.l  RCVR_BLK(a5),-(sp)
	move.l  a6,-(sp)
	pea     recover_section
	move.l  sp,RCVR_BLK(a5)

**********  END OF 'TRY' keyword

	move.w  term_and_mode(a4),int_savespace(a4)
	movem.l term_and_mode+2(a4),d0-d5
	movem.l d0-d5,int_savespace+2(a4)

	move.b  INT_COND(a3),intbits(a4) ;Get all the interrupt condition bits

*   From now on, each handler routine checks for its particular interrupting
*   condition and then jumps to the next.  This is done primarily for speed.
	page
********************************************************************************
*                                                                              *
*       routine remcont_reset_isr:      Takes care of communicating a          *
*               =================       card's remote-control-reset to the     *
*                                       operating system                       *
*                                                                              *
********************************************************************************

remcont_reset_isr equ *
	btst    #RC_reset_int,intbits(a4) ; Test for bit #4 for this condition
	beq.s   error_isr
	lea     RCR_hook(a4),a1
	bsr     try_hook



********************************************************************************
*                                                                              *
*       routine error_isr:   Handles the communication of an error from the    *
*               =========    interface card back to BASIC, or the hook.        *
*                                                                              *
*       At entry:                                                              *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  address of SCT: select_code_table                      *
*                                                                              *
*       Upon normal exit:                                                      *
*                                                                              *
*       The 'chk_err' routine is used also at powerup time.                    *
*                                                                              *
********************************************************************************

error_isr equ *
	btst    #error_int,intbits(a4)  ; Test for bit #0 for this condition
	beq.s   data_rx_isr

	bsr     chk_err
	bra.s   data_rx_isr

chk_err clr.w   d0
	move.b  ERROR_CODE(a3),d0       ; fetch error number
	beq.s   errdone                 ; ignore ERROR_CODE=0
	clr.b   ERROR_CODE(a3)
	add.w   #300,d0                 ; add offset

	move.w  d0,ovrlaper(a4)
	lea     err_hook(a4),a1
	bsr     try_hook

errdone rts
	page
********************************************************************************
*                                                                              *
*       routine data_rx_isr: Handles moving received data to the user's        *
*               ===========  buffer for an inbound TRANSFER.                   *
*                                                                              *
********************************************************************************

data_rx_isr equ *
	btst    #rx_int,intbits(a4)     ; Test for bit #1 for this condition
	beq.s   data_tx_isr
	bsr     do_inxfr

********************************************************************************
*                                                                              *
*       routine data_tx_isr: Handles moving transmit data from the user's      *
*               ===========  buffer to the card for an outbound TRANSFER.      *
*                                                                              *
********************************************************************************

data_tx_isr equ *
	btst    #tx_int,intbits(a4)     ; Test for bit #2 for this condition
	beq.s   ON_INTR_isr
	bsr     do_outxfr

********************************************************************************
*                                                                              *
*       routine ON_INTR_isr: Handles the communication of an ON INTR trigger   *
*               ===========  from the interface card back to BASIC.            *
*                                                                              *
********************************************************************************

ON_INTR_isr equ *
	btst    #ON_INTR_int,intbits(a4) ; Test for bit #3 for this condition
	beq     trace_isr

	bclr    #ON_INTR_int,usr0mask(a4)
	beq.s   OIisr1          ; If already 0 don't send again
	bsr     put_INTMASK

OIisr1  lea     USER_ISR(a4),a1
	bsr     try_hook_P              (TM)    7/30/82 bug 158

trace_isr equ *
	btst    #trace_int,intbits(a4)  ; Test for bit #5 for this condition
	beq.s   bit_6_isr
	lea     trc_hook(a4),a1
	bsr     try_hook

bit_6_isr equ *
	btst    #6,intbits(a4)          ; Test for bit #6 for this condition
	beq.s   bit_7_isr
	lea     bt6_hook(a4),a1
	bsr     try_hook
	page
bit_7_isr equ *
	btst    #7,intbits(a4)          ; Test for bit #7 for this condition
	beq.s   end_isr
	lea     bt7_hook(a4),a1
	bsr     try_hook


* -------------------------- End of the ISR ------------------------------------

end_isr equ     *

********** RECOVER SECTION FROM 'TRY' ABOVE *****

	move.l  8(sp),RCVR_BLK(a5)
	adda.l  #12,sp
	bra.s   rcvdone

recover_section equ *           ; On escape, flag overlapped error
	movea.l (sp)+,a6        ; to background
	move.l  (sp)+,RCVR_BLK(a5)

* Body of 'RECOVER' block:
	cmpi.w  #IOE_ERROR,ESC_CODE(a5)
	bne.s   rcvdone         ; Throw away non-I/O errors
	move.b  IO_SC(a4),d0
	cmp.b   IOE_SC(a5),d0
	bne.s   rcvdone
	move.w  IOE_RSLT(a5),ovrlaper(a4)
* That was it!

rcvdone movem.l (sp)+,a3/a4
	bsr     eir
	move.w  int_savespace(a4),term_and_mode(a4)
	movem.l int_savespace+2(a4),d0-d5
	movem.l d0-d5,term_and_mode+2(a4)
	rts             ; Return from ISR


try_hook move.l (a1),d0
	beq.s   hook1
	movem.l a3/a4,-(sp)
	movea.l d0,a0
HOOK4   move.l  4(a1),d0                (tm)    12/03/81
	beq.s   hook3                   (tm)    If there is static link - push it
	move.l  d0,-(sp)                (tm)    Roger Ison said this is okay
hook3   jsr     (a0)
hook2   movem.l (sp)+,a3/a4
hook1   rts


try_hook_P move.l (a1),d0               (TM)    7/30/82 bug 158
	beq.s   hook1
	movem.l a3/a4,-(sp)
	movea.l d0,a0
	MOVE.L  8(A1),-(SP)             (TM)    7/30/82 bug 158
	BRA     HOOK4                   (TM)    7/30/82 bug 158
	page
*************************************************
*                                               *
*   routine do_inxfr:  Transfers data in until: *
*               - User buffer filled;           *
*               - Card buffer empty; or         *
*               - Control block reached.        *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

do_inxfr equ    *
	movea.l BUFI_OFF(a4),a2
	beq     inxdone

	move.l  TCNT_OFF(a2),data_number(a4)
	beq     inxdn1
	move.l  TFIL_OFF(a2),data_address(a4)

inxfr1  bsr     find_RXBUF      ; Set up a2.l = buffer descriptor record
*                                                       base address
inxfr4  bsr     RX_stuff_avail  ; See if buffer is empty
	tst.b   d0              ; If so, just sit here & wait
	beq     inxexit

	bsr     ctrlblknext     ; If a control block is next, then
	tst.b   d0
	bne.s   inxfr3

	tst.l   data_number(a4) ; see if chars to transfer
	beq.s   inxdone         ; yes, go do it

	movea.l BUFI_OFF(a4),a1
	move.w  TCHR_OFF(a1),d0 ; Check for term char desired
	bge.s   inxfr5          ; Yes - goto slow section

	bsr     getchars        ; move some data
*                               ; & go back to check for ctrl blk
	bra.s   inxfr1

inxfr5  equ     *       ; SLOW ENTER - search for char
	move.b  d0,-(sp)        ; Save search char
	move.l  data_number(a4),-(sp)
	move.l  #1,data_number(a4)
	bsr     getchars
	move.l  (sp)+,data_number(a4)
	subq.l  #1,data_number(a4)
	move.b  (sp)+,d0        ; Check for term chr
	movea.l data_address(a4),a0
	cmp.b   -1(a0),d0       ; If equal, exit
	beq.s   inxdone
	bra.s   inxfr1

inxfr3  bsr     getctrlblk      ; Get it, and check for the special
	cmpi.b  #255,term(a4)   ; case TERM=255
	bne.s   inxfr2
	move.b  mode(a4),which_RXbuf(a4) ;If so, do the buffer switch
	bra.s   inxfr1          ; And go back for more

inxfr2  move.w  term_and_mode(a4),last_enter_term(a4)
*                               ; Otherwise save the control block & leave
	movea.l BUFI_OFF(a4),a2
	tst.b   TEND_OFF(a2)    ; If EOI term bit set tghen
	beq.s   inxfr1          ; leave else ignore

inxdone movea.l BUFI_OFF(a4),a2
	move.l  data_address(a4),TFIL_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
inxdn1  bsr     inxfr_done
	move.l  a2,d0
	beq.s   inxex1
	lea     T_PR_OFF(a2),a1
	bra     try_hook_P                      (TM)    7/30/82 bug 158

inxexit equ     *
	movea.l BUFI_OFF(a4),a2
	move.l  data_address(a4),TFIL_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
	beq.s   inxdn1                          BUG 1249   TM 01/08/82
inxex1  rts
	page
*************************************************
*                                               *
*   routine do_outxfr:  Transfers data out til: *
*               - User buffer emptied; or       *
*               - Card buffer filled.           *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*   During execution:                           *
*       a2.l =  address of xfr record           *
*                                               *
*************************************************

do_outxfr equ   *
	movea.l BUFO_OFF(a4),a2
	move.l  a2,d0
	beq.s   outxex1

	move.l  TCNT_OFF(a2),data_number(a4)
	beq.s   outxd0
	move.l  TEMP_OFF(a2),data_address(a4)

	bsr     find_TXBUF      ; a2 = buff descr rec addr

outx1   move.l  data_number(a4),-(sp)
	bsr     putchars        ; Send some chars
	move.l  (sp)+,d0
	cmp.l   data_number(a4),d0
	beq.s   outxit          ; If no chars transferred
	tst.l   data_number(a4) ; then exit
	bne.s   outx1           ; Check buffer empty

outxdun movea.l BUFO_OFF(a4),a2
	move.l  data_address(a4),TEMP_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
outxd0  movea.l BUFO_OFF(a4),a2
	tst.b   TEND_OFF(a2)    ; Check for END termination
	beq.s   outxdn1
	bsr     find_TXBUF      ; a2 = buff descr rec addr
	bsr     try_sending_EOF
	tst.b   d0              ; If couldn't send it then
	beq.s   outxex1         ; return, wait for next interrupt

outxdn1 bsr     outxfr_done
	move.l  a2,d0
	beq.s   outxex1
	lea     T_PR_OFF(a2),a1
	bra     try_hook_P                   (TM)    7/30/82 bug 158

outxit  movea.l BUFO_OFF(a4),a2
	move.l  data_address(a4),TEMP_OFF(a2)
	move.l  data_number(a4),TCNT_OFF(a2)
outxex1 rts
	page
*************************************************
*                                               *
*   routine outxfr_done:  Terminates the        *
*               outbound transfer, if any.      *
*                                               *
*   routine inxfr_done:  Terminates the inbound *
*               transfer, if any.               *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

outxfr_done equ *
	bclr    #tx_int,usr0mask(a4)
	beq.s   outxd1          ; If already 0 don't send again
	bsr     put_INTMASK
outxd1  lea     BUFO_OFF(a4),a0
	bra.s   xfrdun


inxfr_done equ *
	bclr    #rx_int,usr0mask(a4)
	beq.s   inxd1           ; If already 0 don't send again
	bsr     put_INTMASK
inxd1   lea     BUFI_OFF(a4),a0

xfrdun  movea.l (a0),a2
	move.l  a2,d0
	beq.s   rtsin
	move.b  #255,T_SC_OFF(a2)
	clr.b   TACT_OFF(a2)
	clr.l   (a0)
rtsin   rts
	page
*************************************************
*                                               *
*   routine wait_outxfrdone: waits until an     *
*               outbound transfer is complete   *
*               (if any).  Also has timeout     *
*               escape.                         *
*                                               *
*   routine wait_inxfrdone: waits until an      *
*               inbound transfer is complete    *
*               (if any).  Also has timeout     *
*               escape.                         *
*                                               *
*   At entry:                                   *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*   This bashes nothing.                        *
*                                               *
*   This routine may escape!                    *
*                                               *
*   MODIFIED by Tim Mikkelsen 12/02/81          *
*            from 12/01/81 code to 11/23/81     *
*                                               *
*************************************************

wait_outxfrdone equ *
	movem.l d0/d2/a0,-(sp)
	movea.l BUFO_OFF(a4),a0
	bra.s   wait

wait_inxfrdone equ *
	movem.l d0/d2/a0,-(sp)
	movea.l BUFO_OFF(a4),a0

wait    move.l  a0,d2           ; 0=no xfr block
	beq.s   waitdun
	cmpi.b  #5,TUSR_OFF(A0) ; >4 = interrupt
	blt.s   waitdun
	move.l  timeout(a4),d2
	btst    #timer_present,sysflag2   is timer available ? tttt JS 8/11/83
	beq.s   wait_timer                if so then use it    tttt JS 8/11/83

wait1   move.l  #256,d0         [UNCALIBRATED] - guess based upon check_tfr loop
wait2   tst.b   TACT_OFF(a0)    ; 0=inactive            (tm)  tst.l -> tst.b
	beq.s   waitdun

	subq.l  #1,d0           ; Timeout computation
	bne.s   wait2
	tst.l   d2
	beq.s   wait1
	subq.l  #1,d2        bug fix -- was d0                 tttt JS 8/11/83
	bne.s   wait1
	bra     time_err

waitdun movem.l (sp)+,d0/d2/a0
	rts

wait_timer equ *
	tst.l   d2             check for infinite timeout    tttt JS 8/11/83
	beq     wait1          use loops if infinite         tttt JS 8/11/83
	move.b  #1,-(sp)          set up timer record        tttt JS 8/11/83
	move.l  d2,-(sp)          d2 has ms to wait          tttt JS 8/11/83
wait3   tst.b   tact_off(a0)      xfr done?                  tttt JS 8/11/83
	beq.s   wait4             if so then exit loop       tttt JS 8/11/83
	pea     (sp)              push ptr to time rec       tttt JS 8/11/83
	jsr     check_timer       and check the timer        tttt JS 8/11/83
	bpl     wait3             if no timeout, keep trying tttt JS 8/11/83
	bra     time_err          timeout -- go escape       tttt JS 8/11/83
wait4   addq    #6,sp             normal exit -- clean stack tttt JS 8/11/83
	bra     waitdun           and return                 tttt JS 8/11/83

	page
*************************************************
*                                               *
*   procedure START_TRANSFER_IN (               *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*   During use:                                 *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

START_TRANSFER_IN equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	trap    #11             get into supervisor mode                scs
* scs   move    sr,-(sp)        ; Funny code to disable
	move    SR_image(a4),sr ; interrupts
	bset    #rx_int,usr0mask(a4)
	bsr     put_INTMASK
	bsr     do_inxfr
	move    (sp)+,sr
	bra     check_ov_error  ; Will enable ints
	page
*************************************************
*                                               *
*   procedure START_TRANSFER_OUT (              *
*               var SCT: select_code_table );   *
*                                               *
*       This starts the card doing a transfer.  *
*       The calling code must have already      *
*       linked the transfer block in to the     *
*       select_code_table structure.            *
*                                               *
*   During use:                                 *
*       a3.l =  card base address ($00xx0001)   *
*       a4.l =  address of select_code_table    *
*                                               *
*************************************************

START_TRANSFER_OUT equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	trap    #11                                                     scs
* scs   move    sr,-(sp)        ; Funny code to disable
	move    SR_image(a4),sr ; interrupts
	bset    #tx_int,usr0mask(a4)
	bsr     put_INTMASK
	bsr     do_outxfr
	move    (sp)+,sr
	bra     check_ov_error  ; Will enable ints

    ttl     dc_rxbuf: Rx buffer utilities
    page


*       ****    *   *   ****    *   *   *****   *****   *****   ****
*       *   *   *   *   *   *   *   *   *       *       *       *   *
*       *   *    * *    *   *   *   *   *       *       *       *   *
*       ****      *     ****    *   *   *****   *****   *****   ****
*       *  *     * *    *   *   *   *   *       *       *       *  *
*       *   *   *   *   *   *   *   *   *       *       *       *   *
*       *   *   *   *   ****     ***    *       *       *****   *   *





********************************************************************************
*                                                                              *
*       routine set_RXBUF_a6:   Routine to set a6 as the base address          *
*               ============    pointer to whichever Rx buffer is being used.  *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  data buffer base address (shifted, +1+selectcode)      *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               a6.l =  Base address of DATA_BUFFERS[WHICH_RXBUF]              *
*               This also bashes d0.                                           *
*                                                                              *
********************************************************************************

set_RXBUF_a6 equ *
	clr.l   d0                      ; Setup d0.l=offset
	move.b  which_RXbuf(a4),d0      ; to which Rx buffer
	asl.l   #4,d0                   ; being used
	lea     DATA_AREA(a2,d0),a6
	rts
	page
********************************************************************************
*                                                                              *
*       routine RX_BUFF_bytes:  Function which returns the number of           *
*               =============   characters until the first control block in    *
*                               the Receive Buffer.  If there are no control   *
*                               blocks, this just returns the number of        *
*                               characters in the buffer.  This only works     *
*                               on the current Rx data buffer, and does not    *
*                               extract TERM=255 control blocks!               *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  data buffer base address (shifted, +1+selectcode)      *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  Number of characters.                                  *
*               a1, d4 and d5 are left with values from find_RX_DATA.          *
*               This also bashes a0, d1 and d2.                                *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and find_RX_DATA.      *
*                                                                              *
********************************************************************************

RX_BUFF_bytes equ *
	bsr     find_RX_DATA            ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  a6,-(sp)
	bsr     set_RXBUF_a6

	clr.l   d0                      ; Get garbage out of top of d0, d1
	clr.l   d1
	movep.w CTRL_AREA+EMPTY(a2),d1  ; Fetch pointers (bytes in wrong order)
	bsr     gain_access             ; Need access to FILL pointers
	movep.w FILL(a6),d0
	movep.w CTRL_AREA+FILL(a2),d2
	bsr     release_access
	cmp.w   d2,d1                   ; If the two ctrl block pointers are not
	beq.s   RBb1                    ; equal, then we want to use the pointer
	ror.w   #7,d1                   ; field from the next control block to
	add.l   a3,d1                   ; indicate how much data may be removed
	movea.l d1,a0
	movep.w POINTER(a0),d0          ; --- Use it as the "FILL" pointer

RBb1    ror.w   #8,d0                   ; Switch bytes for FILL
	movep.w EMPTY(a6),d1            ; and get EMPTY and switch bytes
	ror.w   #8,d1                   ; d0="FILL", d1=EMPTY

	sub.w   d1,d0                   ; Compute d0 := FILL-EMPTY
	bge.s   RBb2
	add.w   d5,d0                   ; If negative, add data buffer size
RBb2    movea.l (sp)+,a6
	rts     ; Now d0 = ("FILL"-EMPTY) mod SIZE --- of data buffer
	page
********************************************************************************
*                                                                              *
*       routine getctrlblk:     Routine which gets a control block from the    *
*               ==========      Receive buffer.  It must have already been     *
*                               determined that there is a control block at    *
*                               the front of the buffer, since this routine    *
*                               does NOT check for that condition.  The TERM   *
*                               and MODE fields of the removed block are left  *
*                               in the appropriate (.term and .mode) in the    *
*                               sc_subtabletype structure.                     *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               sc_subtabletype.term =  TERM field of control block (8 bits)   *
*               sc_subtabletype.mode =  MODE field of control block (8 bits)   *
*               a1, d4 and d5 are left with the values from find_CTRL_AREA.    *
*               This bashes d0, d2, and a0.                                    *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and find_CTRL_AREA.    *
*                                                                              *
********************************************************************************

getctrlblk equ  *
	bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TRCTRLBUFF_SIZE

	clr.l   d0                      ; Clear top of d0
	movep.w CTRL_AREA+EMPTY(a2),d0  ; Get control buffer EMPTY pointer
	ror.w   #7,d0                   ; Now make it into a 68000 pointer
	add.l   a3,d0
	movea.l d0,a0                   ; Move to a0 so we can use it

	move.b  TERMFIELD(a0),term(a4)  ; Store term & mode fields
	move.b  MODEFIELD(a0),mode(a4)

	add.w   #CTRLBLKSIZE,d0         ; Bump pointer by control block size
	cmp.w   d0,d4                   ; and check for wraparound.
	bne.s   gcb1
	move.w  a1,d0                   ; If so, set to front of buffer
gcb1    bclr    #0,d0                   ; Make it into a Z80
	rol.w   #7,d0                   ; type pointer with bytes reversed
	bsr     gain_access             ; Now store the updated EMPTY pointer
	movep.w d0,CTRL_AREA+EMPTY(a2)
	bsr     release_access
	rts     ;<<<CAN'T COMBINE WITH ABOVE!!!!!
	page
********************************************************************************
*                                                                              *
*       routine getchars:       Routine which takes characters from the        *
*               ========        Receive buffer and puts them in the area       *
*                               pointed to by sc_subtabletype.data_address     *
*                               and sized by sc_subtabletype.data_number.      *
*                               The number of characters                       *
*                               actually transfered is the minimum of:         *
*                               (1) the number of characters available before  *
*                               the first Receive buffer control block;        *
*                               (2) sc_subtabletype.data_number;               *
*                               and (3) the number of characters               *
*                               available until the Receive buffer wraparound  *
*                               point.  THIS NUMBER MAY BE ZERO!               *
*                               This alters data_address and data_number to    *
*                               reflect where to start going next time this    *
*                               is called.  The criteria for ending the        *
*                               transfer at a higher level must be determined  *
*                               by data_number, RX_stuff_avail and             *
*                               ctrl_blk_next/getctrlblk.                      *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               data_address and data_number are updated, plus the EMPTY       *
*               pointer in the card's Receive data buffer.                     *
*               In sc_subtabletype last_enter_term and last_enter_mode are     *
*               zeroed if any data is moved.                                   *
*               a1 and d4 are left with the values from find_RX_DATA.          *
*               This bashes d0, d1, d2, d3, d4, d5, a0, and a1.                *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, and RX_BUFF_bytes.     *
*                                                                              *
********************************************************************************

getchars equ    *
	bsr     RX_BUFF_bytes           ; Setup a1 = data buffer base addr
*                                               d3 = offset to which Rxbuff used
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  d0,d3                   ; d3.l = available characters

	movem.l a2/a6,-(sp)             ; Saved for local use
	bsr     set_RXBUF_a6

	clr.l   d0
	movep.w EMPTY(a6),d0            ; Get RXDATABUFF_EMPTY and make
	ror.w   #7,d0                   ; it into a 68000 pointer
	add.l   a3,d0
	movea.l d0,a2                   ; Save EMPTY for later!

	sub.l   d4,d0
	neg.l   d0                      ; d0 = wraparound address - EMPTY
	and.l   #$0000FFFE,d0
	ror.w   #1,d0                   ; d0.l = number of bytes till wraparound

	cmp.l   d0,d3                   ; If d0>d3 then set d0 := d3
	bgt.s   gc1
	move.l  d3,d0

gc1     move.l  data_number(a4),d2      ; Fetch number of positions available
	cmp.l   d0,d2                   ; If d0>d2 then set d0 := d2
	bgt.s   gc2
	move.l  d2,d0

gc2     move.l  d0,d3                   ; d3.l saves number of chars actually
*                                       ; transferred below
	beq.s   gcdone                  ; If zero, no work to be done
	clr.w   last_enter_term(a4)     ; This also clears last_enter_mode.
	subq.w  #1,d0                   ; Make offset correct for dbf instr.
	movea.l data_address(a4),a0     ; Get character pointer into a0

gcloop  move.b  (a2),(a0)+              ; Transfer a character & bump dest ptr
	addq.w  #2,a2                   ; Bump source pointer (odd bytes)
	dbf     d0,gcloop               ; Then decrement d0 & loop

	sub.l   d3,d2                   ; Decrement datacnt by # bytes
	move.l  d2,data_number(a4)      ; Now store adjusted address and
	move.l  a0,data_address(a4)     ; number fields

	move.l  a2,d1                   ; Store pointer for computations
	cmp.l   a2,d4                   ; Now check to see if EMPTY was moved
	bne.s   gc3                     ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
gc3     bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,EMPTY(a6)            ; Remember d1 = card's EMPTY pointer.
	bsr     release_access
gcdone  movem.l (sp)+,a6/a2
	rts
	page
********************************************************************************
*                                                                              *
*       routine RX_stuff_avail: Routine which determines whether there is      *
*               ==============  ANYTHING (data or control blocks) in the       *
*                               Receive buffer.  This consumes any TERM=255    *
*                               control blocks before returning the function.  *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  $00 if buffer is empty,                                *
*                       $01 if ctrl buffer is empty and data buffer is not,    *
*                       $02 if data buffer is empty and ctrl buffer is not,    *
*                       $03 if both data and ctrl buffers are not empty.       *
*               a1 and d4 are left with the values from find_RX_DATA.          *
*               This bashes d0, d1, d2, d3, d4, d5, a0 and a1.                 *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access and release_access.                     *
*                                                                              *
********************************************************************************

RX_stuff_avail equ *
	bsr     find_RX_DATA            ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = RXDATABUFF_SIZE
	move.l  a6,-(sp)
	bsr     set_RXBUF_a6

	bsr     gain_access
	movep.w FILL(a6),d3             ; Fetch FILL & EMPTY (bytes reversed but
	movep.w CTRL_AREA+FILL(a2),d1
	bsr     release_access          ; we're just checking equality)
	clr.l   d2
	clr.l   d0
	movep.w CTRL_AREA+EMPTY(a2),d2
	cmp.w   d1,d2                   ; Compare ctrl buff FILL & EMPTY
	bne.s   setbit1                 ; If not equal, then set bit 1
chkdata movep.w EMPTY(a6),d2
	cmp.w   d3,d2                   ; Compare data buff FILL & EMPTY
	beq.s   return
	addq.b  #1,d0                   ; And set bit 0 if not equal
return  movea.l (sp)+,a6
	rts

setbit1 addq.b  #2,d0                   ; Set "ctrl not empty" bit
	ror.w   #7,d2                   ; Something in control buffer - see if
*                                       ; this control block is at the head of
	add.l   a3,d2                   ; the queue (bytes reversed!)
	movea.l d2,a0
	movep.w POINTER(a0),d1
	movep.w EMPTY(a6),d2
	cmp.w   d2,d1                   ; if POINTER field<>DATABUFF_EMPTY
	bne.s   chkdata                 ;   then go check data buff
	cmpi.b  #255,TERMFIELD(a0)      ; else if it's a TERM=255 control block
	bne.s   chkdata                 ; No, go back and check data buff

	bsr     getctrlblk              ; Otherwise consume the control block
	move.b  mode(a4),which_RXbuf(a4) ;and switch to new data buffer
	movea.l (sp)+,a6
	bra.s   RX_stuff_avail          ; And go back and re-compute result
	page
********************************************************************************
*                                                                              *
*       routine ctrlblknext:    Routine which determines whether the next      *
*               ===========     thing to be consumed from the Receive buffer   *
*                               is a control block.  THE RESULT OF THIS        *
*                               FUNCTION IS NOT VALID UNLESS RX_BUFFER_empty   *
*                               RETURNS FALSE!!!                               *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  RX buffer record base address from find_RXBUF          *
*               a3.l =  card base address ($00xx0001)                          *
*                                                                              *
*       Upon exit:                                                             *
*               d0.b =  $FF if control block is next, $00 if data is next.     *
*               This bashes d2, d5 and a0.                                     *
*                                                                              *
********************************************************************************

ctrlblknext equ *
	bsr     gain_access
	movep.w CTRL_AREA+FILL(a2),d2   ; Check if ctrl buffer is empty
	bsr     release_access
	clr.l   d0
	movep.w CTRL_AREA+EMPTY(a2),d0  ; Fetch ctrl buffer EMPTY pointer
	cmp.w   d0,d2                   ; If equal then return d0.b=$00
	beq.s   cbn1
	ror.w   #7,d0
	add.l   a3,d0
	movea.l d0,a0
	movep.w POINTER(a0),d0          ; Fetch the POINTER field from the

	clr.l   d5                      ; Setup d5.l=offset
	move.b  which_RXbuf(a4),d5      ; to which Rx buffer
	asl.l   #4,d5                   ; being used

	movem.l d0/a6,-(sp)
	bsr     set_RXBUF_a6
	movep.w EMPTY(a6),d2            ; first ctrl block and compare to the
	movem.l (sp)+,d0/a6

	cmp.w   d0,d2                   ; data buffer EMPTY pointer
	seq     d0                      ; Then set d0 if equal
	rts

cbn1    clr.l   d0
	rts

    ttl     dc_trans: Handshake transfer code
    page


*       *****   ****     ***    *   *    ***    *****   *****   ****
*         *     *   *   *   *   **  *   *   *   *       *       *   *
*         *     *   *   *   *   * * *   *       *       *       *   *
*         *     ****    *****   *  **    ***    ***     ***     ****
*         *     *  *    *   *   *   *       *   *       *       *  *
*         *     *   *   *   *   *   *   *   *   *       *       *   *
*         *     *   *   *   *   *   *    ***    *       *****   *   *




in_timeout      equ     6  [UNCALIBRATED 1 MS]
out_timeout     equ     7  [UNCALIBRATED 1 MS]


*************************************************
*                                               *
*   procedure OUTPUT_DATA (                     *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               COUNT:    longword       );     *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   This routine calls find_TXBUF and putchars. *
*                                               *
*************************************************

output_data equ *
	movea.l (sp)+,a0
	move.l  (sp)+,d1        ; COUNT
	movea.l (sp)+,a1        ; PTR
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  a1,data_address(a4)     ; initialize address/count
	move.l  d1,data_number(a4)

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_outxfrdone

	move.l  timeout(a4),timeout_counter(a4)
	move.l  #out_timeout,inner_counter(a4)

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	beq.s   outdone

	btst    #timer_present,sysflag2   check for timer      tttt JS 8/11/83
	beq.s   outtimer                  if got it, use it    tttt JS 8/11/83

out_2   tst.l   data_number(a4)         ; And transfer characters until done
	beq.s   outdone
	bsr     putchars
	subq.l  #1,inner_counter(a4)    ; Test for timeout condition
	bne.s   out_2
	move.l  #out_timeout,inner_counter(a4)
	tst.l   timeout_counter(a4)
	beq.s   out_2
	subq.l  #1,timeout_counter(a4)
	beq     time_err                ; if so, escape
	bra.s   out_2

outdone rts
*
outtimer tst.l  timeout(a4)           see if infinit timeout  tttt JS 8/11/83
	beq     out_2                 if so don't use this    tttt JS 8/11/83
	move.b  #1,-(sp)             else setup timer record  tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                             tttt JS 8/11/83
outtloop tst.l  data_number(a4)      check if all done        tttt JS 8/11/83
	beq.s   outtexit             if so then get out       tttt JS 8/11/83
	bsr     putchars             else send chars          tttt JS 8/11/83
	pea     (sp)                 push ptr to time rec     tttt JS 8/11/83
	jsr     check_timer          and check the timer      tttt JS 8/11/83
	bpl     outtloop             if not timeout keep going tttt JS 8/11/83
	bra     time_err             else do timeout escape   tttt JS 8/11/83
outtexit addq   #6,sp                normal exit -- cleanup   tttt JS 8/11/83
	rts                          and return               tttt JS 8/11/83

	page
*************************************************
*                                               *
*   procedure ENTER_DATA (                      *
*               var SCT:  select_code_table;    *
*               PTR:      ^ data_bytes;         *
*               var COUNT:longword       );     *
*                                               *
*  COUNT initially passes the number of bytes   *
*  which the upper level wants to read.  THE    *
*  ROUTINE DOES NOT NECESSARILY READ THIS MANY! *
*  Upon exit COUNT will be reflect the number   *
*  of data bytes entered, whether or not there  *
*  is an escape.                                *
*                                               *
*  escape(EOD): Terminated by reaching a control*
*     block.  TERM&MODE may be read with STATUS *
*     9 and 10.                                 *
*                                               *
*       This routine calls find_RXBUF,          *
*       getctrlblk, getchars, ctrlblknext, and  *
*       RX_BUFFER_EMPTY.                        *
*                                               *
*************************************************

enter_data equ  *
	movea.l (sp)+,a0
	movea.l (sp)+,a2        ; addr(COUNT)
	movea.l (sp)+,a1        ; PTR
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	move.l  a1,data_address(a4)     ; initialize address

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_inxfrdone

	move.l  timeout(a4),timeout_counter(a4)
	move.l  #in_timeout,inner_counter(a4)

	move.l  (a2),data_number(a4)
	move.l  a2,-(sp)

	btst    #timer_present,sysflag2   is timer present?  tttt JS 8/11/83
	bne.s   in_1                     if not, continue    tttt JS 8/11/83
	move.b  #1,-(sp)              else stack time rec    tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                            tttt JS 8/11/83

	bra.s   in_1

in_0    bsr     eir
	tst.l   data_number(a4)         ; See if all characters transferred
	beq.s   in_exit                 ; If so, leave

in_1    bsr     find_RXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	btst    #timer_present,sysflag2  using timer?         tttt JS 8/11/83
	bne.s   in_1b                    if not then skip     tttt JS 8/11/83
	tst.l   timeout(a4)              infinite timeout?    tttt JS 8/11/83
	beq.s   in_4                     then skip checking   tttt JS 8/11/83
	pea     (sp)                   push ptr to time re    tttt JS 8/11/83
	jsr     check_timer            and check timer        tttt JS 8/11/83
	bpl.s   in_4            if not timeout, keep trying   tttt JS 8/11/83
	addq    #6,sp           else clean stack              tttt JS 8/11/83
	bra.s   in_1c           and do timeout stuff          tttt JS 8/11/83

in_1b   subq.l  #1,inner_counter(a4)    ; Test for timeout condition
	bne.s   in_4
	move.l  #in_timeout,inner_counter(a4)
	tst.l   timeout_counter(a4)
	beq.s   in_4
	subq.l  #1,timeout_counter(a4)
	bne.s   in_4
in_1c   movea.l (sp)+,a0
	move.l  (a0),d0
	sub.l   data_number(a4),d0
	move.l  d0,(a0)
	bra     time_err

in_4    bsr     dir
	bsr     RX_stuff_avail          ; See if buffer is empty
	tst.b   d0                      ; If so, just sit here & wait
	beq.s   in_0

	bsr     ctrlblknext             ; If a control block is next, then
	tst.b   d0
	beq.s   in_3

	bsr     getctrlblk              ; Get it, and check for the special
	cmpi.b  #255,term(a4)           ; case TERM=255
	bne.s   in_2
	move.b  mode(a4),which_RXbuf(a4) ;If so, do the buffer switch
	bra.s   in_1                    ; And go back for more

in_2    move.w  term_and_mode(a4),last_enter_term(a4)
*                                       ; Otherwise save the control block & leave
in_exit btst    #timer_present,sysflag2  using timer?        tttt JS 8/11/83
	bne.s   in_ex2                   no -- skip ahead    tttt JS 8/11/83
	addq.l  #6,sp                    else clean stack    tttt JS 8/11/83
in_ex2  bsr     eir
	movea.l (sp)+,a0
	move.l  (a0),d0
	sub.l   data_number(a4),d0
	move.l  d0,(a0)
	tst.l   data_number(a4)
	beq     outdone                 ; If nonzero then early EOI; escape
	moveq   #EOD_SEEN,d0
	bra     escape

in_3    tst.l   data_number(a4)         ; see if chars to transfer
	beq.s   in_exit                 ; yes, go do it

	bsr     getchars                ; move some data
	bra     in_0                    ; & go back to check for ctrl blk
	page
*************************************************
*                                               *
*   procedure OUTPUT_END (                      *
*               var SCT:  select_code_table );  *
*                                               *
*   Equivalent to the BASIC OUTPUT Sc;END.      *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   This routine calls find_TXBUF and           *
*   try_sending_EOF.                            *
*                                               *
*************************************************

output_end equ *
	movea.l (sp)+,a0
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error          ; Escape if o/v error
	bsr     wait_outxfrdone

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
*                                                       base address
	move.l  timeout(a4),outer_tx_count(a4)
	move.l  #sEtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)             infinite loop? tttt JS 5/3/84
	beq.s   trysend                     yes, normal loop  tttt JS 5/3/84
	btst    #timer_present,sysflag2        timer avail?   tttt JS 5/3/84
	beq.s   try_timer                      if so, use it  tttt JS 5/3/84

trysend bsr     try_sending_EOF
	tst.b   d0
	bne.s   sentEOF

	subq.l  #1,inner_tx_count(a4)
	bne.s   trysend
	move.l  #sEtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)
	beq.s   trysend
	subq.l  #1,outer_tx_count(a4)
	bne.s   trysend
	bra     time_err

sentEOF rts

try_timer move.b #1,-(sp)                  setup timer record  tttt JS 5/3/84
	move.l  timeout(a4),-(sp)                              tttt JS 5/3/84
try_timer2 bsr     try_sending_EOF                             tttt JS 5/3/84
	tst.b   d0                         successful?         tttt JS 5/3/84
	bne.s   try_timer3                 yes, get out        tttt JS 5/3/84
	pea     (sp)                     point to timer rec    tttt JS 5/3/84
	jsr     check_timer              and check timer       tttt JS 5/3/84
	bpl     try_timer2               if no timeout, loop   tttt JS 5/3/84
	addq    #6,sp                    timeout, one more try tttt JS 5/3/84
	move.l  #1,outer_tx_count(a4)    with short count      tttt JS 5/3/84
	bra     trysend                                        tttt JS 5/3/84
try_timer3 addq   #6,sp                  clean stack           tttt JS 5/3/84
	rts                              and return            tttt JS 5/3/84

	page
*************************************************
*                                               *
*   procedure CONTROL_BFD (                     *
*               var SCT:  select_code_table;    *
*               REG:      0..127;               *
*               VAL:      0..255);              *
*                                               *
*   Control register 0 is intercepted and       *
*   if MODE=0 no action is performed, otherwise *
*   the card is reset IMMEDIATELY.              *
*                                               *
*   This operation may hang waiting for space.  *
*                                               *
*   The ranges of REG & VAL are not checked     *
*   for validity.                               *
*                                               *
*   This routine calls find_TXBUF and putctrlblk*
*                                               *
*************************************************

control_bfd equ *
	movea.l (sp)+,a0
	move.w  (sp)+,d1        ; VAL
	move.w  (sp)+,d2        ; REG
	movea.l (sp)+,a4        ; SCT
	pea     (a0)
	movea.l c_adr(a4),a3
	addq.l  #1,a3

	bsr     check_ov_error  ; Escape if o/v error
*                               (tm) moved by Tim Mikkelsen 12/02/81
	move.b  d2,term(a4)     (tm) ; Intercept CONTROL 0
	beq.s   ctrl0           (tm)

	bsr     wait_outxfrdone

	move.b  d1,mode(a4)

	bsr     find_TXBUF              ; Set up a2.l = buffer descriptor record
	bra     putctrlblk              ;               base address

ctrl0   tst.b   d1
	beq.s   ctrldun
	bsr     wait_inxfrdone
	bra     do_reset
ctrldun rts

    ttl     dc_txbuf: Tx buffer utilities
    page


*       *****   *   *   ****    *   *   *****   *****   *****   ****
*         *     *   *   *   *   *   *   *       *       *       *   *
*         *      * *    *   *   *   *   *       *       *       *   *
*         *       *     ****    *   *   *****   *****   *****   ****
*         *      * *    *   *   *   *   *       *       *       *  *
*         *     *   *   *   *   *   *   *       *       *       *   *
*         *     *   *   ****     ***    *       *       *****   *   *



sEtimeout       equ     11   [UNCALIBRATED]
pcbtimeout      equ     11   [CALIBRATED 1 MS]


********************************************************************************
*                                                                              *
*       routine TXCTRLBUFFroom: Function which returns the number of byte      *
*               ==============  positions as yet unused in the Transmit ctrl   *
*                               Buffer.                                        *
*                                                                              *
*       routine TXDATABUFFroom: Function which returns the number of byte      *
*               ==============  positions as yet unused in the Transmit data   *
*                               Buffer.                                        *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  TXBUFF base address (shifted, +1+selectcode)           *
*               a3.l =  card base address ($00xx0001)                          *
*               d5.l =  TXDATABUFF_SIZE or TXCTRLBUFF_SIZE                     *
*                       (unshifted, not adjusted)                              *
*                                                                              *
*       Upon exit:                                                             *
*               d0.l =  TXDATABUFF_FILL or TXCTRLBUFF_FILL (unshifted)         *
*               d3.l =  Number of bytes left                                   *
*               This also bashes d2.                                           *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access and release_access.                     *
*                                                                              *
********************************************************************************

TXCTRLBUFFroom equ *
	clr.l   d0                      ; Get garbage out of top of d0&d3
	clr.l   d3
	movep.w CTRL_AREA+FILL(a2),d0
	bsr     gain_access             ; Need access to EMPTY
	movep.w CTRL_AREA+EMPTY(a2),d3  ; Fetch pointers (bytes in wrong order)
	bra.s   room1

TXDATABUFFroom equ *
	clr.l   d0                      ; Get garbage out of top of d0&d3
	clr.l   d3
	movep.w DATA_AREA+FILL(a2),d0
	bsr     gain_access             ; Need access to EMPTY
	movep.w DATA_AREA+EMPTY(a2),d3  ; Fetch pointers (bytes in wrong order)
room1   bsr     release_access

	ror.w   #8,d0                   ; Switch bytes in d0 & d3
	ror.w   #8,d3

	sub.w   d0,d3                   ; Compute d3 := EMPTY-FILL
	subq.w  #1,d3                   ; (EMPTY-FILL-1)
	bge.s   room2
	add.w   d5,d3                   ; If negative, add size

room2   rts                             ; Return (EMPTY-FILL-1) mod SIZE
	page
********************************************************************************
*                                                                              *
*       routine putchars:       Routine which takes characters from the        *
*               ========        area sc_subtabletype.data_address sized by     *
*                               sc_subtabletype.data_number and moves          *
*                               them to the Transmit buffer.  The number of    *
*                               characters actually transfered is the minimum  *
*                               of: (1) the number of characters available;    *
*                               (2) the number of byte positions left in the   *
*                               Transmit buffer; and (3) the number of byte    *
*                               positions in the Transmit buffer until the     *
*                               wraparound point.  THIS NUMBER CAN BE ZERO.    *
*                               This alters data_address and data_number to    *
*                               reflect where to start going next time this    *
*                               is called.  The entire transfer is done when   *
*                               data_number goes to zero.                      *
*                                                                              *
*       At entry:                                                              *
*               a2.l =  TX buffer record base address (shifted, +1+selectcode) *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               data_number and data_address are updated, plus FILL in the     *
*               card's Transmit buffer.                                        *
*               a1, d4 and d5 are left with the values from find_DATA_AREA.    *
*               This bashes d0, d1, d2, d3, d4, d5, a0, and a1.                *
*                                                                              *
*       Interrupts:                                                            *
*               This does its own enabling/disabling.  Interrupts are left ON. *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls gain_access, release_access, TXDATABUFFroom,        *
*       and find_DATA_AREA.                                                    *
*                                                                              *
********************************************************************************

putchars equ    *
	bsr     find_DATA_AREA          ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = TXDATABUFF_SIZE
	bsr     dir
	bsr     TXDATABUFFroom          ; d3.l = available buffer positions
	move.l  d0,d1                   ; d0.l = d1.l = TXDATABUFF_FILL
	move.l  d4,d0
	andi.l  #$0000FFFE,d0
	asr.l   #1,d0                   ; d0.l = unshifted TXDATABUFF_END
	sub.l   d1,d0                   ; d0.l = remaining positions to wrap

	cmp.l   d0,d3                   ; If d0>d3 then set d0 := d3
	bgt.s   pc1
	move.l  d3,d0

pc1     move.l  data_number(a4),d2      ; Fetch number of chars avail into d2
	cmp.l   d0,d2                   ; If d0>d2 then set d0 := d2
	bgt.s   pc2
	move.l  d2,d0

pc2     move.l  d0,d3                   ; d3.l saves number of chars actually
*                                       ; transferred below
	beq.s   pcdone                  ; If zero, no work to be done
	subq.w  #1,d0                   ; Make offset correct for dbf instr.
	movea.l data_address(a4),a0     ; Get character pointer into a0

	lsl.w   #1,d1
	add.l   a3,d1
	movem.l a1,-(sp)                ; Save a1 so we can use the register
	movea.l d1,a1                   ; Now a1 is useable pointer

pcloop  move.b  (a0)+,(a1)              ; Transfer a character & bump source ptr
	addq.w  #2,a1                   ; Bump destination pointer (odd bytes)
	dbf     d0,pcloop               ; Then decrement d0 & loop

	sub.l   d3,d2
	move.l  d2,data_number(a4)      ; Now store adjusted number and
	move.l  a0,data_address(a4)     ; address fields

	move.l  a1,d1                   ; Move 68000 FILL pointer into d1
	movem.l (sp)+,a1                ; Restore a1 before we forget!
	cmp.l   d1,d4                   ; Now check to see if FILL was moved
	bne.s   pc3                     ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
pc3     bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,DATA_AREA+FILL(a2)   ; Remember d1 = card's FILL pointer.
	bsr     release_access
pcdone  bra     eir
	page
********************************************************************************
*                                                                              *
*       routine putctrlblk:     Routine which puts a control block into the    *
*               ==========      Transmit buffer area of the card.  The         *
*                               appropriate pointers are updated to reflect    *
*                               the control block.  This routine also contains *
*                               a timeout mechanism which will be adjusted     *
*                               to the proper values later.  If a timeout      *
*                               occurs, an escape is done with NO DAMAGE to    *
*                               the buffer.  The only thing that can cause the *
*                               timeout is < 4 positions left in the control   *
*                               buffer.  SEMAPHORE timeout is not handled      *
*                               by this routine.                               *
*                                                                              *
*       At entry:                                                              *
*               sc_subtabletype.term =  TERM field for control block (8 bits)  *
*               sc_subtabletype.mode =  MODE field for control block (8 bits)  *
*               a2.l =  TX buffer record base address (shifted, +1+selectcode) *
*               a3.l =  card base address ($00xx0001)                          *
*               a4.l =  pointer to sc_subtabletype structure                   *
*                                                                              *
*       Upon exit:                                                             *
*               FILL in the card's transmit control buffer is updated.         *
*               a1, d4 and d5 are left with the values from find_CTRL_AREA.    *
*               This bashes d0, d1, d2, d3, d4, d5, a0 and a1.                 *
*               This uses inner/outer_tx_count for computing timeouts.         *
*                                                                              *
*       Interrupts:                                                            *
*               This does its own enabling/disabling.  Interrupts are left ON. *
*                                                                              *
*       This routine uses the card's SEMAPHORE to gain access.                 *
*                                                                              *
*       This routine calls TXCTRLBUFFroom, escape, gain_access, find_CTRL_AREA,*
*       eir, dir and release_access.                                           *
*                                                                              *
********************************************************************************

putctrlblk equ  *
	bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TXCTRLBUFF_SIZE
	move.l  timeout(a4),outer_tx_count(a4)
	move.l  #pcbtimeout,inner_tx_count(a4) ; Load timeout value
*
	btst    #timer_present,sysflag2      timer present?    tttt JS 8/11/83
	beq.s   pcbtime                   if so then use it    tttt JS 8/11/83
*
pcbwait bsr     dir
	bsr     TXCTRLBUFFroom          ; Get d3 = #bytes available in buffer
	cmpi.l  #4,d3                   ; and d0 = CTRLBUFF_FILL (unshifted)
	bge.s   roomok                  ; If >=4 bytes, can go ahead!
	bsr     eir
	subq.l  #1,inner_tx_count(a4)
	bne.s   pcbwait                 ; Loop, then if it times out give an
	move.l  #pcbtimeout,inner_tx_count(a4)
	tst.l   outer_tx_count(a4)
	beq.s   pcbwait
	subq.l  #1,outer_tx_count(a4)
	bne.s   pcbwait
	bra     time_err                ; escape(timeout).

roomok  lsl.w   #1,d0                   ; Make CTRLBUFF_FILL into a 68000
	add.l   a3,d0                   ; pointer
	movea.l d0,a0                   ; Put in a0 to use it.

	movep.w DATA_AREA+FILL(a2),d0   ; Get the DATA_FILL pointer to put
	movep.w d0,POINTER(a0)          ; into the POINTER FIELD
	move.w  term_and_mode(a4),d0
	movep.w d0,TERMFIELD(a0)
	adda.l  #CTRLBLKSIZE,a0         ; Bump pointer by TWO bytes

	move.l  a0,d1                   ; Move 68000 FILL pointer into d1
	cmp.l   d1,d4                   ; Now check to see if FILL was moved
	bne.s   pcb1                    ; past end of buffer.  If so, set to
	move.l  a1,d1                   ; the front of the buffer.
pcb1    bclr    #0,d1                   ; Fix up the 68000 pointer to be the
	rol.w   #7,d1                   ; card's type of pointer
	bsr     gain_access
	movep.w d1,CTRL_AREA+FILL(a2)
	bsr     release_access
	bra     eir
*
pcbtime tst.l   timeout(a4)          see if infinite timeout   tttt JS 8/11/83
	beq     pcbwait              if so use other loops     tttt JS 8/11/83
	move.b  #1,-(sp)             else setup time record    tttt JS 8/11/83
	move.l  timeout(a4),-(sp)                              tttt JS 8/11/83
pcbtloop bsr    dir                  loop checks copied from   tttt JS 8/11/83
	bsr     TXCTRLBUFFroom       code above                tttt JS 8/11/83
	cmpi.l  #4,d3                                          tttt JS 8/11/83
	bge.s   troomok              ok -- leave               tttt JS 8/11/83
	bsr     eir                                            tttt JS 8/11/83
	pea     (sp)                push ptr to time rec       tttt JS 8/11/83
	jsr     check_timer         timeout?                   tttt JS 8/11/83
	bpl     pcbtloop            no, do loop again          tttt JS 8/11/83
	addq    #6,sp               yes, clean stack and do    tttt JS 5/3/84
	move.l  #1,outer_tx_count(a4)  quick final check       tttt JS 5/3/84
	bra     pcbwait                                        tttt JS 5/3/84
troomok addq    #6,sp               normal exit -- cleanup stk tttt JS 8/11/83
	bra     roomok              and return                 tttt JS 8/11/83
	page
*************************************************
*                                               *
*   routine try_sending_EOF:  tries to send EOF *
*               and returns immediately if      *
*               unsuccessful.                   *
*                                               *
*   At entry:                                   *
*       a2.l =  TX buffer-record base addr      *
*       a3.l =  card base address               *
*       a4.l =  pointer to sc_subtabletype      *
*                                               *
*   Upon exit:                                  *
*       d0.l = 0 if unsuccessful;               *
*              1 if successful.                 *
*                                               *
*   This bashes d0,d1,d2,d3,d4,d5,a0 & a1       *
*                                               *
*************************************************

try_sending_EOF equ *
	moveq   #4,d1
	clr.l   d0
	move.b  TXENDBLOCKSPACE-TXBUFF(a2),d0
	beq.s   sE3                     ; If it's zero jump down & wait for 4
	move.l  d0,d1                   ; bytes in the control queue
sE1     bsr     find_DATA_AREA          ; Setup a1 = data buffer base addr
*                                               d4 = end of data buffer addr
*                                               d5 = TXDATABUFF_SIZE
sE1loop bsr     dir
	bsr     TXDATABUFFroom          ; Now hang until enough space becomes
	cmp.l   d1,d3                   ; available in the data queue
	bge.s   sE2
	bsr     eir
noroom  clr.l   d0
	rts

sE2     moveq   #8,d1                   ; if TXENDBLOCKSPACE#0 then wait for
*                                       ; 8 bytes, not 4.
sE3     bsr     find_CTRL_AREA          ; Setup a1 = ctrl buffer base addr
*                                               d4 = end of ctrl buffer addr
*                                               d5 = TXCTRLBUFF_SIZE
sE3loop bsr     dir
	bsr     TXCTRLBUFFroom          ; Now hang until enough space becomes
	cmp.l   d1,d3                   ; available in the ctrl queue
	bge.s   sE4
	bsr     eir
	bra.s   noroom

sE4     tst.b   TXENDBLOCKSPACE-TXBUFF(a2)  ; There's enough room now!! If zero
	beq.s   sE6                         ; then just send 1 block below
	move.w  #$0501,term_and_mode(a4)
	bsr     putctrlblk
	clr.l   data_number(a4)             ; Followed by some space
	move.b  TXENDBLOCKSPACE-TXBUFF(a2),data_number+3(a4)
	move.l  #$FFFF0000,data_address(a4) ; kluge so it isn't left pointing
*                                           to nowhere & get bus error!
sE5     bsr     putchars
	tst.l   data_number(a4)             ; Hang until all sent
	bne.s   sE5
sE6     move.w  #$0500,term_and_mode(a4)
	bsr     putctrlblk
	moveq   #1,d0
	rts


	end

@


55.1
log
@Automatic bump of revision number for PWS version 3.25A
@
text
@@


54.1
log
@Automatic bump of revision number for PWS version 3.24
@
text
@@


53.1
log
@Automatic bump of revision number for PWS version 3.24B
@
text
@@


52.1
log
@Automatic bump of revision number for PWS version 3.24A
@
text
@@


51.1
log
@Automatic bump of revision number for PWS version 3.24d
@
text
@@


50.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@@


49.1
log
@Automatic bump of revision number for PWS version 3.24b
@
text
@@


48.1
log
@Automatic bump of revision number for PWS version 3.24a
@
text
@@


47.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


46.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


45.1
log
@Automatic bump of revision number for PWS version 3.23C
@
text
@@


44.1
log
@Automatic bump of revision number for PWS version 3.23B
@
text
@@


43.1
log
@Automatic bump of revision number for PWS version 3.23aA
@
text
@@


42.1
log
@Automatic bump of revision number for PWS version 3.23e
@
text
@@


41.1
log
@Automatic bump of revision number for PWS version 3.23d
@
text
@@


40.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@@


39.1
log
@Automatic bump of revision number for PWS version 3.23b
@
text
@@


38.1
log
@Automatic bump of revision number for PWS version 3.23a
@
text
@@


37.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


36.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


35.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


34.1
log
@Automatic bump of revision number for PWS version 3.22
@
text
@@


33.1
log
@Automatic bump of revision number for PWS version 3.22D
@
text
@@


32.1
log
@Automatic bump of revision number for PWS version 3.22C
@
text
@@


31.1
log
@Automatic bump of revision number for PWS version 3.22B
@
text
@@


30.1
log
@Automatic bump of revision number for PWS version 3.22A
@
text
@@


29.1
log
@Automatic bump of revision number for PWS version 3.22b
@
text
@@


28.1
log
@Automatic bump of revision number for PWS version 3.3b
@
text
@@


27.1
log
@Automatic bump of revision number for PWS version 3.3a
@
text
@@


26.1
log
@Automatic bump of revision number for PWS version 3.3 Synch
@
text
@@


25.1
log
@Automatic bump of revision number for PWS version 3.2Y
@
text
@@


24.1
log
@Automatic bump of revision number for PWS version 3.2
@
text
@@


23.1
log
@Automatic bump of revision number for PWS version 3.2P
@
text
@@


22.1
log
@Automatic bump of revision number for PWS version 3.2N
@
text
@@


21.1
log
@Automatic bump of revision number for PWS version 3.2M
@
text
@@


20.1
log
@Automatic bump of revision number for PWS version 3.2L
@
text
@@


19.1
log
@Automatic bump of revision number for PWS version 3.2K
@
text
@@


18.1
log
@Automatic bump of revision number for PWS version 3.2J
@
text
@@


17.1
log
@Automatic bump of revision number for PWS version 3.2I+
@
text
@@


16.1
log
@Automatic bump of revision number for PWS version 3.2I
@
text
@@


15.1
log
@Automatic bump of revision number for PWS version 3.2H
@
text
@@


14.1
log
@Automatic bump of revision number for PWS version 3.2G
@
text
@@


13.1
log
@Automatic bump of revision number for PWS version 3.2F
@
text
@@


12.1
log
@Automatic bump of revision number for PWS version 3.2E
@
text
@@


11.1
log
@Automatic bump of revision number for PWS version 3.2D
@
text
@@


10.1
log
@Automatic bump of revision number for PWS version 3.2C
@
text
@@


9.1
log
@Automatic bump of revision number for PWS version 3.2B
@
text
@@


8.1
log
@Automatic bump of revision number for PWS version 3.2A
@
text
@@


7.1
log
@Automatic bump of revision number for PWS version 3.2l
@
text
@@


6.1
log
@Automatic bump of revision number for PWS version 3.2k
@
text
@@


5.1
log
@Automatic bump of revision number for PWS version 3.2j
@
text
@@


4.1
log
@Automatic bump of revision number for PWS version 3.2i
@
text
@@


3.1
log
@Automatic bump of revision number for PWS version 3.2h
@
text
@@


2.1
log
@Auto bump rev number to 2.1 for sys 3.2e.
@
text
@@


1.1
log
@Initial revision
@
text
@@
