; Kermit system dependent module for Heath/Zenith Z100
; Includes fix to SETBAUD from August Treubig of Middle South Services
; via John Voigt, Tulane Univ. Systems Group <SYSBJAV@TCSVM.BITNET>
; Add global entry point vtstat for use by Status in mssset.
; Add a few register saves & restores.
; Also trimmed off trailing commas from publics. Joe R. Doupnik 12 March 1986

        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel
        public  ctlu, cmblnk, locate, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep
        public  count, xofsnt, puthlp, putmod, clrmod, poscur
        public  sendbr, machnam, setktab, setkhlp, lclini, showkey
        include mssdef.h

false   equ     0
true    equ     1
mntrgh  equ     bufsiz*3/4      ; High point = 3/4 of buffer full.

; constants used by serial port handler

BRKBIT  EQU     048H            ; Send-break bit.

MDMCOM1 EQU     00EFH           ; Address of modem port command. [19b]

; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;    or port2)
; port1, port2 - portinfo structures for the corresponding ports

; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
;    not implemented)
; setkhlp - help for setktab.

BIOS_SEG SEGMENT AT 40H         ; Define segment where BIOS really is
        ORG     6*3
BIOS_AUXOUT LABEL FAR           ; AUX output routine
        ORG     26*3
BIOS_AUXFUNC LABEL FAR          ; AUX: function
        ORG     27*3
BIOS_CONFUNC LABEL FAR          ; CON: function
BIOS_SEG ENDS

; Function codes for BIOS_xxxFUNC
CHR_WRITE       EQU     0       ; Write character
CHR_READ        EQU     1       ; Read character
CHR_STATUS      EQU     2       ; Get status
  CHR_SFGS      EQU     0       ; Get status subfunction
  CHR_SFGC      EQU     1       ; Get config subfunction
CHR_CONTROL     EQU     3       ; Control function
  CHR_CFSU      EQU     0       ; Set new configuration parameters
  CHR_CFCI      EQU     1       ; Clear input buffer


datas   segment public 'datas'
        extrn   drives:byte, flags:byte, trans:byte
        extrn   portval:word, port1:byte, port2:byte

setktab db      13
        mkeyw   'F0',96h
        mkeyw   'F1',97h
        mkeyw   'F2',98h
        mkeyw   'F3',99h
        mkeyw   'F4',9ah
        mkeyw   'F5',9bh
        mkeyw   'F6',9ch
        mkeyw   'F7',9dh
        mkeyw   'F8',9eh
        mkeyw   'F9',9fh
        mkeyw   'F10',0a0h
        mkeyw   'F11',0a1h
        mkeyw   'SCAN',-1

setkhlp db      cr,lf,'Keyname: f0, ... f11, "HELP" or "SCAN" follwed by '
        db      'decimal scan code$'
brkval  db      0               ; What to send for a break.
brkadr  dw      0               ; Where to send it.
badbd   db      cr,lf,'Unimplemented baud rate$'
noimp   db      cr,lf,'Not implemented$'
machnam db      'Heath-Zenith Z-100$'
crlf    db      cr,lf,'$'
delstr  db      BS,BS,' ',BS,'$' ; Delete string. [21d]
home    db      ESC,'H$'
eeolstr db      ESC,'K$'        ; Erase to end of line
clrstr  db      ESC,'E$'        ; Erase entire display
enamod  db      ESC,'x1$'       ; Enable 25th line
dismod  db      ESC,'y1$'       ; Disable 25th line
enascan db      ESC,'y?$'       ; Enable scan codes
disscan db      ESC,'x?$'       ; Disable scan codes
begrev  db      ESC,'p$'        ; Enter reverse video
endrev  db      ESC,'q$'        ; Exit reverse video
lin25   db      ESC,'Y8 $'      ; Column 1 row 25
savcur  db      ESC,'j$'        ; Save current cursor position
precur  db      ESC,'k$'        ; Restore cursor to previous position
clrlin  db      cr,'$'          ; Clear line (just the cr part).
xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
tmp     db      ?,'$'
temp1   dw      ?               ; Temporary storage.

ontab   db      02H             ; Two entries.
        db      03H,'OFF$'      ; Should be alphabetized. [19a]
        dw      00H
        db      02H,'ON$'
        dw      01H

