; ===========================================================================
; FOSSIL.ASM - Fossil Comunications Driver, Christopher Robert Evans
; ------------ Fido technical document FSC-0015, obsoletes FSC-0008
; fossil com driver for citadel
; Type MAKE FOSSIL to assemble program
; ===========================================================================

Compnext      dd 0ffff0000h
Comdevattr    dw 1000000000000100b 
Comstrategy   dw offset _c_strategy
Cominterrupt  dw offset _c_interrupt
Com_device    db 'COM     ' ; Blank-padded device (or 10-byte block device sub-unit number)
; Jump table 
comtable      db 9
              dw cs:popen      ; 0 - initialize driver
              dw cs:com_err     ; 1 - media change check 
              dw cs:com_err     ; 2 - build BPB
              dw cs:com_err     ; 3 - IOCTL string output
              dw cs:com_err     ; 4 - input
              dw cs:com_err     ; 5 - nondestructive input
              dw cs:com_err     ; 6 - input status
              dw cs:com_err     ; 7 - input flush
              dw cs:com_err     ; 8 - output
              dw cs:com_err     ; 9 - output w/ verify

XFOSSIL:
              ; filler for alignment
              dw offset cs:popen        ; open port with params
              dw offset cs:pclose    ; close port
;              dw offset cs:ring_detect   ; is the RI line active?
;              dw offset cs:have_carrier  ; is the CD line active?
;              dw offset cs:mi_ready      ; do we have stuff waiting?
;              dw offset cs:ib_flush      ; flush the input buffer
;              dw offset cs:get_input     ; get the next thing waiting
;              dw offset cs:put_output    ; send this character...
;              dw offset cs:set_dtr       ; raise or drop it
;              dw offset cs:ob_flush      ; flush output buffer
;              dw 118 dup (0)          ; 128 total entries reserved

com1            EQU 03f8h
com2            EQU 02f8h
com3            EQU 03e8h
com4            EQU 02e8h
irq4            EQU 4
irq3            EQU 3
commbufsize     EQU 2048

oldint14        dd ?
sio_mode        db 0
ports           dw 0
portsactive     dw 0
portsallocated  dw 0
pinit           db 0
mport           dw 0
mports          dw 0
mbaud           dw 0
stops           db 0
mparity         db 0
cCTS            db 0
dLEN            db 0
fossilvers      dw 0158h

banner db 'Portions (c)1989,90 David Nugent & Unique Computing Pty Ltd.',0ffh,0ffh
       db '         (C) 1987, VEP Software, Naugatuck, CT 06770. All rights reserved.',0ffh
       db '         (C) 1988, Rick Moore,  Homewood,  IL, 60430. All rights reserved.',0ffh
       db 0

notloaded_msg   db 'There is already abother FOSSIL loaded.',0ffh,0
prevbnu_msg     db 'Previous BNU in memory.',0ffh,0
resident_msg    db 'Communications driver installed.', 0ffh,0
incompatible_msg db 'Incompatible driver version.',0ffh,0

ports_msg       db '     Ports Found: ',0
ports_active    db '     Ports Active: ', 0
ports_allocated db '     Ports Allocated: ',0
; Requested FOSSIL parameters with ports still active.
; Communications driver not yet installed.
; Invalid command line option specified.
; No diagnostic module.
; DOS memory allocation failure - aborting.
; Communications driver successfully unloaded.
; INT 14H vector is not currently active.
; Recapture not necessary. - existing BNU driver in use.
; Unable to recapture vector 14H - BNU driver not present.
; Recapture of vector 14H successful
; API's installed (VFOSSIL?) - can't unload BNU yet.
; Reboot failure - unable to reboot system.
; Error in requested carrier watch command - aborted.
; Carrier watch enabled.Carrier watch disabled.
; Cannot unload driver if installed from CONFIG.SYS.
; Can't expand TX/RX buffer size beyond original size.
; Unable to unload: Unload other resident programs first.
; Problem initialising FOSSIL driver
; Insufficient number of available ports
; No COM ports found - BNU not loaded!

combuffer  db commbufsize dup(01)
tail       db 0
head       db 0

; ===========================================================================
is_ring proc far
; FOSSIL does not provide for RI tracking
; ===========================================================================
         xor ax, ax
         ret
is_ring endp

; ===========================================================================
mi_ready   proc far
; ===========================================================================
         cmp [cs:pinit], 1
         jne no_hc

         mov ah, 3
         mov dx, [cs:mport]
         int 14h

         test ah, 1
         jz no_hc

         mov ax, 1
         ret
