; Kermit system dependent module for UCI EZ-PC, base upon IBM-PC module.

; Edit History
; Add global entry point vtstat for use by Status in mssset.
; Cleared terminal emulation flag, flags.vtflg, in procedure lclini.
; Added register save/restore in procedure getbaud.
; Also trimmed off trailing commas in publics. Joe R. Doupnik 12 March 1986

;  Make break be 275 ms, DT 5:51pm  Thursday, 6 December 1984

        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.
TIMER   EQU     40H             ; Use to issue short beep.
PORT_B  EQU     61H             ; Port B address.
MCONF   EQU     11H             ; Machine configuration.
KEYB    EQU     16H
BIOS    EQU     10H

MDMDAT1 EQU     03F8H           ; Address of modem port (data). [19b]
MDMSTS1 EQU     03F9H           ;**** Address of modem port status. [19b]
MDMCOM1 EQU     03FBH           ; Address of modem port command. [19b]
MDMDAT2 EQU     02F8H           ; Port 2 address. [19b]
MDMSTS2 EQU     02F9H           ;**** Port 2 status. [19b]
MDMCOM2 EQU     02FBH           ; Port 2 command. [19b]
MDMINP  EQU     2               ;**** MC2661 INPUT READY BIT

MDMINTV EQU     0030H           ; Address of modem port interrupt vector.
MDINTV2 EQU     002CH           ; Address for port 2. [19b]
MDMINTO EQU     0EFH            ; Mask to enable interrupt for modem port.
MDINTO2 EQU     0F7H            ; Enable interrupt level 3. [19b]
MDMINTC EQU     010H            ; Bit to set to disable interrupts for modem.
MDINTC2 EQU     008H            ; Disable IRQ3. [19b]