; this table is indexed by the baud rate definitions given in
; pcdefs.  Unsupported baud rates should contain FF.
bddat   label   word
        dw      0               ; 45.5 baud
        dw      1               ; 50 baud
        dw      2               ; 75 baud
        dw      3               ; 110 baud
        dw      4               ; 134.5 baud
        dw      5               ; 150 baud
        dw      6               ; 300 baud
        dw      7               ; 600 baud
        dw      8               ; 1200 baud
        dw      9               ; 1800 baud
        dw      10              ; 2000 baud
        dw      11              ; 2400 baud
        dw      12              ; 4800 baud
        dw      13              ; 9600 baud
        dw      14              ; 19200 baud
        dw      15              ; 38400 baud

; storage for port configuration
cfginfo struc
cfclass db      0
cfattr  db      0
cfport  dw      0
cfbaud  db      0
cfhshk  db      0
cfbctl  db      0
cfecnt  db      0
cfncnt  db      0
cfnchr  db      0
cfres   db      6 dup(?)
cfsize  db      0
cfginfo ends

auxconf cfginfo <>

; variables for serial interrupt handler

count   dw      0               ; Number of chars in int buffer.

ourarg  termarg <>

shkbuf  db      300 dup (?)     ; room for definition
shkmsg  db      '  Scan code: '
shkmln  equ     $-shkmsg
shkms1  db      cr,lf,'  Definition: '
shkm1ln equ     $-shkms1
datas   ends

code    segment public
        extrn   comnd:near, dopar:near, defkey:near
        assume  cs:code,ds:datas

; local initialization

lclini  proc    near
        mov     brkval,BRKBIT   ; What to send for a break.
        mov     brkadr,MDMCOM1
        mov     flags.vtflg,0   ; Turn off true Heath mode (allows key macros)

        ret
lclini  endp

; this is called by Kermit initialization.  It checks the
; number of disks on the system, sets the drives variable
; appropriately.  Returns normally.

DODISK  PROC    NEAR
        mov     ah,gcurdsk      ; Current disk value to AL.
        int     dos
        mov     dl,al           ; Put current disk in DL.
        mov     ah,seldsk       ; Select current disk.
        int     dos
        mov     drives,al
        ret
DODISK  ENDP

; show the definition of a key.  The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc    near
        push    es
        push    ax              ; save the ptr
        mov     bx,ds
        mov     es,bx           ; address data segment
        cld
showk1: mov     ah,prstr
        mov     dx,offset enascan ; enable scan codes
        int     dos
        mov     ah,0ch          ; char input with buffer flush
        mov     al,7
        int     dos
;       mov     ah,chr_control
;       mov     al,chr_cfci     ; clear input
;       call    bios_confunc
;       mov     ah,chr_read
;       call    bios_confunc    ; read a char
        push    ax
        mov     ah,prstr
        mov     dx,offset disscan ; disable scan codes
        int     dos
        pop     ax
;       push    ax              ; save the character
;       call    gss             ; get shift state
;       pop     bx
        mov     ah,0            ; shift state to ah
;       mov     al,bh           ; scan code to al
        push    ax              ; remember scan code
        mov     di,offset shkbuf
        mov     si,offset shkmsg
        mov     cx,shkmln
        rep     movsb           ; copy in initial message
        call    nout            ; write out scan code
        mov     si,offset shkms1
        mov     cx,shkm1ln      ; second message
        rep     movsb
        pop     ax              ; get scan code back
        pop     bx              ; and terminal arg block
        mov     cx,[bx].klen    ; and length
        jcxz    showk2          ; no table, not defined
        push    di              ; remember output ptr
        mov     di,[bx].ktab    ; get key table
        repne   scasw           ; search for a definition for this
        mov     si,di           ; remember result ptr
        pop     di              ; get output ptr back
        jne     showk2          ; not defined, forget it
        sub     si,[bx].ktab    ; compute offset from beginning
        sub     si,2            ; minus 2 for pre-increment
        add     si,[bx].krpl    ; get index into replacement table
        mov     si,[si]         ; pick up replacement
        mov     cl,[si]         ; get length
        mov     ch,0
        inc     si
        rep     movsb           ; copy into buffer
showk2: mov     ax,offset shkbuf ; this is buffer
        mov     cx,di
        sub     cx,ax           ; length
        pop     es
        ret                     ; and return
showkey endp

; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.

CLRBUF  PROC    NEAR
        cli
        mov     ah,chr_control
        mov     al,chr_cfci
        call    bios_auxfunc
        mov     count,0
        sti
        ret
CLRBUF  ENDP

; Clear to the end of the current line.  Returns normally.

CLEARL  PROC    NEAR
        mov     ah,prstr
        mov     dx,offset eeolstr       ; Erase to end of line
        int     dos
        ret
CLEARL  ENDP

; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  Should honor xon/xoff.  Skip returns on
; success, returns normally if the character cannot be written.

