home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MS DOS Archives 1
/
MS-DOS_Archives_Volume_One_Walnut_Creek.iso
/
msdos
/
fossil
/
t2kcom52.arc
/
T2KCOMM.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-24
|
65KB
|
2,240 lines
page 58,132
title T2KCOMM - FOSSIL Driver For The Tandy 2000 - v5.2
.186
subttl Overview and History
page
; This program implements the FOSSIL (Fido, Opus, SEAdog Standard
; Interface Layer) communications driver for the Tandy 2000. FOSSIL
; functions 00h - 1Bh, 7Eh, and 7Fh are implemented.
; Written by Rick Moore
; Copyright 1987, 1988 by Solar Wind Computing, ALL RIGHTS RESERVED
; This code may be used and distributed in its unmodified form for ANY
; NONCOMMERCIAL USE WHATEVER. Modified versions of this software are NOT to
; be distributed without the express written consent of the author. You are
; not allowed to sell or otherwise make money from the use of this software
; without specific license from the author. You may contact the author at:
; Solar Wind Computing
; P.O. Box 1204
; Homewood, IL 60430
; You may contact the author with bug reports or suggestions for improvement
; via FidoNet mail at Net 115 Node 333 - Solar Wind Opus for non-commercial
; purposes only.
; History:
; v1.0 - 01/87 REM
; v1.1 - 02/87 REM 1. Added functions 20 and 21.
; 2. Fixed several mites in x-on/x-off logic
; 3. Optimized branch instructions for minimum
; overhead in the interrupt routines. Some
; of the code may look strange at first, but
; the code has been arranged to minimize
; instruction prefetch queue flushing.
; 4. Eliminated dependence on Tandy BIOS int 14h
; by incorporating the code to set the 8253 and
; 8251A in T2KCOMM. This will help minimize
; stack usage from within T2KCOMM, and will
; allow future expansion to support 19200 bps.
; v1.2 - 03/87 REM 1. Fixed the mistake in the implementation of
; (never released) functio 20, in which, due to confusion on
; my part, I did not implement the ability to
; cancel the watchdog function.
; 2. Added full word length, parity, and stop bit
; support to function 0.
; 3. Simplified and improved the transmitter hold
; logic.
; 4. Changed function 7 to return timer parms for
; the PC BIOS interrupt, 1C. This cuts by 80%
; the overhead associated with the timer tick.
; v3.00 - 05/87 REM 1. Added functions 22 and 23, bringing the driver
; up to compliance with Draft 3 of the FOSSIL
; spec.
; 2. Changed naming convention. The first digit of
; the version is the FOSSIL spec level and the
; decimal places represent the release version
; within that spec.
; 3. Completely changed the way parameters are passed
; and returned within the program. As the FOSSIL
; spec has added function, it has become harder
; and harder to keep the required parameters in
; the proper register(s) through the various
; routines. Therefore, all registers except CS
; are stored in a stack frame upon entry to the
; int 14h code. All registers except CS and SS
; will be restored when exiting. Therefore all
; return values must be stored into the stack
; frame before returning.
; 4. Fixed again, and hopefully once and for all, the
; mite in the x-on/x-off logic.
; 5. Added DSR handshaking.
; v3.10 - 06/87 REM 1. Reorganized and optimized the USART interrupt
; handler to insure reliable operation at 19.2kb
; and above.
; 2. Optimized the FOSSIL read and write routines for
; the same reason.
; 3. Swatted more mites.
; v3.20 - 07/87 REM 1. Increased transmit buffer size to 4k. Opus's
; Zmodem routine uses window sizes of 2k, so
; I wanted more of a pad.
; 2. More bulletproofing against lost interrupts
; 3. Added an incredible kluge to make the driver
; completely compatible with the Tandy BIOS. It
; seems that the Tandy int 14 function 3 (status)
; stores the next character available in the
; buffer (if one exists) at a displacement of 6Fh
; in the BIOS Communication Area. The MS/DOS
; device driver for the AUX: device looks for this
; character when the "non-destructive" read
; function is called. Now this driver does the
; same thing as the Tandy BIOS.
; 3.30 - 07/87 REM 1. Fixed brain-damaged logic in the Timer Tick
; Manager routines. Somehow, I copied old code
; back into the source deck. It is back the way
; it was supposed to be all along.
; 2. Corrected function 0Ch to be a non-destructive,
; rather than a destructive read.
; 3.40 - 09/87 REM 1. Eliminated three more lockup conditions.
; 2. Added full Xon/Xoff and CTS/RTS support, in
; both host and remote modes. Now supports the
; "Modem Steady" option at speeds up to 9.6 kbps.
; Special thanks to Vince Perriello for a
; suggestion that really made it simpler.
; 3. Decreased the transmit buffer size back to 1k,
; which seems to work better at lower speeds than
; larger sizes.
; 4.00 - 10/87 REM 1. Driver now fully implements the draft 4 FOSSIL
; spec, including functions 7Eh and 7FH.
; 2. Changed receive mode Xon/Xoff to be controlled
; by AL bit 08h, as specified in draft 4 spec.
; 3. T2KCOMM now returns the overflow, framing error,
; and parity error bits in AH when status is
; returned.
; 4.10 - 10/87 REM 1. Converted to device driver with support for AUX,
; COM1, and FOSSIL$ devices.
; 2. Removed kludge to support Tandy AUX driver from
; "status" FOSSIL BIOS call.
; 5.00 - 11/87 REM 1. Changed the register calling conventions to use
; the draft 5 specs, replacing DS:DX with ES:DX,
; and DS:SI with ES:DI.
; 2. Corrected error in transmit-with-wait and
; transmit-without-wait routines. Now both
; routines take the character to be enqueued from
; the stack frame rather than directly from AL.
; The previous method worked, but only accidently.
; 5.10 - 01/88 REM 1. Fixed errors in both the block read and
; block write routines.
; 5.20 - 02/88 REM 1. Implemented the change to the status call as
; specified in the V5 FOSSIL spec dated 02/11/88:
; Bit 03h of AL always returned set.
; 2. Removed support for status bits not defined by
; FOSSIL V5 spec.
; 3. Corrected version code returned by open.
;
subttl Standard Equates And Macro Definitions
page
code segment public 'code'
assume cs:code, ds:code
org 0000h
include C:\Usr\Include\Bioscall.Asm
include C:\Usr\Include\Doscall.Asm
include C:\Usr\Include\Regframe.Asm
FOSSIL equ 14h ;FOSSIL interrupt number
subttl Device Driver Declarations
page
; Standard request header definition
RequestHeader struc
RHLen db ? ;Length of request header
RHUnit db ? ;Unit number
RHCmd db ? ;Command code
RHStatus dw ? ;Status word
db 9 dup (?)
RHBufAdr dd ? ;I/O buffer address
RHCount dw ? ;I/O count
RequestHeader ends
; Maximum valid command number for device driver commands
MaxCmd equ 12
subttl Device Driver Headers And Command Tables
page
FOSSIL$ dd -1 ;Pointer to next driver
dw 0C000h ;Driver attributes
dw Strategy ;Offset of strategy routine
dw FOS$Int ;Offset of interrupt routine
db 'FOSSIL$ ' ;Device name
CopyMsg db 'Copyright 1987, 1988, Solar Wind Computing,'
db ' ALL RIGHTS RESERVED.',13,10,'$'
even
; COM1 Device driver header
COM1 dd -1 ;Pointer to next driver
dw 08000h ;Driver attributes
dw Strategy ;Offset of strategy routine
dw COM1Int ;Offset of interrupt routine
db 'COM1 ' ;Device name
; AUX Device driver header
AUX dd -1 ;Pointer to next driver
dw 08000h ;Driver attributes
dw Strategy ;Offset of strategy routine
dw AUXInt ;Offset of interrupt routine
db 'AUX ' ;Device name
; FOSSIL$ Command Table
FOS$Tab dw FInit1 ;Device initialization
dw FNop ;Media check (not applicable)
dw FNop ;Build BPB (not applicable)
dw FReadCtl ;Read control string
dw FRead ;Read
dw FReadAhead ;Non-destructive look ahead
dw FInStat ;Input status
dw FInFlush ;Flush input buffer
dw FWrite ;Write
dw FWrite ;Write verify
dw FOutStat ;Output status
dw FOutFlush ;Flush output buffer
dw FWriteCtl ;Write control string
; COM1 and AUX Command Table
COM1Tab dw FInit2 ;Device initialization
dw FNop ;Media check (not applicable)
dw FNop ;Build BPB (not applicable)
dw FCmdErr ;Read control string
dw FRead ;Read
dw FReadAhead ;Non-destructive look ahead
dw FInStat ;Input status
dw FInFlush ;Flush input buffer
dw FWrite ;Write
dw FWrite ;Write verify
dw FOutStat ;Output status
dw FOutFlush ;Flush output buffer
dw FCmdErr ;Write control string
subttl Device Driver Data Areas
page
; I/O Packet Address
PacketAddr dd 0 ;Strategy routine saves header address here
; Driver stack
dw 128 dup (0)
OurStack equ $
subttl Device Driver Strategy Routine
page
Strategy proc far
mov word ptr cs:PacketAddr,bx ;Save request header offset
mov word ptr cs:PacketAddr+2,es ;Save request header segment
ret ;Return to MS/DOS
Strategy endp
subttl FOSSIL$ Device Driver Interrupt Routine
page
FOS$Int proc far
pusha ;Save MS/DOS's registers
mov bx,offset FOS$Tab ;Point to FOSSIL$ command table
xor dx,dx ;Set channel to use
jmp short Interrupt
FOS$Int endp
subttl COM1 Device Driver Interrupt Routine
page
COM1Int proc far
pusha ;Save MS/DOS's registers
mov bx,offset COM1Tab ;Point to COM1 command table
xor dx,dx ;Set channel to use
jmp short Interrupt
COM1Int endp
subttl AUX Device Driver Interrupt Routine
page
AUXInt proc far
pusha ;Save MS/DOS's registers
mov bx,offset COM1Tab ;Point to COM1 command table
xor dx,dx ;Set channel to use
jmp short Interrupt
AUXInt endp
subttl Common Device Driver Interrupt Routine
page
Interrupt proc far
push ds
push es
mov ax,cs ;Set up DS
mov ds,ax
mov cx,offset OurStack ;Set up our stack
mov si,ss ;Save MS/DOS's SS/SP
mov di,sp
mov ss,ax ;Load our SS/SP
mov sp,cx
push si ;Save pointer to MS/DOS's stack
push di
les di,PacketAddr ;Point to request header
mov es:[di].RHStatus,0 ;Zero status word
mov al,es:[di].RHCmd ;Get command
cmp al,MaxCmd ;Too high?
ja BadCmd ;Yes - return error
xor ah,ah ;Convert command to displacement
shl ax,1
add bx,ax ;Add displacement to table base
call word ptr [bx] ;Call appropriate routine
IntExit:
or es:[di].RHStatus,0100h ;Set DONE bit
pop di ;Restore MS/DOS's stack
pop si
mov ss,si
mov sp,di
pop es ;Restore MS/DOS's registers
pop ds
popa
ret ;Return to MS/DOS
BadCmd:
or es:[di].RHStatus,8003h ;Set error + invalid cmd flags
jmp IntExit ;Continue
Interrupt endp
subttl Device Driver NOP Routine
page
FNop proc near
ret ;Return to interrupt routine
FNOP endp
subttl Device Driver Invalid Command Routine
page
FCmdErr proc near
or es:[di].RHStatus,8003h ;Set error + invalid cmd flags
ret ;Return to interrupt routine
FCmdErr endp
subttl Device Driver Read Control String Routine
page
FReadCtl proc near
ret ;Return to interrupt routine
FReadCtl endp
subttl Device Driver Read Routine
page
FRead proc near
mov cx,es:[di].RHCount ;Get I/O count
les di,es:[di].RHBufAdr ;Point to MS/DOS's buffer
FReadAgain:
cmp cx,1 ;One character left to read?
jb FReadExit ;Less than one - all done
je FReadOne ;Yes - use single read
mov ah,18h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
sub cx,ax ;Subtract from number requested
add di,ax ;Add to index into buffer
jmp FReadAgain ;Check for done
FReadOne:
mov ah,02h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
stosb ;Store in MS/DOS's buffer
FReadExit:
les di,PacketAddr ;Point to packet header
ret ;Return to interrupt routine
FRead endp
subttl Device Driver Read-Ahead Routine
page
FReadAhead proc near
mov ah,0Ch ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
cmp ax,-1 ;Anything there?
je FReadAheadBusy ;No - indicate busy
lds si,es:[di].RHBufAdr ;Point to MS/DOS's buffer
mov ds:[si],al ;Store it in MS/DOS's buffer
ret ;Return to interrupt routine
FReadAheadBusy:
or es:[di].RHStatus,0200h ;Indicate Busy
ret ;Return to interrupt routine
FReadAhead endp
subttl Device Driver Input Status Routine
page
FInStat proc near
mov ah,03h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
test ah,mask ARxRdy ;Anything in receive buffer?
jnz FInStatExit ;Yes - leave BUSY flag reset
or es:[di].RHStatus,0200h ;No - set BUSY flag
FInStatExit:
ret ;Return to interrupt routine
FInStat endp
subttl Device Driver Input Flush Routine
page
FInFlush proc near
mov ah,0Ah ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
ret ;Return to interrupt routine
FInFlush endp
subttl Device Driver Write Routine
page
FWrite proc near
mov cx,es:[di].RHCount ;Get I/O count
les di,es:[di].RHBufAdr ;Point to MS/DOS's buffer
FWriteAgain:
cmp cx,1 ;One character left to write?
jb FWriteExit ;Less than one - all done
je FWriteOne ;Yes - use single write
mov ah,19h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
sub cx,ax ;Subtract from number requested
add di,ax ;Add to index into MS/DOS's buffer
jmp FWriteAgain ;Check for done
FWriteOne:
mov al,es:[di] ;Get char from MS/DOS's buffer
mov ah,01h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
FWriteExit:
les di,PacketAddr ;Point to packet header
ret ;Return to interrupt routine
FWrite endp
subttl Device Driver Output Status Routine
page
FOutStat proc near
mov ah,03h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
test ah,mask ATxEmp ;Any room in buffer?
jnz FOutStatExit ;Yes - leave BUSY flag reset
or es:[di].RHStatus,0200h ;No - set BUSY flag
FOutStatExit:
ret ;Return to interrupt routine
FOutStat endp
subttl Device Driver Output Flush Routine
page
FOutFlush proc near
mov ah,09h ;Set FOSSIL function
int FOSSIL ;Call FOSSIL
ret ;Return to interrupt routine
FOutFlush endp
subttl Device Driver Write Control String Routine
page
FWriteCtl proc near
ret ;Return to interrupt routine
FWriteCtl endp
subttl BIOS Comm Equates And Definitions
page
; Equates for 8251A USART
MStatPort equ 00h ;Modem status port
; Bit definitions for MStatPort
MSBits record MACLow:1,MFill:5,MDCD:1,MRI:1
UCtrlPort equ 12h ;8251A control port
; Bit definitions for UCtrlPort
UCBits record UHunt:1,UReset:1,URTS:1,UErrClr:1,UBrk:1,URxEn:1,UDTR:1,UTxEn:1
UStatPort equ 12h ;8251A status port
; Bit definitions for UStatPort
USBits record UDSR:1,UBrkDet:1,UFrmErr:1,UOvrErr:1,UParErr:1,UTxEmp:1,URxRdy:1,UTxRdy:1
UDataPort equ 10h ;8251A data port
; Bit definitions for status returned in AX by the status function
AStatAH record ATimeOut:1,ATxRdy:1,ATxEmp:1,ABrkDet:1,AFrmErr:1,AParErr:1,AOvrErr:1,ARxRdy:1
AStatAL record ADCD:1,Fill:7
; Bit definitions for parms passed in AL to FOSSIL function 0Fh (Flow Control)
FlParm record FlFill:4,FlRXon:1,FlDTR:1,FlRTS:1,FlTXon:1
; Equates for 8253-5 programmable interval timer
PCnt0Port equ 40h ;Timer 0
PCnt1Port equ 42h ;Timer 1
PCnt2Port equ 44h ;Timer 2
PModePort equ 46h ;Mode register
; Equates for 8259A interrupt controller
OCW1A equ 62h ;8259(0) OCW1 port
OCW2A equ 60h ;8259(0) OCW2-3 port
NOPCmd59 equ 40h ;OCW2 for NOP
EOICmd59 equ 62h ;OCW2 for specific EOI for level 2
ISRCmd59 equ 0bh ;OCW3 to return IS reg
; Equates for 80186
EOIReg86 equ 0FF22h ;Address of 80186 EOI register
EOICmd86 equ 000Ch ;Specific EOI command for 80186 level 6
; Equates for ACSII characters
CtlC equ 03h
CtlK equ 0bh
Xon equ 11h
Xoff equ 13h
Magic equ 1954h ;"Magic" value returned by FOSSIL
MaxFun equ 27 ;Maximum function supported
Version equ 5 ;Spec version supported
Revision equ 2 ;Revision level within version
; Miscellaneous equates
ChanFF equ 00FFh ;Channel id for dummy operations
even
TTRoutLim equ 8 ;Number of timer tick routine buckets
TTRoutTab dd TTRoutLim dup (?) ;Timer tick routine table
TTRoutCnt dw 0 ;Count of active timer tick routines
OldInt1C dd 0 ;Original int 1Ch vector
LastCntl db 0 ;Last control byte sent to USART
XChar db 0 ;Handshake character stuffed to transmitter
LastXChar db Xon ;Last handshake character sent
RFlag db 0 ;Receiver flags
; Bit definitions of RFlag
RBits record RCtlChk:1,RCtlRcv:1,ROvr:1
TFlag db 0 ;Transmitter hold flags
; Bit definitions of TFlag
TBits record TXonHld:1,TPrgHld:1
FFlag db 0 ;Flow checking flags
; Bit definitions of FFlag
FBits record FRXon:1,FTXon:1,FRTS:1
; Baud rate multiplier for 8253-5 PIT
even
RateTable label word
dw 6 ;19.2 kbps
dw 3 ;38.4 kbps
dw 416 ;300 bps
dw 208 ;600 bps
dw 104 ;1.2 kbps
dw 52 ;2.4 kbps
dw 26 ;4.8 kbps
dw 13 ;9.6 kbps
even
; User appendage table
UserAppTable dd 64 dup (?) ;Vectors for user functions 80h to BFh
; Buffer sizes
TBufSize equ 1024 ;Transmit buffer size
RBufSize equ 4096 ;Receive buffer size
RBUfLimit equ 3072 ;Receive handshake point
TBufFirst dw 0 ;Index to first character in xmit buffer.
TBufNext dw 0 ;Index to first free space in xmit buffer.
TBufCnt dw 0 ;Number of characters in xmit buffer.
TBuf db TBufSize dup (?) ;Xmit buffer
RBufFirst dw 0 ;Index to first character in recv buffer
RBufNext dw 0 ;Index to first free space in recv buffer
RBufCnt dw 0 ;Number of characters in rec. buffer
RBuf db RBufSize dup (?) ;Recv buffer
; Fossil information area
even
Info equ $
InfoSize dw 20 ;Size of info area
InfoVer db Version ;Fossil major version
InfoRev db Revision ;Fossil revision level
InfoId dd 0 ;Pointer to ID string
InfoRSize dw RBufSize ;Receive buffer size
InfoRFree dw 0 ;Receive buffer free space
InfoTSize dw TBufSize ;Transmit buffer size
InfoTFree dw 0 ;Transmit buffer free space
InfoScrW db 80 ;Video screen width
InfoScrH db 24 ;Video screen height
InfoBaud dw 0 ;Actual computer to modem baud rate
IDString db 'T2KCOMM, Version 5.2, by Rick Moore',0
subttl BIOS Comm Interrupt Handler
page
.sall
even
Int14 proc far
jmp short Int14a ;Jump around prefix
db 0,0,0,0
dw Magic ;FOSSIL "magic" value
db MaxFun ;Highest function value
db 0
Int14a: sti ;Allow interrupts
and ah,ah ;High bit on?
js DispatchUserApp ;Yes - dispatch user appendage
cmp ah,MaxFun ;Regular FOSSIL function?
ja UserAppMgr ;No - go check for appendage function
pusha ;Set up register frame
push ds
push es
cld ;Clear the direction flag
mov bp,sp ;BP points to register frame
mov bx,cs ;Set DS = CS
mov ds,bx
; Determine type of request and call the appropriate routine
mov si,ax ;Get function number
shr si,8 ;Shift into low byte
shl si,1 ;Convert into displacement
call word ptr FuncTab[si] ;Call appropriate routine
pop es ;Restore caller's registers
pop ds
popa
Exit14: iret ;Return to point of interrupt
DispatchUserApp:
cmp ah,0BFh ;Appendage number out of range?
ja Exit14 ;Yes - just return
push bp ;Save bp
sub sp,8 ;Reserve room for stack frame
mov bp,sp ;Point to stack frame
push ax ;Save registers used
push bx
mov bx,[bp]+8 ;Relocate saved bp in stack frame
mov [bp],bx
mov bl,ah ;Get copy of appendage number
shl bl,1 ;Convert to displacement
shl bl,1 ; (Discarding two high order bits)
xor bh,bh ;Convert to word
add bx,offset UserAppTable ;Add table base to displacement
mov ax,cs:[bx] ;Get appendage offset
mov [bp]+2,ax ;Store in stack frame
mov ax,cs:[bx]+2 ;Get appendage segment
mov [bp]+4,ax ;Store in stack frame
mov [bp]+6,offset Exit14 ;Set up appendage return address
mov [bp]+8,cs
pop bx ;Restore registers used
pop ax
pop bp
FarRet: ret ;Dispatch user appendage
subttl Install and remove user appendages
page
;
; This routine installs/removes user appendages into/from the FOSSIL
; dispatcher. Appendage numbers 80h through BFh are supported.
;
; Entry conditions:
; AH = 7Eh - Install an appendage
; 7Fh - Remove an appendage
; AL = Appendage number
; ES = Segment of appendage entry point
; DX = Offset of appendage entry point
; Exit conditions:
; AH = 1954h
; BL = Appendage number (same as AL on entry)
; BH = 00h - Operation unsuccessful
; 01h - Operation successful
;
UserAppMgr:
cmp ah,7Eh ;Check for valid appendage
jb Exit14 ; manager function
cmp ah,7Fh
ja Exit14
push ax ;Save ax
and al,al ;Verify that appendage number
jns UserAppErr ; is within range
cmp al,0BFh
ja UserAppErr
mov bl,al ;Get copy of appendage number
shl bl,1 ;Convert to displacement
shl bl,1 ; (Discarding two high order bits)
xor bh,bh ;Convert to word
add bx,offset UserAppTable ;Add table base to displacement
cmp ah,7Eh ;Install request?
jne UserAppRmv ;No - must be a remove request
cmp cs:[bx],offset FarRet ;Verify that entry in question
jne UserAppErr ; is not already in use
mov ax,cs
cmp cs:[bx]+2,ax
jne UserAppErr
cli ;No interrupts
mov cs:[bx],dx ;Insert offset of user appendage
mov cs:[bx]+2,es ;Insert segment of user appendage
sti ;Interrupts ok
mov bh,1 ;Indicate success
jmp short UserAppExit ;Get out
UserAppRmv:
cmp cs:[bx],dx ;Verify that entry points to the
jne UserAppErr ; routine we are trying to remove
mov ax,es
cmp cs:[bx]+2,ax
jne UserAppErr
cli ;No interrupts
mov cs:[bx],offset FarRet ;Insert default offset
mov cs:[bx]+2,cs ;Insert default segment
sti ;Interrupts ok
mov bh,1 ;Indicate success
jmp UserAppExit ;Get out
UserAppErr:
xor bh,bh ;Indicate failure
UserAppExit:
pop ax ;Restore ax
mov bl,al ;Return appendage number assigned
mov ax,Magic ;Indicate the FOSSIL is installed
jmp Exit14 ;Get out
Int14 endp
Functab dw offset CSetChan ;Function 00h
dw offset CTxWait ;Function 01h
dw offset CRxWait ;Function 02h
dw offset CStatus ;Function 03h
dw offset COpen ;Function 04h
dw offset CClose ;Function 05h
dw offset CDTR ;Function 06h
dw offset TTickParm ;Function 07h
dw offset CFlushOut ;Function 08h
dw offset CPurOut ;Function 09h
dw offset CPurIn ;Function 0Ah
dw offset CTxNowait ;Function 0Bh
dw offset CRxNowait ;Function 0Ch
dw offset KRxNowait ;Function 0Dh
dw offset KRxWait ;Function 0Eh
dw offset CFlowCtl ;Function 0Fh
dw offset CCtlChk ;Function 10h
dw offset DSetCurLoc ;Function 11h
dw offset DGetCurLoc ;Function 12h
dw offset DPutDos ;Function 13h
dw offset CWatchDog ;Function 14h
dw offset DPutBios ;Function 15h
dw offset TTickMgr ;Function 16h
dw offset Reboot ;Function 17h
dw offset CBlockRead ;Function 18h
dw offset CBlockWrite ;Function 19h
dw offset CBreak ;Function 1Ah
dw offset CInfo ;Function 1Bh
subttl Set channel parameters
page
CSetChan proc near
;
; Sets channel parameters
;
; Entry conditions:
; [bp].RegAL = channel parameters
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = channel status
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CSetChanFF ;Yes - just return
mov dx,OCW1A ;Point to PIC(0) OCW1 port
cli ;No interrupts
xor bl,bl ;Clear work area
xor ax,ax ;Clear ax
mov al,[bp].RegAL ;Get parms from reg frame
mov InfoBaud,ax ;Store port info in info area
mov ah,al ;Make copy of parms
and ah,mask CRParity ;Mask out all but parity bits
shl ah,1 ;Convert to USART command bits
or bl,ah ;Set bits in new USART command
mov ah,al ;Make copy of parms
and ah,mask CRWordLen ;Mask out all but word length bits
shl ah,2 ;Convert to USART command bits
or bl,ah ;Set bits in new USART command
mov ah,al ;Make copy of parms
and ah,mask CRStopBit ;Mask out all but # stop bits
shl ah,5 ;Convert to USART command bits
or ah,42h ;Set bits 6 and 1 in USART command
or ah,bl ;Leave new USART command in ah
mov bl,al ;Makecopy of parms
and bl,mask CRRate ;Mask off all but rate bits
xor bh,bh ;Zero high order byte
shr bx,4 ;Convert to word displacement
add bx,offset RateTable ;Point to baud rate table
mov bx,0[bx] ;Get baud rate divisor
mov dx,UCtrlPort ;Point to USART control port
xor al,al ;Clear USART out with 3 nulls
call PutWait
call PutWait
call PutWait
mov al,mask UReset ;Reset the USART
call PutWait
mov dx,PModePort ;Point to PIT mode port
mov al,76h ;Get PIT command
call PutWait ;Write to PIT
mov dx,PCnt1Port ;Point to PIT counter 1
mov al,bl ;Get low order byte of divisor
call PutWait ;Write to PIT
mov al,bh ;Get high order byte of divisor
call PutWait ;Write to PIT
mov dx,UCtrlPort ;Point to USART control port
mov al,ah ;Get USART mode byte
cli ;No interrupts
call PutWait
mov al,mask URTS + mask UDTR + mask URxEn + mask UTxEn
mov LastCntl,al ;Save USART control byte
or al,mask UErrClr ;Reset USART error flags
call PutWait ;Send it to USART control port
sti ;Allow interrupts
jmp CStatus ;Get status and return
CSetChanFF:
ret ;Return to caller
CSetChan endp
subttl Send a character to channel with wait
page
CTxWait proc near
;
; Enqueues a character into a channel's transmit buffer. Waits
; forever for space in the buffer.
;
; Entry conditions:
; [bp].RegAL = character to enqueue
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = channel status
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CTxWtChanFF ;Yes - just return
CTxWtAgain:
cmp TBufCnt,TBufSize ;Is the transmit buffer full?
jae CTxWtAgain ;Yes - continue on
mov bx,TBufNext ;Point to next free char
mov al,[bp].RegAL ;Get char from stack frame
mov TBuf[bx],al ;Place char into buffer
inc TBufCnt ;Increment transmit buffer count
call TxEnable ;Enable transmitter
cmp bx,TBufSize-1 ;Past end?
jae CTxWaitWrap ;Yes - go wrap
inc TBufNext ;Save pointer to next free char
jmp short CStatus ;Get status and return
CTxWaitWrap:
mov TBufNext,0 ;Save pointer to next free char
jmp short CStatus ;Get status and return
CTxWtChanFF:
ret ;Return to caller
CTxWait endp
subttl Receive a character from a channel with wait
page
CRxWait proc near
;
; Dequeues a character from a channel's receive buffer. Waits
; forever for a character.
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAL = character
; [bp].RegAH = 00h
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CRxWtRet ;Yes - just return
CRxWtAgain:
cmp RBufCnt,0 ;Anything in the buffer?
je CRxWtAgain ;No - keep trying
mov bx,RBufFirst ;Point to next recvd char
mov al,byte ptr RBuf[bx] ;Get it into al
xor ah,ah ;Clear ax
mov [bp].RegAX,ax ;Store in register frame
dec RBufCnt ;Decrement buffer count
cmp RBufCnt,RBufLimit ;Below cutoff point
ja CRxWtNoRFlow ;No - continue
call RxUnhold ;Yes - unhold receiver
CRxWtNoRFlow:
cmp bx,RBufSize-1 ;Past end?
jae CRxWtWrap ;Yes - go wrap buffer
inc RBufFirst ;Save the new start pointer
CRxWtRet:
ret ;Return to caller
CRxWtWrap:
mov RBufFirst,0 ;Save the new start pointer
ret ;Return to caller
CRxWait endp
subttl Get the status of a channel
page
CStatus proc near
;
; Gets a channel's status
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = channel status
;
cmp [bp].RegDX,ChanFF ;Dummy channel
je CStatRet ;Yes - just return
mov dx,0008h ;Initialize status
cmp RBufCnt,0 ;Anything in receiver buffer
je CStatTxRdy ;No - continue
or dh,mask ARxRdy ;Yes - indicate RxRDY
CStatTxRdy:
cmp TBufCnt,TBufSize ;Buffer full?
jae CStatDCD ;Yes - continue
or dh,mask ATxEmp ;No - indicate transmit hold reg empty
cmp TBufCnt,0 ;Anything in transmit buffer?
jne CStatOvr ;Yes - continue
or dh,mask ATxRdy ;No - indicate transmit shift reg empty
CStatOvr:
test RFlag,mask ROvr ;Has an overrun occurred?
jz CStatDCD ;No - continue
or dh,AOvrErr ;Indicate overrun
and RFlag,not mask ROvr ;Reset overrun indicator
CStatDCD:
cli ;No interrupts
mov al,LastCntl ;Get USART command
or al,mask UErrClr ;Reset USART error flags
out UCtrlPort,al ;Send command to USART
in al,MStatPort ;Get modem status
and al,mask MDCD ;Strip off all but DCD
xor al,mask MDCD ;Reverse the bit
shl al,6 ;Shift into high order bit
sti ;Interrupts ok
or dl,al ;Save in DL
mov [bp].RegAX,dx ;Store status in register frame
CStatRet:
ret ;Return to caller
CStatus endp
subttl Open a channel
page
COpen proc near
;
; Open a channel
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = 1954h
; [bp].RegBL = Highest function supported (not including 7E/7F)
; [bp].RegBH = FOSSIL spec revision supported
;
cmp [bp].RegDX,ChanFF ;Dummy channel
je COpenExit ;Yes - just return success
call CClose ;Reset the channel
mov [bp].RegAL,01h ;Set AL in stack frame
call CDTR ;Cancel any flow control
COpenExit:
mov [bp].RegAX,Magic ;Put return values in reg frame
mov [bp].RegBL,MaxFun ;Highest function supported
mov [bp].RegBH,Version ;Spec revision supported
ret ;Return to caller
COpen endp
subttl Close a channel
page
CClose proc near
;
; Close a channel
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CCloseRet ;Yes - just return
xor bx,bx
cli ;No interrupts
mov TBufFirst,bx ;Zero transmit buffer pointers
mov TBufNext,bx
mov TBufCnt,bx
mov RBufFirst,bx ;Zero receive buffer pointers
mov RBufNext,bx
mov RBufCnt,bx
mov RFlag,bl ;Reset receiver flags
mov TFlag,bl ;Reset transmitter hold flags
mov FFlag,bl ;Reset flow control flags
mov XChar,bl ;Cancel any pending Xoff
mov al,LastCntl ;Get current USART command
and al,not mask UBrk ;Reset break bit
or al,mask URTS + mask UTxEn + mask URxEn ;Set up USART command
mov LastCntl,al ;Save new USART command
or al,mask UErrCLr ;Set error clear bit
out UCtrlPort,al ;Send new command to USART
push [bp].RegAX ;Save AX from stack frame
mov [bp].RegAL,0 ;Zero AL in stack frame
sti ;Allow interrupts
call CFlowCtl ;Cancel any flow control
pop [bp].RegAX ;Restore AX in stack frame
CCloseRet:
ret ;Return to caller
CClose endp
subttl Toggle a channel's DTR line
page
CDTR proc near
;
; Toggle a channel's DTR line
;
; Entry conditions:
; [bp].RegAH = 06h
; [bp].RegAL = 00h - Lower DTR
; Not 00h - Raise DTR
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel
je CDTRRet ;Yes - just return
cli ;No interrupts
mov al,LastCntl ;Get last control byte
cmp [bp].RegAL,00h ;Request to lower DTR?
jne CDTRSet ;No - check for set
and al,not mask UDTR ;Mask DTR off
jmp short CDTRExit ;Go output control byte
CDTRSet:
or al,mask UDTR ;Mask DTR on
CDTRExit:
out UCtrlPort,al ;Send control byte to USART
mov LastCntl,al ;Save new control byte
nop ;Wait a bit
nop
sti ;Interrupts ok
CDTRRet:
ret ;Return to caller
CDTR endp
subttl Return timer parameters
page
TTickParm proc near
;
; This routine returns information about this machine's interval timer
;
; Entry conditions
; none
; Exit conditions:
; [bp].RegAL = timer tick interrupt #
; [bp].RegAH = Ticks per second
; [bp].RegDX = milliseconds per tick
;
mov [bp].RegAL,1Ch ;Timer interrupt #
mov [bp].RegAH,20 ;Ticks per second
mov [bp].RegDX,50 ;Millisecs per tick
ret ;Return to caller
TTickParm endp
subttl Flush a channel's transmit buffer
page
CFlushOut proc near
;
; Flush a channel's transmit buffer
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; none
;
CFlushAgain:
cmp [bp].RegDX,ChanFF ;Dummy channel
je CFlushRet ;Yes - just return
cmp TBufCnt,0 ;Is transmit buffer empty?
jne CFlushAgain ;No - wait for it to be
CFlushRet:
ret ;Yes - return to caller
CFlushOut endp
subttl Purge a channel's transmit buffer
page
CPurOut proc near
;
; Purges (discards) a channel's transmit buffer
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel
je CPurOutRet ;Yes - just return
xor bx,bx
cli ;Disable interrupts
mov TBufFirst,bx ;Zero transmitter buffer pointers
mov TBufNext,bx
mov TBufCnt,bx
sti ;Enable interrupts
CPurOutRet:
ret
CPurOut endp
subttl Purge a channel's receive buffer
page
CPurIn proc near
;
; Purges (discards) a channel's receive buffer
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CPurInRet ;Yes - just return
xor bx,bx
cli ;No interrupts
mov RBufFirst,bx ;Zero receiver buffer pointers
mov RBufNext,bx
mov RBufCnt,bx
call RxUnhold ;Cancel any handshaking holds
sti ;Interrupts ok
CPurInRet:
ret
CPurIn endp
subttl Send a character to a channel without wait
page
CTxNowait proc near
;
; Enqueue a character into the a channel's transmit buffer. Returns
; without waiting if buffer is full.
;
; Entry conditions:
; [bp].RegAL = character to enqueue
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = 0000h - operation was not successful
; 0001h - operation was successful
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CTxNwRet ;Yes - just return
cmp TBufCnt,TBufSize ;Is the transmit buffer full?
jae CTxNwNoroom ;Yes - go indicate failure
mov bx,TBufNext ;Point to next free char
mov al,[bp].RegAL ;Get char from stack frame
mov TBuf[bx],al ;Place char into buffer
mov [bp].RegAX,1 ;Set successful return code
inc TBufCnt ;Increment xmit buffer count
call TxEnable ;Enable transmitter
cmp bx,TBufSize-1 ;Past end?
jae CTxNwWrap ;Yes - go wrap buffer
inc TBufNext ;Save pointer to next free char
CTxNwRet:
ret ;Return to caller
CTxNwNoroom:
mov [bp].RegAX,0 ;Set unsuccessful return code
ret ;Return to caller
CTxNwWrap:
mov TBufNext,0 ;Save pointer to next free char
ret ;Return to caller
CTxNowait endp
subttl Receive a character from a channel without wait
page
CRxNowait proc near
;
; Peeks for a character from a channel's receive buffer
; and returns it. Returns without waiting if buffer
; is empty. The character is not removed from the receive
; buffer.
;
; Entry conditions:
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = FFFFh (operation was not successful)
; [bp].RegAL = char recvd (operation was successful)
; [bp].RegAH = 00h (operation was successful)
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CRxNwRet ;Yes - just return
cmp RBufCnt,0 ;Anything in the buffer?
je CRxNwEmpty ;No - go indicate failure
mov bx,RBufFirst ;Point to next recvd char
mov al,byte ptr RBuf[bx] ;Get it into register
xor ah,ah ;Clear ah
mov [bp].RegAX,ax ;Store result in register frame
CRxNwRet:
ret ;Return to caller
CRxNwEmpty:
mov [bp].RegAX,0FFFFh ;Set unsuccessful return code
ret ;Return to caller
CRxNowait endp
subttl Receive character from keyboard without wait
page
KRxNowait proc near
;
; Receives a character from the keyboard. Returns immediately
; if a character is not available.
;
; Entry conditions:
; none
; Exit conditions:
; [bp].RegAX = FFFFh (operation was not successful)
; [bp].RegAL = ASCII value (operation was successful)
; [bp].RegAH = keyboard scan code (operation was successful)
;
mov ah,KeybdScan ;Set BIOS function
int BiosKeybd ;Call the BIOS
jnz KRxNwReady ;If char present, get out
mov ax,0FFFFh ;Indicate no char present
KRxNwReady:
mov [bp].RegAX,ax ;Put result in register frame
ret ;Return to caller
KRxNowait endp
subttl Receive character from keyboard with wait
page
KRxWait proc near
;
; Receives a character from the keyboard. Waits forever
; for a character.
;
; Entry conditions:
; none
; Exit conditions:
; [bp].RegAL = ASCII value
; [bp].RegAH = keyboard scan code
;
mov ah,KeybdRead ;Set BIOS function
int BiosKeybd ;Call the BIOS
mov [bp].RegAX,ax ;Put result in register frame
ret ;Return to caller
KRxWait endp
subttl Set/reset flow control
page
CFlowCtl proc near
;
; Enable/disable flow control. The Tandy 2000 implements
; CTS handshaking in hardware. There is no way to disable
; this handshaking, as the 8251A USART will simply not transmit
; data until CTS is true. DSR/DTR handshaking is not supported
; at this time.
;
; Entry conditions:
; [bp].RegAL = xxxxxxx0 - Disable transmit Xon/Xoff
; xxxxxxx1 - Enable transmit Xon/Xoff
; xxxxxx0x - Disable CTS/RTS
; xxxxxx1x - Enable CTS/RTS
; xxxx0xxx - Disable receive Xon/Xoff
; xxxx1xxx - Enable receive Xon/Xoff
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CFlRet ;Yes - just return
cli ;No interrupts
mov al,LastCntl ;Copy USART command
test [bp].RegAL,mask FlTXon ;Enable transmit Xon/Xoff?
jz CFlTXonOff ;No - disable it
or FFlag,mask FTXon ;Yes - set indicator
jmp short CFlRXon ;Check receiver Xon/Xoff
CFlTXonOff:
and FFlag,not mask FTXon ;Reset indicator
test TFlag,mask TXonHld ;Has transmitter been held?
jz CFlRXon ;Check receiver Xon/Xoff
and TFlag,not mask TXonHld ;Cancel existing hold
or al,mask UTxEn ;Enable transmitter
CFlRXon:
test [bp].RegAL,mask FlRXon ;Enable receive Xon/Xoff?
jz CFlRXonOff ;No - disable it
or FFlag,mask FRXon ;Set indicator
mov XChar,0 ;Cancel any pending Xoff
jmp short CFlRTS ;Check RTS/CTS
CFlRXonOff:
and FFlag,not mask FRXon ;Reset indicator
cmp LastXChar,Xoff ;Was Xoff sent?
jne CFlRTS ;No - check RTS/CTS
mov XChar,Xon ;Stuff Xon into transmitter
or al,mask UTxEn ;Enable transmitter
CFlRTS:
test [bp].RegAL,FlRTS ;Enable RTS handshaking?
jz CFlRTSOff ;No - disable RTS handshaking
or FFlag,mask FRTS ;Yes - set indicator
jmp short CFlOut ;Output USART control byte (if needed)
CFlRTSOff:
and FFlag,not mask FRTS ;Reset indicator
or al,mask URTS ;Set RTS bit in USART control byte
CFlOut:
cmp al,LastCntl ;Has USART control byte changed?
je CFlEXit ;No - don't need to send it
out UCtrlPort,al ;Send it to the USART
mov LastCntl,al ;Save new USART control byte
nop ;Wait a bit
nop
CFlExit:
sti ;Interrupts ok
CFlRet:
ret ;Return to caller
CFlowCtl endp
subttl Set/reset CTL-C/CTL-K checking
page
CCtlChk proc near
;
; Enable/disable Ctl-C/Ctl-K checking; logout and clear current
; Ctl-C/Ctl-K mask. Also enable/disable the transmitter
;
; Entry conditions:
; [bp].RegAL = xxxxxxx0 - Disable Ctl-C/Ctl-K checking
; xxxxxxx1 - Enable Ctl-C/Ctl-K checking
; xxxxxx0x - Disable transmitter
; xxxxxx1x - Enable transmitter
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = 0000h - Ctl-C/Ctl-K not received since last logout
; 0001h - Ctl-C/Ctl-K received since last logout
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CCtlRet ;Yes - just return
test [bp].RegAL,02h ;Disable transmitter?
jz CCtlTxEn ;No - enable it
or TFlag,mask TPrgHld ;Indicate program hold
jmp short CCtlCont ;Go output control byte
CCtlTxEn:
and TFlag,not mask TPrgHld ;Indicate no programmer hold
call TxEnable ;Enable transmitter
CCtlCont:
test [bp].RegAL,01h ;Start Ctl-C/Ctl-K checking?
cli ;No interrupts
jz CCtlOff ;No - stop Ctl-C/Ctl-K checking?
or RFlag,mask RCtlChk ;Indicate checking
jmp short CCtlLog
CCtlOff:
and RFlag,not mask RCtlChk ;Indicate no checking
jmp short CCtlClr ;Clear things up
CCtlLog:
mov [bp].RegAX,0 ;Zero mask
test RFlag,mask RCtlRcv ;Has a break been received?
jz CCtlClr ;No - leave mask zero
mov [bp].RegAX,1 ;Yes - indicate break to caller
CCtlClr:
and RFlag,not mask RCtlRcv ;Zero break flag
sti ;Interrupts ok
CCtlRet:
ret ;Return to caller
CCtlChk endp
subttl Set cursor location
page
DSetCurLoc proc near
;
; Set current cursor position
;
; Entry conditions
; [bp].RegDH = row
; [bp].RegDL = column
; Exit conditions:
; none
;
mov dx,[bp].RegDX ;Get parms from register frame
mov ah,VideoSetCurPos ;Set BIOS function
xor bh,bh ;Select page 0
int BiosVideo ;Call BIOS
ret ;Return to caller
DSetCurLoc endp
subttl Get cursor location
page
DGetCurLoc proc near
;
; Get current cursor position
;
; Entry conditions
; none
; Exit conditions:
; [bp].RegDH = row
; [bp].RegDL = column
;
mov ah,VideoGetCurPos ;Set BIOS function
xor bh,bh ;Select page 0
int BiosVideo ;Call BIOS
mov [bp].RegDX,dx ;Store results in register frame
ret ;Return to caller
DGetCurLoc endp
subttl Put character to display using ANSI.SYS
page
DPutDos proc near
;
; Put a character to the display via ANSI.SYS
;
; Entry conditions
; [bp].RegAL = char to output
; Exit conditions:
; none
mov dl,[bp].RegAL ;Get char from register frame
dir_con_io ;Write char using ANSI
ret ;Return to caller
DPutDos endp
subttl Watch channel and reboot if CD lost
page
CWatchDog proc near
;
; This routine adds/deletes a small routine to/from the timer tick. This
; routine checks for CD on a channel. If CD is false, the system is
; rebooted.
;
; Entry conditions:
; [bp].RegAL = 00h - Disable watchdog
; [bp].RegAL = 01h - Enable watchdog
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel
je CWatchDogRet ;Yes - just return
push [bp].RegES ;Save current stack frame values
push [bp].RegDX
push [bp].RegAX
mov [bp].RegES,cs ;Get segment of watchdog routine
mov [bp].RegDX,offset WatchDog ;Get offset
call TTickMgr ;Install tick routine
pop [bp].RegAX ;Restore caller's stack frame
pop [bp].RegDX
pop [bp].RegES
CWatchDogRet:
ret ;Return to caller
CWatchDog endp
subttl Put char to console bypassing DOS
page
DPutBios proc near
;
; Put a character to the display bypassing DOS
;
; Entry conditions
; [bp].RegAL = char to output
; Exit conditions:
; none
;
mov al,[bp].RegAL
mov ah,VideoWrTty ;Set BIOS function
int BiosVideo ;Call BIOS
ret ;Return to caller
DPutBios endp
subttl Manage the timer tick chain
page
TTickMgr proc near
;
; This routine adds and deletes routines from the timer tick chain.
; A maximum of eight routines are supported. If a request is
; made to delete a routine already present in the chain, the
; old version is deleted, and the new one added to the top of
; the chain. The chain of routines is maintained as a push/pop
; stack.
;
; Entry conditions:
; [bp].RegAL = 00h - Delete a routine from the chain
; [bp].RegAL = 01h - Add a routine to the chain
; [bp].RegES = Segment of routine
; [bp].RegDX = Offset of routine
; Exit conditions:
; [bp].RegAX = 0000h - Operation was successful
; FFFFh - Operation was unsuccessful
;
test [bp].RegAL,1 ;Request to add routine?
jz TTDelete ;No - must be delete
call TTFind ;It is add - check for duplicate
and ax,ax ;Check return code
js TTAdd ;No dups - just add it
call TTSnip ;Remove old version of routine
and ax,ax ;Everything ok?
js TTErr ;No - error
TTAdd:
call TTPush ;Push new routine pointer
jmp short TTRet ;Get out
TTDelete:
call TTFind ;Find requested routine
and ax,ax ;Found?
js TTErr ;No - error
call TTSnip ;Yes - snip it from chain
TTRet:
mov [bp].RegAX,ax ;Put return code in stack frame
ret ;Return to caller
TTErr:
mov [bp].RegAX,0FFFFh ;Indicate failure
ret ;Return to caller
TTickMgr endp
subttl Find a routine in the timer tick chain
page
TTFind proc near
mov bx,offset TTRoutTab ;Get routine table address
xor si,si ;Zero the table index
mov cx,TTRoutCnt ;Get number of routines
and cx,cx ;Are there any?
jz TTFindNotFound ;No - skip the search
TTFindLoop:
mov ax,[bp].RegES ;Get segment of search argument
cmp ax,[bx][si]+2 ;Equal to segment of table element?
jne TTFindIncr ;No - try next table element
mov ax,[bp].RegDX ;Get offset of search argument
cmp ax,[bx][si] ;Equal to offset of table element?
je TTFindFound ;Yes - exit loop
TTFindIncr: ;No - keep trying
add si,4 ;Increment the table index
loop TTFindLoop ;If more table elements, try again
TTFindNotFound:
mov ax,0FFFFh ;No luck - set no-hit return code
jmp short TTFindRet ;Go return to caller
TTFindFound: ;Search successful - convert index
mov ax,TTRoutCnt ; to relative table entry index
sub ax,cx
TTFindRet:
ret ;Return to caller
TTFind endp
subttl Snip a routine from the timer tick chain
page
TTSnip proc near
mov cx,TTRoutCnt ;Get the number of routines
and cx,cx ;Anything to delete?
jz TTSnipErr ;No - error
cmp ax,TTRoutCnt-1 ;Trying to delete past last routine?
ja TTSnipErr ;Yes - error
dec cx ;Convert to displacement
jz TTSnipDecr ;No pop needed for last routine
sub cx,ax ;Calculate number of moves
mov bx,offset TTRoutTab ;Point base to routine table
shl ax,2 ;Convert routine number to an offset
add bx,ax ; and add it to the base
xor si,si ;Zero the loop index
cli ;No interrupts
TTSnipLoop: ;Pop remaining routines
mov ax,[bx][si]+6 ;Move segment
mov [bx][si]+2,ax
mov ax,[bx][si]+4 ;Move offset
mov [bx][si],ax
add si,4 ;Increment index
loop TTSnipLoop ;Repeat for remaining routines
TTSnipDecr:
dec TTRoutCnt ;Decrement routine counter
sti ;Allow interrupts
xor ax,ax ;Set successful return code
ret ;Return to caller
TTSnipErr:
mov ax,0FFFFh ;Set unsuccessful return code
ret ;Return to caller
TTSnip endp
subttl Push a new routine onto the timer tick chain
page
TTPush proc near
cmp TTRoutCnt,TTRoutLim ;Chain full?
je TTPushErr ;Yes - error
mov bx,offset TTRoutTab ;Set base to start of table
mov cx,TTRoutCnt ;Get number of routines
and cx,cx ;Are there any?
jz TTPushNew ;No - just add new routine
mov si,cx ;Get starting index
dec si ;Convert to displacment
shl si,2
cli ;No interrupts
TTPushLoop:
mov ax,[bx][si]+2 ;Move segment
mov [bx][si]+6,ax
mov ax,[bx][si] ;Move offset
mov [bx][si]+4,ax
sub si,4 ;Decrement index
loop TTPushLoop ;Repeat for remaining routines
TTPushNew:
mov ax,[bp].RegES ;Insert segment of new routine
mov [bx]+2,ax
mov ax,[bp].RegDX ;Insert offset of new routine
mov [bx],ax
inc TTRoutCnt ;Increment routine counter
sti ;Allow interrupts
xor ax,ax ;Indicate success
ret ;Return to caller
TTPushErr:
mov ax,0FFFFh ;Indicate failure
ret ;Return to caller
TTPush endp
subttl Reboot the system
page
Reboot proc near
;
; This routine reboots the system using the BIOS reboot interrupt.
; The T2K only supports hard reboots.
;
; Entry conditions:
; none
; Exit conditions:
; none
;
int BiosBoot ;Reboot via BIOS
Reboot endp
subttl Dequeue a block of characters from a channel
page
CBlockRead proc near
;
; This routine dequeues a block of characters from a channel's
; receive buffer into a user provided buffer. Up to 64k
; characters may be dequeued with one call. The routine
; only as many characters as the buffer contains at the time
; of the call.
;
; Entry conditions:
; [bp].RegCX = Maximum number of characters to dequeue
; [bp].RegDX = channel
; [bp].RegES = Segment of user's buffer
; [bp].RegDI = Offset of user's buffer
; Exit conditions:
; [bp].RegAX = Number of characters dequeued into
; the user's buffer
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CBlkRdRet ;Yes - just return
mov bx,RBufCnt ;Get number of chars in buffer
and bx,bx ;Buffer empty?
jz CBlkRdEmpty ;Yes - get out
cmp bx,[bp].RegCX ;Greater than number requested?
jbe CBlkRdNotAll ;No - can only move what we have
mov bx,[bp].RegCX ;Yes - move number requested
CBlkRdNotAll:
mov cx,RBufSize ;Get length of buffer
sub cx,RBufFirst ;Calculate length to end of buffer
mov es,[bp].RegES ;Point to user's buffer
mov di,[bp].RegDI
mov si,offset RBuf ;Point to receive buffer
add si,RBufFirst ;Point to first char to be moved
cmp cx,bx ;Greater than number requested?
jb CBlkRd2Moves ;No - will take two moves
mov cx,bx ;Yes - only one move needed
rep movsb ;Move chars to user buffer
sub si,offset RBuf ;Convert to displacement within buffer
cmp si,RBufSize ;At end of buffer?
jb CBlkRdDone ;No - finish up
xor si,si ;Yes - wrap
jmp short CBlkRdDone ;Finish up
CBlkRd2Moves:
mov ax,cx ;Save move length
rep movsb ;Move first chars to user buffer
mov cx,bx ;Get total move length
sub cx,ax ;Decrement by number already moved
mov si,offset RBuf ;Point to start of buffer
rep movsb ;Move remaining number of chars
sub si,offset RBuf ;Convert to displacement within buffer
CBlkRdDone:
mov RBufFirst,si ;Set pointer to next char in buffer
cmp RBufCnt,RBufLimit ;Below cutoff point
ja CBlkRdNoRFlow ;No - continue
call RxUnhold ;Yes - unhold receiver
CBlkRdNoRFlow:
sub RBufCnt,bx ;Decrement count of chars in buffer
CBlkRdEmpty:
mov [bp].RegAX,bx ;Return total number moved
CBlkRdRet:
ret ;Return to caller
CBlockRead endp
subttl Enqueue a block of characters on a channel
page
CBlockWrite proc near
;
; This routine enqueues a block of characters from a user
; provided buffer into a channel's transmit buffer. Up to 64k
; characters may be enqueued with one call. The routine only
; enqueues as many characters as there are free in the transmit
; buffer at the time of the call.
;
; Entry conditions:
; [bp].RegCX = Maximum number of characters to enqueue
; [bp].RegDX = channel
; [bp].RegES = Segment of user's buffer
; [bp].RegDI = Offset of user's buffer
; Exit conditions:
; [bp].RegAX = Number of characters enqueued into
; the transmit buffer
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CBlkWrRet ;Yes - just return
mov bx,TBufSize ;Get length of buffer
mov cx,bx ;Save a copy
sub bx,TBufCnt ;Calculate free space
jz CBlkWrFull ;Is buffer full?
cmp bx,[bp].RegCX ;Greater than number requested?
jbe CBlkWrNotAll ;No - can only move what we can hold
mov bx,[bp].RegCX ;Yes - move number requested
CBlkWrNotAll:
sub cx,TBufNext ;Calculate length to end of buffer
mov dx,cs ;Point to transmit buffer
mov es,dx
mov di,offset TBuf
add di,TBufNext ;Point to free space
mov ds,[bp].RegES ;Point to user's buffer
mov si,[bp].RegDI
cmp cx,bx ;Greater than number requested?
jb CBlkWr2Moves ;No - will take two moves
mov cx,bx ;Yes - only one move needed
rep movsb ;Move chars to user buffer
sub di,offset TBuf ;Convert to displacement within buffer
cmp di,TBufSize ;At end of buffer?
jb CBlkWrDone ;No - finish up
xor di,di ;Yes - wrap
jmp short CBlkWrDone ;Finish up
CBlkWr2Moves:
mov ax,cx ;Save move length
rep movsb ;Move first chars to user buffer
mov cx,bx ;Get total move length
sub cx,ax ;Decrement by number already moved
mov di,offset TBuf ;Point to start of buffer
rep movsb ;Move remaining number of chars
sub di,offset TBuf ;Convert to displacement within buffer
CBlkWrDone:
mov ds,dx ;Restore DX
mov TBufNext,di ;Point to free space
add TBufCnt,bx ;Increment count of chars in buffer
CBlkWrFull:
mov [bp].RegAX,bx ;Return total number moved
call TxEnable ;Enable the transmitter
CBlkWrRet:
ret
CBlockWrite endp
subttl Start/Stop sending a break on a channel
page
CBreak proc near
;
; This routine starts/stops sending a break (continuous spacing) on
; the specified channel.
;
; Entry conditions:
; [bp].RegAL = 00h - Stop sending break
; 01h - Start sending break
; [bp].RegDX = channel
; Exit conditions:
; none
;
cmp [bp].RegDX,ChanFF ;Dummy channel?
je CBreakRet ;Yes - just return
cli ;No interrupts
mov al,LastCntl ;Get current USART command
test [bp].RegAX,01h ;Request to start sending break?
jz CBreakStop ;No - then stop sending break
and TFlag,not mask TXonHld ;Cancel existing hold
or al,mask UBrk ;Set break bit
and al,not mask UTxEn ;Reset transmit enable bit
jmp short CBreakOut ;Go send it to to the USART
CBreakStop:
and al,not mask UBrk ;Reset break bit
or al,mask UTxEn ;Set transmit enable bit
CBreakOut:
out UCtrlPort,al ;Send command to USART
mov LastCntl,al ;Save new USART command
nop ;Wait a bit
nop
sti ;Allow interrupts
CBreakRet:
ret ;Return to caller
CBreak endp
subttl Return information about the driver
page
CInfo proc near
;
; This routine fills a user-supplied buffer with various information
; concerning the internal status and capabilities of the FOSSIL.
;
; Entry conditions:
; [bp].RegCX = Length of user-supplied buffer
; [bp].RegES = Segment of user-supplied buffer
; [bp].RegDI = Offset of user supplied buffer
; [bp].RegDX = channel
; Exit conditions:
; [bp].RegAX = Number of characters actually placed into
; the user-supplied buffer
;
mov ax,RBufSize ;Calculate receive buffer free space
sub ax,RBufCnt
mov InfoRFree,ax ;Store it in info area
mov ax,TBufSize ;Calculate transmit buffer free space
sub ax,TBufCnt
mov InfoTFree,ax ;Store it in info area
mov si,offset Info ;Set up source pointer
mov es,[bp].RegES ;Set up destination pointer
mov di,[bp].RegDI
mov cx,InfoSize ;Get length of info area
cmp cx,[bp].RegCX ;Is user's buffer large enough?
jae CInfoMove ;Yes - move entire area
mov cx,[bp].RegCX ;No - just move number requested
CInfoMove:
mov [bp].RegAX,cx ;Store number moved in stack frame
rep movsb ;Move info area to user buffer
ret ;Return to caller
CInfo endp
subttl Output to a port and wait a while
page
PutWait proc near
out dx,al ;Write to specified port
nop
nop
nop
ret ;Return to caller
PutWait endp
subttl Enable the USART transmitter
page
TxEnable proc near
mov al,LastCntl ;Copy last USART command
or al,mask UTxEn ;Set transmitter enable bit
cmp al,LastCntl ;Any change?
je TxEnableRet ;No - no action needed
pushf ;Save interrupt state
cli ;No interrupts
out UCtrlPort,al ;Send command to USART
mov LastCntl,al ;Save USART command
nop ;Wait a bit
nop
popf ;Restore interrupt state
TxEnableRet:
ret ;Return to caller
TxEnable endp
subttl Cancel receiver holds
page
RxUnhold proc near
mov al,LastCntl ;Copy last USART command
test FFlag,mask FRXon ;Receive Xon/Xoff active?
jz RxUnhOut ;No - output USART command
cmp LastXChar,Xon ;Was Xon already sent?
je RxUnhOut ;Yes - Xon not needed
mov XChar,Xon ;Feed Xon to transmitter
or al,mask UTxEn ;Enable transmitter
RxUnhOut:
or al,mask URTS ;Raise RTS
cmp al,LastCntl ;Anything changed?
je RxUnhRet ;No - don't output USART command
pushf ;Save interrupt state
cli ;No - interrupts
out UCtrlPort,al ;Output USART command
mov LastCntl,al ;Save new USART command
nop ;Wait a bit
nop
popf ;Restore interrupt state
RxUnhRet:
ret ;Return to caller
RxUnhold endp
subttl Carrier watchdog routine
page
WatchDog proc far
push ax ;Save caller's register
in al,MStatPort ;Get modem status
test al,mask MDCD ;CD true?
jz WatchDogRet ;Yes - continue
int BiosBoot ;No - reboot system
WatchDogRet:
pop ax ;Restore caller's register
ret ;Return to caller
WatchDog endp
subttl 8251A USART Interrupt Handler
page
Int72 proc near
sti ;Allow interrupts
push ax ;Save caller's regsisters
push bx
push ds
mov ax,cs ;Set DS to CS
mov ds,ax
Repoll: ;Determine source of interrupt
in al,UStatPort ;Get USART status
test al,mask URxRdy ;Rx ready?
jnz RxInt ;Yes - go process receiver interrupt
test al,mask UTxRdy ;Tx ready?
jz Int72Ret ;No - get out
test LastCntl,mask UTxEn ;Transmitter enabled?
jz Int72Ret ;No - get out
jmp TxInt ;Yes - process transmitter interrupt
Int72Ret:
; Issue EOI to reset IS bit in 8259A. Also, check 8259A for
; more interrupts at this level in 80186 - if none pending,
; then issue EOI in 80186
cli ;No interrupts
mov al,EOICmd59 ;Set OCW2 to specific EOI for level 2
out OCW2A,al ;Output OCW2 to PIC(0)
nop
nop
mov al,ISRCmd59 ;Set OCW3 to return IS reg
out OCW2A,al ;Output OCW3
nop
nop
xchg bx,dx ;Save dx
mov dx,EOIReg86 ;Point to 80186 EOI register
in al,OCW2A ;Get PIC(0) in-service register
or al,al ;Any other interrupts pending?
jnz NoEOI86 ;Yes - don't clear 80186
mov ax,EOICmd86 ;Get non-specific EOI for 80186
out dx,ax ;Clear 80186 interrupt controller
NoEOI86:
xchg bx,dx ;Restore dx
pop ds ;Restore previous context
pop bx
pop ax
iret ;Return to point of interrupt
page
; Process Receiver Interrupt
;
RxInt:
in al,UDataPort ;Get data
test RFlag,mask RCtlChk ;Trapping Ctl-C/Ctl-K?
jnz RxChkCtl ;Yes - check for break
RxInt1:
test FFlag,mask FTXon ;Transmit Xon/Xoff active?
jnz RxTFlow ;Yes - go check for Xon/Xoff
RxInt2:
mov bx,RBufNext ;bx := next space in buffer
mov byte ptr RBuf[bx],al ;Place data into buffer
cmp RBufCnt,RBufSize ;Room for data in buffer?
jae RxOverrun ;No - Indicate overrun
inc RBufCnt ;Increment # of chars in buffer
cmp RBufCnt,RBufLimit ;Receiver past handshake point?
jbe RxNoRFlow ;Yes - go do handshake
mov al,LastCntl ;Copy last USART control byte
test FFlag,mask FRXon ;Receive Xon/Xoff active?
jz RxRFlowRTS ;No - check RTS handshaking
cmp LastXChar,Xoff ;Xoff already sent
je RxRFlowRTS ;Yes - don't send another
mov XChar,Xoff ;Feed Xoff to transmitter
or al,mask UTxEn ;Enable transmitter
RxRFlowRTS:
test FFlag,mask FRTS ;RTS handshaking active?
jz RxRFlowOut ;No - output USART control byte
and al,not mask URTS ;Lower RTS
RxRFlowOut:
cmp al,LastCntl ;Has anything changed?
je RxNoRFlow ;No - no need to do anything
mov LastCntl,al ;Save new USART control byte
out UCtrlPort,al ;Output control byte to USART
RxNoRFlow:
cmp bx,RBufSize-1 ;Past end of the buffer?
jnb RxWrap ;Yes - go wrap buffer
inc RBufNext ;Increment buffer index
jmp Repoll ;Check for more work
RxChkCtl:
cmp al,CtlC ;Ctl-C?
je RxSetMask ;Yes - treat specially
cmp al,CtlK ;Ctl-K?
jne RxInt1 ;No - go buffer char
RxSetMask:
or RFlag,mask RCtlRcv ;Indicate break received
jmp Repoll ;Don't buffer char
RxTFlow:
cmp al,Xon ;Xon?
jne RxChkXoff ;No - continue checking
and TFlag,not mask TXonHld ;Yes - tell xmitter to proceed
call TxEnable ;Enable transmitter
jmp Repoll ;Don't buffer Xon
RxChkXoff:
cmp al,Xoff ;Xoff?
jne RxInt2 ;No - try to buffer char
or TFlag,mask TXonHld ;Yes - tell xmitter to hold it
jmp Repoll ;Don't buffer Xoff
RxOverrun:
or RFlag,mask ROvr ;Indicate overrun
jmp Repoll
RxWrap:
mov RBufNext,0 ;Zero buffer index
jmp Repoll ;Check for more work
page
; Process transmitter interrupt
;
;
; Buffer contains data - output a byte to the USART
;
TxInt: cmp XChar,0 ;Need to send a flow control char?
jne TxSendXChar ;Yes - send it
cmp TBufCnt,0 ;Anything in buffer?
je TxShutoff ;No - shut off transmitter
cmp TFlag,0 ;Transmitter held?
jne TxShutoff ;Yes - shut off transmitter
mov bx,TBufFirst ;BX points to next char to be sent
mov al,TBuf[bx] ;Get data from buffer
out UDataPort,al ;Send data
dec TBufCnt ;Decrement buffer count
cmp bx,TBufSize-1 ;Past end?
jnb TxWrap ;Yes - wrap buffer
inc TBufFirst ;Increment buffer index
jmp Repoll ;Check for RxRdy
TxWrap:
mov TBufFirst,0 ;Zero buffer index
jmp Repoll ;Check for RxRDY
TxSendXChar:
mov al,XChar ;Get the handshake character to send
out UDataPort,al ;Send it to the USART
mov LastXChar,al ;Save last handshake character
mov XChar,0 ;Clear the handshake character
jmp Repoll ;Check for RxRdy
TxShutoff:
mov al,LastCntl ;Get last USART command
and al,not mask UTxEn ;Reset TxEnable bit
out UCtrlPort,al ;Output to USART
mov LastCntl,al ;Save last USART command
nop ;Wait a bit
nop
jmp Repoll ;Check for RxRdy
Int72 endp
subttl Timer tick routine
page
Int1C proc near
push ds ;Save affected regs
push bx
push cx
mov cx,cs ;Set data segment
mov ds,cx
mov cx,TTRoutCnt ;Get number of routines
and cx,cx ;Are there any?
jz Int1CSkip ;No - just return
mov bx,offset TTRoutTab ;Point to routine table
Int1CLoop:
call dword ptr [bx] ;Call the routine
add bx,4 ;Point to next routine
loop Int1CLoop ;Continue if any more routines
Int1CSkip:
pop cx ;Pop affected regs
pop bx
pop ds
jmp dword ptr cs:OldInt1C ;jump to BIOS tick handler
Int1C endp
subttl Initialization Routines
page
FInit1 proc near
mov word ptr InfoID,offset IDString ;Place address of ID string
mov word ptr InfoID+2,cs ; into information area
;
; Initialize the extended dispatcher address table
;
mov bx,offset UserAppTable ;Point to table
mov dx,offset FarRet ;Get address of iret instruction
mov cx,64 ;Set up initialization loop
InitLoop:
mov [bx],dx ;Save offset in table entry
mov [bx]+2,ds ;Save segment
add bx,4 ;Point to next entry
loop InitLoop ;Repeat for all 64 entries
push ds ;Save DS
cli ;No interrupts
;
; Install FOSSIL BIOS
;
mov cx,offset Int14 ;Set up offset of new comm BIOS
mov dx,cs ;Set up segment of new comm BIOS
xor ax,ax
mov ds,ax ;Point to Int 14h vector
mov si,14h*4
mov ds:[si],cx ;Insert new Int 14h vector
mov ds:[si]+2,dx
mov si,53h*4 ;Point to Int 53h vector
mov ds:[si],cx ;Insert new Int 53h vector
mov ds:[si]+2,dx
;
; Install new USART handler
;
mov cx,offset Int72 ;Set up offset of new USART handler
mov si,72h*4 ;Point to Int 72h vector
mov ds:[si],cx ;Insert new Int 72h vector
mov ds:[si]+2,dx
;
; Install timer tick manager
;
mov si,1Ch*4 ;Point to timer tick vector
mov ax,ds:[si] ;Get current tick offset
mov word ptr cs:OldInt1C,ax ;Save current tick offset
mov ax,ds:[si]+2 ;Get current tick segment
mov word ptr cs:OldInt1C+2,ax ;Save current tick segment
mov cx,offset Int1C ;Point to our tick routine
mov ds:[si],cx ;Insert new Int 1Ch vector
mov ds:[si]+2,dx
sti ;Enable interrupts
pop ds ;Restore DS
;
; Set end of driver address in request header
;
mov word ptr es:[di].RHBufAdr,offset FInit1
mov word ptr es:[di].RHBufAdr+2,cs
;
; Initialize the pointers to the secondary device driver headers
;
mov word ptr FOSSIL$,offset COM1 ;Store offset
mov word ptr FOSSIL$+2,cs ;Store segment
mov word ptr COM1,offset AUX ;Store offset
mov word ptr COM1+2,cs ;Store segment
;
; Init port 0 to 2400 8 N 1
;
xor ah,ah ;Set FOSSIL function
mov al,0a3h ;Set port parameters
xor dx,dx ;Set port number
int FOSSIL ;Call FOSSIL
;
; Let the user know everything is OK and exit
;
mov dx,offset InstMsg
call prtmsg ;Print installed message
;
; Print copyright message
;
mov dx,offset CopyMsg
call PrtMsg
ret ;Return to interrupt routine
FInit1 endp
FInit2 proc near
;
; Set end of driver address in request header
;
mov word ptr es:[di].RHBufAdr,offset FInit1
mov word ptr es:[di].RHBufAdr+2,cs
ret ;Return to interrupt routine
FInit2 endp
subttl Message Routine
page
PrtMsg proc near
put_string
ret
PrtMsg endp
InstMsg db 'T2KCOMM FOSSIL Driver, v5.2',13,10,'$'
code ends
subttl Symbol table
end