mi_ready   endp

; ===========================================================================
set_dtr  proc far
; ===========================================================================
         cmp [cs:pinit], 1
         jne no_sd

        ; mov al, [setit]
         mov ah, 6
         mov dx, [cs:mport]
         int 14h

no_sd:   ret
set_dtr  endp

; ===========================================================================
c_flush  proc far
; ===========================================================================
         cmp [cs:pinit], 1
         jne nonflsh

         ; Flush the input/output buffers
         mov  cs:[head], al
         mov  cs:[tail], al

         mov ah, 0ah
         mov dx, [cs:mport]
         int 14h

         mov ah, 8
         mov dx, [cs:mport]
         int 14h

nonflsh:
         ret
c_flush  endp

; ===========================================================================
c_carrier proc far
; ===========================================================================
         cmp [cs:pinit], 1
         jne no_hc
 
         mov ah, 3
         mov dx, [cs:mport]
         int 14h

         test al, 80h
         jz no_hc

         ; have carrier...
         mov ax, 1
         ret
no_hc:   xor ax, ax
         ret
c_carrier endp

; ===========================================================================
c_read  proc far
; ===========================================================================
     cmp  [cs:pinit], 1
     jne  _getinx
     mov  al, cs:sio_mode
     or   al, al
     jz   _bcom_mode
          _sio_in cs:mport, 0
     jmp  _getinx
_bcom_mode:
          mov ah, 2
          mov dx, [cs:mport]
          int 14h
_getinx:
     ret
c_read  endp

; ===========================================================================
c_write  proc far
; ===========================================================================
     cmp  [cs:pinit], 1
     jne  _putx
     mov  bl, cs:sio_mode
     or   bl, bl
     jz   _bcom_mode2
          _sio_out cs:mport, 0, 0
     jmp  _putx
_bcom_mode2:
          mov ah, 1
          mov dx, [cs:mport]
       ;  mov al, [char]
          int 14h
_putx:
     ret
c_write  endp

; ===========================================================================
int14   proc far
; ===========================================================================
        cli
        cld
        mov  bx, cs
        mov  ds, bx
_14handler:
        cmp  ah, 00
        jne  _ichktx
        ; Set the BaudRate 
        ; AL=BBBPPSXX
;Bits        [7:5] 000 = 19200, 001 = 38400, 010 = 300, 011 = 600, 100 = 1200   
;                  101 = 2400, 110 = 4800, 111 = 9600,
;Parity:     [4:3] 00 or 10 = none, 01 = odd, 11 = even.
;StopBits:   [2:2] 0 = 1, 1 = 2
;CharLength: 5 bits plus value [1:0]
;Support for [4:0] = 00011 required of driver, others optional
        ; DX = port 
        mov  ax, 0  ; status bits
        jmp  eoi14
_ichktx:     ; Transmit Character
        cmp  ah, 01
        jne  eoi14
        ; al = char

        mov  ax, 0  ; status bits
        jmp  eoi14
eoi14:
        mov  al, 20h   ; port 20h, 8259-1 int command
        out  20h, al   ;  al = 20h, end of interrupt
        sti
        iret
orgint14:
        call dword ptr cs:oldint14
        sti
        iret
_c_strategy:
        mov  word ptr [cs:reqpktptr], bx
        mov  word ptr [cs:reqpktptr+2], es
        retf
    ;    mov ds, ax
    ;    mov byte ptr ds:[417h], 0
    ;    int 20h
    ;    ret
_c_interrupt:
        push es
        push bx
        les  bx, [cs:reqpktptr]
        or   word ptr es:[bx+3], 100h  ; set done flag
        pop  bx
        pop  es
        retf
int14   endp

; ===========================================================================
f_status proc far
; ===========================================================================
       _print ports_msg, 1
       mov  ax, ports
       call putnum
       _newline
       _print ports_active, 1
       mov  ax, portsactive
       call putnum
       _newline
       _print ports_allocated, 1
       mov  ax, portsallocated
       call putnum
       _newline
       ret
f_status endp

; ===========================================================================
chkfossil proc far
; ===========================================================================
       cld
     ;  mov  ax, 3514h
     ;  int  21h
       mov  ax, 14h
       call getvector
       mov  word ptr oldint14, bx
       mov  word ptr oldint14+2, es
       ; detect fossil
       cmp  word ptr es:[bx+6], 1954h 
       je   fossilexists
       mov  ah, 0BCh
       mov  dx, 1954h
       int  11h 
       cmp  ax, 1954h
       jne  prevbnu