outchr: mov     bp,portval
        cmp     ds:[bp].floflg,0 ; Are we doing flow control.
        je      outch2          ; No, just continue.
        xor     cx,cx           ; clear counter
outch1: cmp     xofrcv,true     ; Are we being held?
        jne     outch2          ; No - it's OK to go on.
        loop    outch1          ; held, try for a while
        mov     xofrcv,false    ; timed out, force it off and fall thru.
outch2: push    dx              ; Save register.
        mov     al,ah           ; Parity routine works on AL.
        call    dopar           ; Set parity appropriately.
        call    bios_auxout
        pop     dx
        jmp     rskp

; This routine blanks the screen.  Returns normally.

CMBLNK  PROC    NEAR
        mov     ah,prstr
        mov     dx,offset clrstr
        int     dos
        ret
CMBLNK  ENDP

; Locate: homes the cursor.  Returns normally.

LOCATE  PROC    NEAR
        mov     ah,prstr
        mov     dx,offset home  ; Go to top left corner of screen.
        int     dos
LOCATE  ENDP

; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $.  Returns normally.
putmod  proc    near
        push    dx              ; preserve message
        mov     ah,prstr
        mov     dx,offset savcur
        int     dos
        mov     dx,offset enamod
        int     dos
        mov     dx,offset lin25
        int     dos
        mov     dx,offset begrev
        int     dos
        pop     dx              ; get message back
        int     dos             ; write it out
        mov     dx,offset endrev
        int     dos
        mov     dx,offset precur
        int     dos
        ret                     ; and return
putmod  endp

; clear the mode line written by putmod.  Returns normally.
clrmod  proc    near
        mov     ah,prstr
        mov     dx,offset dismod
        int     dos
        ret
clrmod  endp

BEEP    PROC    NEAR
        mov     dl,07           ; ASCII BEL
        mov     ah,dconio
        int     dos             ; Ring it
        ret
BEEP    ENDP


; put a help message on the screen.  This one uses reverse video...
; pass the message in ax, terminated by a null.  Returns normally.
puthlp  proc    near
        push    ax              ; preserve this
        mov     ah,prstr
        mov     dx,offset crlf
        int     dos
        pop     si              ; point to string again
puthl3: lodsb                   ; get a byte
        cmp     al,0            ; end of string?
        je      puthl4          ; yes, stop
        mov     dl,al
        mov     ah,dconio
        int     dos
        jmp     puthl3          ; and keep going
puthl4: mov     ah,prstr
        mov     dx,offset crlf
        int     dos
        ret
puthlp  endp

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.

DOBAUD  PROC    NEAR
        mov     bp,portval
        mov     temp1,ax        ; Don't overwrite previous rate. [25]
        mov     ax,ds:[bp].baud ; Check if new rate is valid. [25]
        mov     tmp,2
        mul     tmp             ; Get index into baud table.
        mov     bx,offset bddat ; Start of table.
        add     bx,ax
        mov     ax,[bx]         ; The data to output to port.
        cmp     ax,0FFH         ; Unimplemented baud rate.
        jne     dobd0
        mov     ax,temp1        ; Get back orginal value.
        mov     ds:[bp].baud,ax ; Leave baud rate as is.
        mov     ah,prstr
        mov     dx,offset badbd ; Give an error message.
        int     dos
        ret
dobd0:  push    ax              ; Save it
        mov     bx,ds           ; Set up pointer to config info
        mov     es,bx           ;  .  .  .
        mov     bx,offset auxconf ;  .  .  .
        mov     ah,chr_status
        mov     al,chr_sfgc     ; get current config info
        call    bios_auxfunc
        pop     ax              ; get baud back
        mov     auxconf.cfbaud,al
        mov     ah,chr_control  ; Function is control
        mov     al,chr_cfsu     ; Subfunction is set new config
        call    bios_auxfunc    ; Set the configuration
        ret
DOBAUD  ENDP

; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.

GETBAUD PROC    NEAR
        push    ax              ; save regs [jrd]
        push    bx              ; [jrd]
        push    cx              ; [jrd]
        push    es              ; [jrd]
        mov     bx,ds
        mov     es,bx
        mov     bx,offset auxconf
        mov     ah,chr_status
        mov     al,chr_sfgc     ; Status function get config info
        push    di              ;*** Save this!
        call    bios_auxfunc
        pop     di              ;*** Restore
        mov     ch,0
        mov     cl,auxconf.cfbaud
        mov     bp,portval
        mov     ds:[bp].baud,cx
        pop     es              ; restore regs [jrd]
        pop     cx              ; [jrd]
        pop     bx              ; [jrd]
        pop     ax              ; [jrd]
        ret
