home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
tpdoskermit.zip
/
async.sal
< prev
next >
Wrap
Text File
|
1991-04-18
|
16KB
|
742 lines
; ASYNC.SAL Driver for RS232 fra Turbo Pascal V4
; Version 2.0
; Date: 87-11-19, 20:10
saljmp short
salcmp unsigned
salmac := mov &-,&+
include pascal.mac
buffers struc
PortNr dw ?
IntNr dw ?
oldModemCntrReg db ?
oldLevel db ?
oldVector dd ?
Inx dw ?
R_Buf2 dw ?
OutX dw ?
SizeX dw ?
LimitX dw ?
InT dw ?
OutT dw ?
T_Buf2 dw ?
SizeT dw ?
Send_T dw ?
Show_X dw ?
Show_X2 dw ?
Toggle_Xoff dd ?
RLS_user dd ?
MODEM_user dd ?
Ctrl_P db ?
UseTInt db ?
HostX db ?
Bfull db ?
AutoX db ?
AltX db ?
Xoff1C db ?
Xoff2C db ?
Xon1C db ?
Xon2C db ?
Line_Status db ?
MODEM_Status db ?
WaitTX db ?
Int_Mask db ?
buffers ends
DXofs MACRO ofs
mif ofs
ife ofs - 1
inc dx
else
ife ofs + 1
dec dx
else
add dx,ofs
endif
endif
endif
ENDM
InPort MACRO ofs
dx := [bx.PortNr]
DXofs <ofs>
in al,dx
ENDM
OutPort MACRO ofs
dx := [bx.PortNr]
DXofs <ofs>
out dx,al
ENDM
InPOfs MACRO ofs
DXofs <ofs>
in al,dx
ENDM
OutPOfs MACRO ofs
DXofs <ofs>
out dx,al
ENDM
LineContrReg = 3 ; (* to specify format of transmitted data *)
LowBaudRateDiv = 0 ; (* lower byte of divisor to select baud rate *)
HighBaudRateDiv = 1 ; (* higher byte of divisor *)
LineStatusReg = 5 ; (* holds status info on the data transfer *)
ReceiverReg = 0 ; (* received CHAR is in this register *)
TransmitReg = 0 ; (* CHAR to send is to put in this reg *)
IntEnableReg = 1 ; (* to enable the selected interrupt *)
IntIdentReg = 2 ; (* to identify the interrupt *)
ModemContrReg = 4 ; (* controls the interface to a modem *)
ModemStatusReg = 6 ; (* holds status of line (BREAK etc.) *)
Icntrlw2 = 20h ;Interrupt controller
SEOI1 = 64h ;EOI for COM1
SEOI2 = 63h ;EOI for COM2
FALSE = 0
TRUE = 1
RLSint = 6
RDRint = 4
THREint = 2
MODEMint = 0
DATA SEGMENT WORD PUBLIC
ASSUME DS:DATA
EXTRN RS_BufPtr:WORD
EXTRN RS_TimeOut:WORD
DATA ENDS
CODE SEGMENT BYTE PUBLIC
ASSUME CS:CODE
public Rs_Com4int
Rs_Com4int proc far
push ax
push bx
mov bx,offset DATA:rs_bufptr[12]
jmp short comcont
public rs_com3int
rs_com3int proc far
push ax
push bx
mov bx,offset DATA:rs_bufptr[8]
jmp short comcont
public rs_com2int
rs_com2int proc far
push ax
push bx
mov bx,offset DATA:rs_bufptr[4]
jmp short comcont
public rs_com1int
rs_com1int proc far
push ax
push bx
mov bx,offset DATA:rs_bufptr[0]
comcont:
push ds
mov ax, DATA
mov ds,ax
ASSUME DS:DATA
mov bx,[bx]
; Reset Video TimeOut Count
rs_timeout := 0
; STI ;Enable int's
push cx
push dx
push di
push si
push es
repeat_int:
CLI
InPort IntIdentReg ;Hvorfor er jeg her?
if al = RDRint then
call ReadInt
jmp repeat_int
endif
if al = THREint then ;TX int
call SendNext ;Restart
jmp repeat_int
endif
if al = RLSint then
InPOfs <LineStatusReg - IntIdentReg>
and al,1Eh ;Keep OE(2),PE(4),FE(8) and BI(10)
or [bx.Line_Status],al
jmp repeat_int
endif
if al = MODEMint then
InPOfs <ModemStatusReg-IntIdentReg> ;Restart async chip
or [bx.MODEM_Status],al
if word ptr [bx].MODEM_user <> 0 then
push bx
push ds
call dword ptr [bx+MODEM_user]
pop ds
pop bx
endif
jmp repeat_int
endif
InPOfs <ModemStatusReg-IntIdentReg> ;Restart async chip
or [bx.MODEM_Status],al
jmp $+2
InPOfs <LineStatusReg-ModemStatusReg>
and al,1Eh ;Keep OE(2),PE(4),FE(8) and BI(10)
or [bx.Line_Status],al
pop es
pop si
pop di
pop dx
pop cx
pop ds
pop bx
; Enable HW int's
CLI
al := 20h
out Icntrlw2,al
pop ax
iret
rs_com1int endp
rs_com2int endp
rs_com3int endp
rs_com4int endp
ReadInt Proc near
InPOfs <ReceiverReg - IntIdentReg> ;Get received char
; Test if room in buffer
les si,dword ptr [bx.InX] ;Get buffer Address
lea di,[si+1]
if di >= [bx.SizeX] then xor di,di
if di <> [bx.OutX] then ;Buffer not full
es:[si] := al
[bx.InX] := di
else
or [bx.Line_Status],20h ;Overrun Error!
endif
STI
if [bx.AutoX] = FALSE then ret
; Test if XOFF or XON
ah := al ; Test if XOFF or XON
and ah,7fh ; Use 7 low bits!
if [bx.Ctrl_P] < 1 then
if [bx.HostX] = FALSE then
cmp ah,[BX.Xoff1C]
je TurnOff
if [bx.AltX] = TRUE then
cmp ah,[bx.Xoff2C]
je TurnOff
endif
endif
cmp ah,[BX.Xon1C]
je TurnOn
cmp [bx.AltX],TRUE
jne nochange
cmp ah,[bx.Xon2C]
je TurnOn
jmp short nochange
endif
if = then ; if [bx.Ctrl_P] = 1 then
if ah = 10h then
[bx.Ctrl_P] := 2
jmp short nochange
endif
cmp [bx.HostX],TRUE
je TurnOn
cmp ah,[bx.Xoff1C]
je TurnOff
jmp short nochange
endif
if [bx.Ctrl_P] = 2 then
[bx.Ctrl_P] := 3
jmp short nochange
endif
[bx.Ctrl_P] := 1
jmp short nochange
TurnOn:
[bx.HostX] := FALSE ; Save new value
call StartSender
al := ' '
jmp short updateX
TurnOff:
[bx.HostX] := TRUE
al := 'X'
UpdateX:
if [bx.Show_X2] <> 0 then
les di,dword ptr [bx.Show_X]
es:[di] := al
endif
NoChange:
; Test if buffer almost full
dx := [bx.OutX]
di := [bx.InX]
inc di
sub dx,di ;InX
if carry then add dx,[bx.SizeX]
; dx = Free space in buffer
cmp dx,[bx.LimitX]
jbe almost_full
ret ;Buffer not full, early exit
Almost_Full:
test [bx.Bfull],1 ;Is our bit set?
jnz Second_Limit ;Yes, check if past second limit
or [bx.Bfull],1 ;Set our bit
Stop_Rec:
if [bx.UseTint] = TRUE then
al := [bx.Xoff1C]
ah := TRUE
[bx.Send_T] := ax ;Send before all others
call StartSender
ret ;Exit after XOFF sent
endif
call WaitTHRE
al := [bx.Xoff1C]
out dx,al
ret
Second_Limit:
shl dx,1
cmp dx,[bx.LimitX]
jbe Stop_Rec
ret
ReadInt endp
WaitTHRE proc near
mov dx,[bx].PortNr
DXofs LineStatusReg
repeat
in al,dx
ah := al
and ah,1Eh
or [bx.Line_Status],ah
until al AND 20h true
DXofs <TransmitReg - LineStatusReg>
ret
WaitTHRE endp
SendByte proc near ; Sending WO TX-int
; INPUT al : byte to send
; OUTPUT ah : status
; REG'S dx
push ax
call WaitTHRE
pop ax
ah := FALSE;
if [bx.HostX] = FALSE then
out dx,al
ah := TRUE
endif
ret
SendByte EndP
SendInt Proc near
; Use buffered sending
; INPUT al : byte to send
; OUTPUT ah : status
; REG'S dx,si,di,es,
si := [bx.InT]
lea di,[si+1]
if di >= [bx.SizeT] then xor di,di
ah := FALSE
if di <> [bx.OutT] then
es := [bx.T_Buf2]
es:[si] := al
[bx.InT] := di ;Update input pointer
ah := TRUE
endif
call StartSender ;Restart if neccessary
ret
SendInt endp
StartSender proc near
push ax
call SendNext
;Turn on TX int's again!
InPort IntEnableReg
or al,2
out dx,al
pop ax
ret
StartSender endp
SendNoMore:
; Turn off TX int's when no more data
InPort IntEnableReg
and al,NOT 2
out dx,al
ret
SendNext Proc near ;SI
; INPUT
; OUTPUT
; REG'S dx,ax,si,es
if [bx.WaitTX] = FALSE then
InPort LineStatusReg
ah := al
and ah,1Eh
or [bx.Line_Status],ah
if al AND 20h true then
DXofs <TransmitReg - LineStatusReg>
xor ax,ax
xchg ax,[bx.Send_T]
if ah <> FALSE then
out dx,al
elseif [bx.HostX] = FALSE then
les si, dword ptr [bx.OutT]
if si = [bx.InT] then jmp SendNoMore
cld
lods byte ptr es:[si]
if si >= [bx.SizeT] then xor si,si
[bx.OutT] := si
out dx,al
endif
endif
endif
STI
ret
SendNext endp
avail proc near
; INPUT
; OUTPUT cx : bytes in input buffer
; REG'S cx
cx := [bx.InX]
sub cx,[bx.OutX]
if carry then add cx,[bx.sizeX]
ret
avail endp
checkempty proc near ;Local proc for read and readblock
; INPUT
; OUTPUT
; REG'S cx,ax
if [bx.Bfull] and 1 true then
call avail
if cx <= [bx.LimitX] then
and [bx.Bfull],254
if zero then
[bx.WaitTX] := TRUE ;Allocate TX
call WaitTHRE
al := [bx.Xon1C]
out dx,al
[bx.WaitTX] := FALSE
endif
endif
endif
ret
checkempty endp
intro MACRO com
bx := [bp+com]
shl bx,1
shl bx,1
bx := rs_bufptr[bx-4]
ENDM
PasProc rs_readblock <bufs, buf, max, byts, byt, com> FAR
; REG'S dx,cx,si,di,es,bx,ax
intro com
xor dx,dx ;zero bytes read
call avail
if cx > [bp].max then cx := [bp].max ;max bytes
jcxz skipblock
mov si,[bx.OutX] ;output index
les di,[bp].buf ;buffer address
cld ;les forover!
dx := [bx.SizeX] ;Copy of size
push ds
ds := [bx.R_buf2] ;Segment of buffer
push bx
xor bx,bx ;bytes read
repeat
lodsb
if si >= dx then xor si,si
ah := al
inc ah
and ah,7fh
if ah <= ' ' then
if bx <> 0 then
if si = 0 then si := dx
dec si
leave
endif
stosb
inc bx
leave
endif
stosb
inc bx
until loop
dx := bx ;Save bytes read
pop bx
pop ds
[bx.OutX] := si
skipblock:
les di,[bp].byt
es:[di] := dx ;bytes read in block
call checkempty
PasRet
PasProc rs_busyread <chrs, chr, dones, done, com> FAR
intro com
si := [bx.OutX]
ax := FALSE
if si <> [bx.InX] then
es := [bx.R_Buf2]
cld
lods byte ptr es:[si]
if si >= [bx.SizeX] then xor si,si
[bx.OutX] := si
les di,[bp+chr] ;ch
stosb
call checkempty
al := TRUE
endif
les di,[bp.done]
stosb
PasRet
PasProc rs_getchar <chrs, chr, com> FAR
intro com
si := [bx.OutX]
xor ax,ax ; Return value
if si <> [bx.InX] then
es := [bx.R_Buf2]
cld
lods byte ptr es:[si]
xor dx,dx
ah := al
inc ah
and ah,7fh
if ah > ' ' then
if si >= [bx.SizeX] then xor si,si
[bx.OutX] := si
les di,[bp+chr] ;ch
stosb
call checkempty
dl := TRUE
endif
ax := dx
endif
PasRet
PasProc rs_write <chr, dones, done, com> FAR
intro com
al := [bp+chr]
if [bx.UseTInt] = TRUE then
call SendInt
else
call SendByte
endif
les di,[bp.done]
es:[di] := ah
PasRet
PasProc rs_writeblock <bufs, buf, len, byts, byt, com> FAR
intro com
cld ;Forward
if [bx.UseTint] = FALSE then
les si,[bp+buf] ;buf
cx := [bp+len] ;len
dx := cx ;bytes sent
jcxz skipwr
push dx
repeat
lods byte ptr es:[si]
call SendByte
if ah = FALSE then leave
until loop
pop dx
sub dx,cx
skipwr:
ax := dx ;Bytes sent
else ;Use TX int's
; Compute free room in TX buffer
cx := [bx.OutT]
di := [bx.InT]
lea si,[di+1]
ax := [bx.SizeT]
sub cx,si ; OutT - (InT+1)
if carry then add cx,ax
if cx > [bp+len] then cx := [bp+len] ;Min(room,len)
push cx ;Bytes sent
jcxz skipwblock ;Request to send zero bytes!
es := [bx.T_Buf2]
; di := [bx.InT] ; OK from start
push ds
mov ds,[bp+bufs]
;******************* Her peker DS p bufferet, ikke p RS_Buffer!
mov si,[bp+buf] ;buf
sub ax,di ;Size - InT
if ax < cx then ;Room on top of buffer?
sub cx,ax ;Overflow part
xchg cx,ax ;Room on top
rep movsb ;First block
xor di,di ;Continue from start of TX buffer
cx := ax ;last part
endif
rep movsb ;Second block
pop ds
;******************** N er DS:BX ok igjen!
if di >= [bx.SizeT] then xor di,di
[bx.InT] := di
skipwblock:
pop ax ; # of bytes sent
endif
les di,[bp+done]
stosw
call StartSender
PasRet
PasProc rs_avail <com> FAR
intro com
call avail
ax := cx
PasRet
PasProc rs_room <com> FAR ;Room in output buffer
intro com
ax := [bx.OutT]
dx := [bx.InT]
inc dx
sub ax,dx
if carry then add ax,[bx].SizeT
PasRet
PasProc rs_enable <com> FAR
intro com
[bx.HostX] := FALSE
mov al,0
OutPort IntEnableReg
al := [bx].Int_Mask
out dx,al
al := TRUE
xchg al,[bx.WaitTX]
if al = FALSE then
call StartSender
[bx.WaitTX] := FALSE
endif
PasRet
PasProc rs_writefirst <chr, com> FAR
intro com
[bx.WaitTX] := TRUE ;Allocate transmitter!
call WaitTHRE
al := [bp+chr] ;ch to send first
out dx,al
[bx.WaitTX] := FALSE
PasRet
CODE ENDS
END