fossilexists:
       ; _print  notloaded_msg, 1
       mov  ax, 1
       jmp  _fossilx
prevbnu:
       ; _print  prevbnu_msg, 1
       mov  ax, 2
       jmp  _fossilx
_fossilx:
       ret
chkfossil endp

; ===========================================================================
initports proc far
; ===========================================================================
        ; initialize serial ports
        int  11h
        shr  ax, 9
        and  ax, 7   ; save bits 11-9
        mov  cx, ax
        cmp  cx, 20
        jbe  short pinitcom
             mov   cx, 1
             mov   ax, cx
pinitcom:
        mov  cs:mports, ax
initcom:

        push cx
        _echo 'C'
        _echo 'O'
        _echo 'M'
        mov  ax, cx
        call putnum
        _newline
        pop  cx
        push cx
        mov  ax, 0a3h   ; 2400,n,8,1
        mov  dx, cx
        int  14h
        pop  cx
        loop initcom
        ;
	mov [cs:mport], dx
        mov [cs:mbaud], bx
        mov [cs:stops], cl
        mov [cs:mparity], ch
        mov [cs:cCTS], al
        mov [cs:dLEN], ah
	mov ah, 4
	xor bx, bx
	int 14h
	cmp ax, 1954h
	jne no_init
        mov [cs:pinit], 1
        ; set baud and stuff (always set 8,n,1 - FOSSIL may not support
        ; other than that, and Citadel never asks for other than that)
        mov ax, [cs:mbaud]
        cmp ax, 2
        jbe is_300
        cmp ax, 3
	je is_600
        cmp ax, 4
	je is_1200
        cmp ax, 5
	je is_2400
        cmp ax, 6
	je is_4800
        cmp ax, 7
	je is_9600
        cmp ax, 8
	je is_19200
; 38400 is as high as fossil supports...
	mov al, 00100011b
	jmp short set_baud
is_300:
	mov al, 01000011b
	jmp short set_baud
is_600:
	mov al, 01100011b
	jmp short set_baud
is_1200:
	mov al, 10000011b
	jmp short set_baud
is_2400:
	mov al, 10100011b
	jmp short set_baud
is_4800:
	mov al, 11000011b
	jmp short set_baud
is_9600:
	mov al, 11100011b
	jmp short set_baud
is_19200:
	mov al, 00000011b
set_baud:                 ; and stuff
	mov ah, 0
        mov dx, [cs:mport]
	int 14h
; set CTS
        xor ax, ax
        mov al, [cs:cCTS]
	shl ax, 1
	mov ah, 0fh
	int 14h
no_init:
        ret
initports endp

; ===========================================================================
f_active proc far
; ===========================================================================
    ;   mov  ax, 2514h   ; 0000:(al*4)
    ;   int  21h
    mov  ax, 14h
    lea  dx, int14
    push cs
    pop  ds
    call setvector
f_active endp

com_err proc far

      ret
com_err endp

; ===========================================================================
pclose proc far
; ===========================================================================
        cmp  [cs:pinit], 1
        jne  no_cp
        mov  ah, 5
        mov  dx, [cs:mport]
        int  14h
        mov  [cs:pinit], 1
no_cp:  ret
pclose endp

; ===========================================================================
popen proc far
; proc init_port port:word, baud:word, stops:word, parity:word, len:word, cCTS:word
; DX = PORT , 0 = COMM1,      1 = COMM2,      2 = COMM3,      3 = COMM4
;	Baud	0 = 110,	1 = 150,	2 = 300,	3 = 600,
;		4 = 1200,	5 = 2400,	6 = 4800,	7 = 9600,
;		8 = 19200,	9 = 38400,	A = 57600,	B = 115200
;	Stops	0 = 1 stop bit, 1 = 2 stop bits
;	Parity	0 = none,	1 = odd,	2 = none,	3 = even
;	Len	0 = 5 bits,	1 = 6 bits,	2 = 7 bits,	3 = 8 bits
;	cCTS	0 = no check,	1 = check CTS on output
; ===========================================================================
       push ds
       push cs
       pop  ds

       call initports
       call chkfossil
       or   ax, ax
       jnz  f_abort
            call f_active
            _print resident_msg, 1
            call f_status
 ;          mov  dx, FossilSize
 ;          mov  ax, 3100h
 ;          int  21h
            clc
       jmp  f_initx
f_abort:

       stc
f_initx:
       pop  ds
       ret
popen endp

FossilSize EQU $-1