GETBAUD ENDP

; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR  PROC    NEAR
        call    chkxon          ; see if we need to xon
        push    bx
        mov     ah,chr_status
        mov     al,chr_sfgs     ; Status function get status
        call    bios_auxfunc
        cmp     bl,0
        jnz     prtch2
        pop     bx
        jmp     rskp            ; No data - check console.
prtch2: mov     dh,0
        mov     dl,bl           ; Place # of chars in dx
        mov     ah,chr_read
        call    bios_auxfunc
        dec     dl              ; Decrement number of chars
        mov     count,dx        ; Save count for posterity
        pop     bx
        ret
PRTCHR  ENDP

; local routine to see if we have to transmit an xon
chkxon  proc    near
        push    bx
        mov     bx,portval
        cmp     [bx].floflg,0   ; doing flow control?
        je      chkxo1          ; no, skip all this
        cmp     xofsnt,false    ; have we sent an xoff?
        je      chkxo1          ; no, forget it
        cmp     count,mntrgh    ; below trigger?
        jae     chkxo1          ; no, forget it
        mov     ax,[bx].flowc   ; ah gets xon
        call    outchr          ; send it
        nop
        nop
        nop                     ; in case it skips
        mov     xofsnt,false    ; remember we've sent the xon.
chkxo1: pop     bx              ; restore register
        ret                     ; and return
chkxon  endp

; Send a break out the current serial port.  Returns normally.
SENDBR  PROC    NEAR
        push    cx
        push    dx
        push    ax
        xor     cx,cx           ; Clear loop counter.
        mov     dx,brkadr       ; Port address.  [19b]
        in      al,dx           ; Get current setting.
        or      al,brkval       ; Set send-break bit(s).
        out     dx,al           ; Start the break.
pause:  loop    pause           ; Wait a while.
        xor     al,brkval       ; Clear send-break bit(s).
        out     dx,al           ; Stop the break.
        pop     ax
        pop     dx
        pop     cx
        ret                     ; And return.
SENDBR  ENDP

; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.

POSCUR  PROC    NEAR
        push    dx
        push    ax              ; [jrd]
        mov     ah,CONOUT
        mov     dl,ESC
        int     dos
        mov     dl,'Y'
        int     dos
        pop     dx
        push    dx
        mov     dl,dh
        add     dl,' '
        int     dos
        pop     dx
        add     dl,' '
        int     dos
        pop     ax              ; [jrd]
        ret
POSCUR  ENDP

; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.

DODEL   PROC    NEAR
        mov     ah,prstr
        mov     dx,offset delstr ; Erase weird character.
        int     dos
        ret
DODEL   ENDP

; Move the cursor to the left margin, then clear to end of line.
; Returns normally.

CTLU    PROC    NEAR
        mov     ah,prstr
        mov     dx,offset clrlin
        int     dos
        call    clearl
        ret
CTLU    ENDP

; set the current port.

COMS    PROC    NEAR
        jmp     notimp
COMS    ENDP

; Set heath emulation on/off.

VTS     PROC    NEAR
        mov     dx,offset ontab
        mov     bx,0
        mov     ah,cmkey
        call    comnd
         jmp    r
        push    bx
        mov     ah,cmcfm
        call    comnd                   ; Get a confirm.
         jmp    vt0                     ; didn't get a confirm.
         nop
        pop     bx
        mov     flags.vtflg,bl          ; Set the Heath emulation flag
        ret
vt0:    pop     bx
        ret
VTS     ENDP

notimp: mov     ah,prstr
        mov     dx,offset noimp
        int     dos
        jmp     rskp

VTSTAT  PROC    NEAR    ; For Status display [jrd]
        ret             ; no emulator status to display
VTSTAT  ENDP

; initialization for using serial port.  This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.

SERINI  PROC    NEAR
        ret                     ; We're done.
SERINI  ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.

SERRST  PROC    NEAR
        ret                     ; All done.
SERRST  ENDP


; put the number in ax into the buffer pointed to by di.  Di is updated
nout    proc    near
        mov     dx,0            ; high order is always 0.
        mov     bx,10
        div     bx              ; divide to get digit
        push    dx              ; save remainder digit
        or      ax,ax           ; test quotient
        jz      nout1           ; zero, no more of number
        call    nout            ; else call for rest of number
nout1:  pop     ax              ; get digit back
        add     al,'0'          ; make printable
        stosb                   ; drop it off
        ret                     ; and return
nout    endp


; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop     bp
        add     bp,3
        push    bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

code    ends
        end