INTCONT EQU     0021H           ; Address of 8259 interrupt controller ICW2-3.
INTCON1 EQU     0020H           ; Address of 8259 ICW1.
EOICOM  EQU     0064H           ; End of interrupt.
EOICOM2 EQU     0063H           ; End of interrupt for COM2. [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.

datas   segment public 'datas'
        extrn   drives:byte,flags:byte, trans:byte
        extrn   portval:word, port1:byte, port2:byte

setktab db      12
        mkeyw   'BACKSPACE',0eh
        mkeyw   'F1',3bh
        mkeyw   'F2',3ch
        mkeyw   'F3',3dh
        mkeyw   'F4',3eh
        mkeyw   'F5',3fh
        mkeyw   'F6',40h
        mkeyw   'F7',41h
        mkeyw   'F8',42h
        mkeyw   'F9',43h
        mkeyw   'F10',44h
        mkeyw   'SCAN',-1

setkhlp db      cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" follwed by '
        db      'decimal scan code$'
brkval  db      0               ; What to send for a break.
brkadr  dw      0               ; Where to send it.
modem   mdminfo <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
erms20  db      cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40  db      cr,lf,'?Warning: Unrecognized baud rate$'
badbd   db      cr,lf,'Unimplemented baud rate$'
machnam db      'IBM-PC$'
crlf    db      cr,lf,'$'
delstr  db      BS,' ',BS,'$'   ; Delete string. [21d]
clrlin  db      cr,'$'                  ; Clear line (just the cr part).
savsci  dw      ?               ; Save for serial port interrupt vector. [14]
savscs  dw      ?               ; Ditto.  [14]
savbr1  dw      ?               ; "Break" interrupt vector. [25]
savbr2  dw      ?               ; Ditto. [25]
portin  db      0               ; Has comm port been initialized. [21c]
xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.

ontab   db      02H             ; Two entries.
        db      03H,'OFF$'      ; Should be alphabetized.  [19a]
        dw      00H
        db      02H,'ON$'
        dw      01H

comptab db      04H
        db      01H,'1$'
        dw      01H
        db      01H,'2$'
        dw      00H
        db      04H,'COM1$'
        dw      01H
        db      04H,'COM2$'
        dw      00H

; this table is indexed by the baud rate definitions given in
; pcdefs.  Unsupported baud rates should contain FF.
bddat   label   word
        ;**** THIS TABLE HAS BEEN CHANGED FOR THE UCI EZ-PC
        dw      000H            ; 45.5 baud  -- MC2661B SUPPORTED
        dw      001H            ; 50 baud
        dw      002H            ; 75 baud
        dw      003H            ; 110 baud
        dw      004H            ; 134.5 baud
        dw      005H            ; 150 baud
        dw      006H            ; 300 baud
        dw      007H            ; 600 baud
        dw      08H             ; 1200 baud
        dw      09H             ; 1800 baud
        dw      0AH             ; 2000 baud
        dw      0BH             ; 2400 baud
        dw      0CH             ; 4800 baud
        dw      0DH             ; 9600 baud
        dw      00EH            ; 19200 baud -- MC2661B SUPPORTED
        dw      00FH            ; 38400 baud -- MC2661B SUPPORTED

; variables for serial interrupt handler

source  db      bufsiz DUP(?)   ; Buffer for data from port.
srcpnt  dw      0               ; Pointer in buffer (DI).
count   dw      0               ; Number of chars in int buffer.
savesi  dw      0               ; Save SI register here.
telflg  db      0               ; Are we acting as a terminal.
mst     dw      0               ; Modem status address.
mdat    dw      0               ; Modem data address.
mdeoi   db      0               ; End-of-Interrupt value.

rbtrn   db      7fH             ; rubout

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, gss:near
        assume  cs:code,ds:datas

; local initialization

lclini  proc    near
        mov     flags.vtflg,0   ; no terminal emulation. [jrd]
        mov     ax,0eH          ; scan code for arrow key
        mov     si,offset rbtrn ; translate to rubout
        mov     cx,1            ; one char translation
        call    defkey
        mov brkval,BRKBIT       ; What to send for a break.
        mov ax,modem.mdcom      ; Where to send it.
        mov brkadr,ax
        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
        int mconf                       ; Get equipment configuration.
        mov ah,al                       ; Store AL value for a bit.
        and al,01H                      ; First, look at bit 0.
        jz dodsk0                       ; No disk drives -- forget it.
        mov al,ah                       ; Get back original value.
        mov cl,6                        ; Shift over bits 6 and 7.
        shr al,cl                       ; To positions 0 and 1.
        inc al                          ; Want 1 thru 4 (not 0 thru 3).
        mov drives,al                   ; Remember how many.
        ret
dodsk0: mov ah,prstr                    ; Print a warning message.
        mov dx,offset erms20            ; I'm not sure if things will
        int dos                         ; work with only a cassette.
        mov drives,0                    ; Say there aren't any drives.
        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: xor     ah,ah
        int     keyb            ; read a char
        push    ax              ; save the character
        call    gss             ; get shift state
        pop     bx
        mov     ah,al           ; 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 ax,offset source
        mov srcpnt,ax
        mov savesi,ax
        mov count,0
        sti
        ret
CLRBUF  ENDP

; Clear to the end of the current line.  Returns normally.

CLEARL  PROC    NEAR
        mov ah,3                ; Clear to end of line.
        mov bh,0
        int bios                ; Get current cursor position
        mov cx,dx
        mov dl,79
        mov ah,7
        mov al,0
        mov bh,7
        int bios
        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.
        sub cx,cx
        mov al,ah               ; Parity routine works on AL.
        call dopar              ; Set parity appropriately.
        mov ah,al               ; Don't overwrite character with status.
        mov dx,modem.mdstat     ; Get port status.
outch3: in al,dx
        test al,01H             ;**** Transmitter ready?
        jnz outch4              ; Yes
        loop outch3
         jmp outch5             ; Timeout
outch4: mov al,ah               ; Now send it out
        mov dx,modem.mddat
        out dx,al
        pop dx
        jmp rskp
outch5: pop dx
        ret

; This routine blanks the screen.  Returns normally.

CMBLNK  PROC    NEAR            ; This is stolen from the IBM example.
        mov cx,0
        mov dx,184FH
        mov bh,7
        mov ax,600H
        int bios
        ret
CMBLNK  ENDP

; Locate: homes the cursor.  Returns normally.

LOCATE  PROC    NEAR
        mov dx,0                ; Go to top left corner of screen.
        jmp poscur
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     cx,1800h
        mov     dx,184fh
        mov     ax,600h         ; scroll to clear the line
        mov     bh,70h          ; inverse video
        int     bios
        mov     dx,1800h        ; now address line 24
        call    poscur
        pop     dx              ; get message back
        mov     ah,prstr
        int     dos             ; write it out
        ret                     ; and return
putmod  endp

; clear the mode line written by putmod.  Returns normally.
clrmod  proc    near
        mov     cx,1800h
        mov     dx,184fh
        mov     ax,600h
        mov     bh,7h
        int     bios
        ret
clrmod  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     si,ax           ; point to it
        mov     dh,1            ; init counter
puthl1: lodsb                   ; get a byte
        cmp     al,lf           ; linefeed?
        jne     puthl2          ; no, keep going
        inc     dh              ; count it
        jmp     puthl1          ; and keep looping
puthl2: cmp     al,0            ; end of string?
        jne     puthl1          ; no, keep going
        mov     ax,600h         ; scroll to clear window
        xor     cx,cx           ; from top left
        mov     dl,4fh          ; to bottom right of needed piece
        mov     bh,70h          ; inverse video
        int     bios
        call    locate          ; home cursor
        pop     si              ; point to string again
puthl3: lodsb                   ; get a byte
        cmp     al,0            ; end of string?
        je      puthl4          ; yes, stop
        mov     ah,14
        int     bios            ; else write to screen
        jmp     puthl3          ; and keep going
puthl4: mov     dx,24 * 100H    ; go to last line
        jmp     poscur          ; position and return
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:  mov temp1,ax            ; Remember value to output. [25]
        mov dx,modem.mdcom      ; LCR -- Initialize baud rate. [19b]
        in al,dx
        mov bl,al


           dec dx                  ;****
           in al,dx
           mov ah,al               ;mode 1
           in al,dx
           mov bh,al               ;mode 2 contains baud rate
           and bh,0f0h             ;mask out baud rate

;          or ax,80h
;       out dx,al
;       mov dx,modem.mddat      ; [19b]


           mov al,ah               ;****
           out dx,al


        mov ax,temp1


           or al,bh                ;****

        out dx,al
        inc dx


           mov al,bl              ;****


        out dx,al
;        mov dx,modem.mdcom      ; [19b]
;        mov al,bl
;        out dx,al
        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 some regs. [rjd]
        push    bx              ; [jrd]
        push    cx              ; [jrd]
        push    dx              ; [jrd]
        push    bp              ; [jrd]
        mov dx,modem.mdcom      ; Get current Line Control Register value.
        in al,dx
        mov bl,al               ; Save it.
;        or ax,80H               ; Turn on to access baud rate generator.
;        out dx,al
;        mov dx,modem.mddat      ; Divisor latch.
;        inc dx

           dec dx                  ;**** mode register

        in al,dx                ; Get hi order byte.
        mov ah,al               ; Save here.
;        dec dx
        in al,dx                ; Get lo order byte.
        push ax
        mov dx,modem.mdcom
        mov al,bl               ; Restore old value.
        out dx,al
        pop ax


           and al,0fh              ;****
           xor ah,ah

;        cmp ax,0FFFFH           ; Who knows what this is.

           cmp al,0ffh             ;****

        je getb2
        mov bx,offset bddat     ; Find rate's offset into table.
        mov cl,0                ; Keep track of index.
getb0:  cmp ax,[bx]
        je getb1
        inc cl
        cmp cl,baudsiz          ; At the end of the list.
        jge getb2
        add bx,2
        jmp getb0
getb1:  mov ch,0
        mov bp,portval
        mov ds:[bp].baud,cx     ; Set baud rate.
        jmp     getb3           ; [jrd]
;;;[jrd]        ret
getb2:  mov ah,prstr
        mov dx,offset erms40
        int dos
getb3:  pop     bp              ; restore regs. [jrd]
        pop     dx              ; [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
        cmp count,0
        jnz prtch2
        jmp rskp                ; No data - check console.
prtch2: mov si,savesi
        lodsb                   ; get a byte
        cmp si,offset source + bufsiz   ; bigger than buffer?
        jb prtch1               ; no, keep going
        mov si,offset source    ; yes, wrap around
prtch1: dec count
        mov savesi,si
        mov dx,count            ; return # of chars in buffer
        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.
        push ax
        mov ax,275              ; # of ms to wait
        call pcwait             ; hold break for desired interval
        pop ax
        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

; Wait for the # of milliseconds in ax
; Thanks to Bernie Eiben for this one.
pcwait  proc    near
        mov     cx,240          ; inner loop counter for 1 millisecond
pcwai1: sub     cx,1            ; inner loop takes 20 clock cycles
        jnz     pcwai1
        dec     ax              ; outer loop counter
        jnz     pcwait          ; wait another millisecond
        ret
pcwait  endp

; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.

POSCUR  PROC    NEAR
        mov ah,2                ; Position cursor.
        mov bh,0
        int bios
        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
        mov dx,offset comptab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp comx               ;  Didn't get a confirm.
         nop
        pop bx
        mov flags.comflg,bl     ; Set the comm port flag.
        cmp flags.comflg,1      ; Using Com 1?
        jne coms0               ; Nope.
        mov ax,offset port1
        mov portval,ax
        mov modem.mddat,MDMDAT1 ; Set COM1 defaults.
        mov modem.mdstat,MDMSTS1
        mov modem.mdcom,MDMCOM1
        mov modem.mddis,MDMINTC
        mov modem.mden,MDMINTO
        mov modem.mdmeoi,EOICOM
        mov modem.mdintv,MDMINTV
        mov brkadr,MDMCOM1
        ret
coms0:  mov ax,offset port2
        mov portval,ax
        mov modem.mddat,MDMDAT2 ; Set COM2 defaults.
        mov modem.mdstat,MDMSTS2
        mov modem.mdcom,MDMCOM2
        mov modem.mddis,MDINTC2
        mov modem.mden,MDINTO2
        mov modem.mdmeoi,EOICOM2
        mov modem.mdintv,MDINTV2
        mov brkadr,MDMCOM2
        ret
comx:   pop bx
        ret
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 VT52 emulation flag.
        ret
vt0:    pop bx
        ret
VTS     ENDP

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
        push es
        cmp portin,0            ; Did we initialize port already? [21c]
        jne serin0              ; Yes, so just leave. [21c]
        cli                     ; Disable interrupts
        cld                     ; Do increments in string operations
        xor ax,ax               ; Address low memory
        mov es,ax
        mov bx,modem.mdintv     ; Save serial card interrupt vector. [19b]
        mov ax,es:[bx]
        mov savsci,ax
        mov ax,offset serint    ; And point it to my routine
        mov es:[bx],ax
        add bx,2                ; Save CS register too. [19b]
        mov ax,es:[bx]
        mov savscs,ax
        mov es:[bx],cs
        mov portin,1            ; Remember port has been initialize.
        call clrbuf             ; Clear input buffer.
        mov ax,modem.mdstat
        mov mst,ax              ; Use this address for status.
        mov ax,modem.mddat
        mov mdat,ax             ; Use this address for data.
        mov al,modem.mdmeoi
        mov mdeoi,al            ; Use to signify end-of-interrupt.
        in al,21H               ; Set up 8259 interrupt controller
        and al,modem.mden       ; Enable INT3 or INT4.
        out 21H,al
        mov dx,modem.mdcom      ; Set up the serial card.

        MOV AL,37H      ;**** RESET MC2661 THROUGH CR4 AND ENABLE TXEN
        OUT DX,AL

;        mov dl,0F9H
;        mov al,1                ; Set up interrupt enable register
;        out dx,al
;        mov dl,0FCH             ; Enable interrupts from serial card
;        mov al,0BH
;        out dx,al
        sti                     ; Allow interrupts
        mov dl,0F8H
        in al,dx
serin0: pop es
        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
        push es                 ; preserve this
        cmp portin,0            ; Reset already?
        je srst1                ; Yes, just leave.
        cli                     ; Disable interrupts
        mov dx,03FbH            ;**** CONTROL REGISTER
        cmp flags.comflg,1      ; Using port 1 ?
        je srst0                ; Yes - continue.
        mov dh,02               ; Set for port 2.
srst0:  mov al,26h                 ;**** DISABLE TXEN
        out dx,al
        in al,21H               ; Interrupt controller
        or al,modem.mddis       ; Inhibit IRQ3 or IRQ4.
        out 21H,al
        xor bx,bx               ; Address low memory
        mov es,bx
        mov bx,modem.mdintv     ; Restore the serial card int vector
        mov ax,savsci
        mov es:[bx],ax
        add bx,2                ; Restore CS too.
        mov ax,savscs
        mov es:[bx],ax
        mov portin,0            ; Reset flag.
        sti
srst1:  pop es
        ret                     ; All done.
SERRST  ENDP

; serial port interrupt routine.  This is not accessible outside this
; module, handles serial port receiver interrupts.

SERINT  PROC  NEAR
        push bx
        push dx
        push ax
        push es
        push di
        push ds
        push bp
        push cx
        cld
        mov ax,seg datas
        mov ds,ax               ; address data segment
        mov es,ax
        mov di,srcpnt           ; Registers for storing data.
        mov dx,mst              ; Asynch status port. [19b]
        in al,dx

;       CALL PRNTAL     ;SEE WHAT STATUS BYTE IS



        test al,MDMINP          ;**** Data available?
        jz retint               ; Nope.
        mov dx,mdat             ; [19b]
        in al,dx
        cmp telflg,0            ; File transfer or terminal mode? [17c]
        jz srint0
        and al,7FH              ; Terminal mode (7 bits only).
srint0: or al,al
        jz retint               ; Ignore nulls.
        mov ah,al
        and ah,7fH              ; strip parity temporarily
        cmp ah,7FH              ; Ignore rubouts, too.
        jz retint
        mov bp,portval
        cmp ds:[bp].floflg,0    ; Doing flow control?
        je srint2               ; Nope.
        mov bx,ds:[bp].flowc    ; Flow control char (BH = XON, BL = XOFF).
        cmp al,bl               ; Is it an XOFF?
        jne srint1              ; Nope, go on.
        mov xofrcv,true         ; Set the flag.
        jmp retint
srint1: cmp al,bh               ; Get an XON?
        jne srint2              ; No, go on.
        mov xofrcv,false        ; Clear our flag.
        jmp retint
srint2: stosb
        cmp di,offset source + bufsiz
        jb srint3               ; not past end...
        mov di,offset source    ; wrap buffer around
srint3: inc count
        cmp ds:[bp].floflg,0    ; Doing flow control?
        je retint               ; No, just leave.
        cmp xofsnt,true         ; Have we sent an XOFF?
        je retint               ; Yes.
        cmp count,mntrgh        ; Past the high trigger point?
        jbe retint              ; No, we're within our limit.
        mov ah,bl               ; Get the XOFF.
        call outchr             ; Send it.
        nop
        nop
        nop                     ; ignore failure.
        mov xofsnt,true         ; Remember we sent it.
retint: mov srcpnt,di
        sti
        mov al,mdeoi            ; [19b]
        out intcon1,al          ; Send End-of-Interrupt to 8259.
        pop cx
        pop bp
        pop ds
        pop di
        pop es
        pop ax
        pop dx
        pop bx
intret: iret
SERINT  ENDP

PRNTAL:
        ;THIS ROUTINE WILL PRINT [AL] ON THE SCREEN
        ;THIS IS HANDY FOR DEBUGGING PURPOSES

        PUSH AX
        PUSH DX
        PUSH AX         ;SAVE STATUS BYTE
        AND AL,0F0H     ;HIGH NIBBLE

        shr al,1
        shr al,1
        shr al,1
        shr al,1

        CMP AL,10       ;IS IT A LET?
        JL CONV1
        ADD AL,7        ;MAKE IT PRINTABLE

CONV1:
        ADD AL,30H      ;MAKE ASCII
        MOV DL,AL
        MOV AH,2
        INT 21H

        POP AX          ;GET LOW NIBBLE
        AND AL,0FH
        CMP AL,10
        JL CONV2
        ADD AL,7        ;MAKE IT PRINTABLE

CONV2:

        ADD AL,30H
        MOV DL,AL

        MOV AH,2
        INT 21H
        MOV DL,20H      ;OUTPUT A SPACE
        MOV AH,2
        INT 21H

        MOV DL,20H
        MOV AH,2
        INT 21H


        POP DX
        POP AX
        RET



; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.

BEEP    PROC    NEAR
        mov al,10110110B        ; Gen a short beep (long one losses data.)
        out timer+3,al          ; Code snarfed from Technical Reference.
        mov ax,533H
        out timer+2,al
        mov al,ah
        out timer+2,al
        in al,port_b
        mov ah,al
        or al,03
        out port_b,al
        sub cx,cx
        mov bl,1
beep0:  loop beep0
        dec bl
        jnz beep0
        mov al,ah
        out port_b,al
        ret
BEEP    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

