home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
modem
/
com_pkg1.arc
/
COM_PKG1.ASM
Wrap
Assembly Source File
|
1984-04-20
|
12KB
|
433 lines
title COM_PKG1
page 60,132
;
; COM_PKG1.ASM library of serial I/O routines
; For the IBM PC's first serial port
; Uses Microsoft Pascal calling conventions
; See GLASSTTY.PAS for sample driver program
;
; Adapted from code by John Romkey and Jerry Saltzer of MIT
; by Richard Gillmann (GILLMANN@ISIB), 1983
;
; Package entry points (MS Pascal calling conventions) are:
;
; init_au(divisor:word) initializes port and interrupt vector
; close_a turns off interrupts from the aux port
; dtr_off turns off dtr
; dtr_on turns on dtr
; crcnt : word returns number of characters in input buffer
; cread : byte reads next character in input buffer
; cwcnt : word returns number of free bytes in output buffer
; cwrit(ch:byte) writes a character to the output buffer
; wlocal(ch:byte) writes a character to the input buffer
; make_br causes a break to be sent
;
page
rsize equ 2048 ; size of receive buffer
tsize equ 256 ; size of transmit buffer
base equ 3f0h ; base of address of aux. port registers
int equ 0ch ; interrupt number for aux port
int_off equ int*4 ; offset of interrupt vector
datreg equ base + 8h ; data register
dll equ base + 8h ; low divisor latch
dlh equ base + 9h ; high divisor latch
ier equ base + 9h ; interrupt enable register
iir equ base + 0ah ; interrupt identification register
lcr equ base + 0bh ; line control register
mcr equ base + 0ch ; modem control register
lsr equ base + 0dh ; line status register
msr equ base + 0eh ; modem status register
dla equ 80h ; divisor latch access
mode equ 03h ; 8-bits, no parity
dtr equ 0bh ; bits to set dtr line
dtr_of equ 00h ; turn off dtr, rts, and the interupt driver
thre equ 20h ; mask to find status of xmit holding register
rxint equ 01h ; enable data available interrupt
txint equ 02h ; enable tx holding register empty interrupt
tcheck equ 20h ; mask for checking tx reg status on interrupt
rcheck equ 01h ; mask for checking rx reg status on interrupt
imr equ 21h ; interuprt mask register
int_mask equ 0efh ; mask to clear bit 4
int_pend equ 01h ; there is an interrupt pending
mstat equ 00h ; modem status interrupt
wr equ 02h ; ready to xmit data
rd equ 04h ; received data interrupt
lstat equ 06h ; line status interrupt
ack equ 244 ; acknowledge symbol
parity equ 7fh ; bits to mask off parity
ocw2 equ 20h ; operational control word on 8259
eoi equ 64h ; specific end of interrupt 4
break equ 40h ; bits to cause break
true equ 1 ; truth
false equ 0 ; falsehood
page
data segment public 'data'
int_offset dw 0 ; the original interrupt offset
int_segment dw 0 ; the original interrupt segment
start_tdata dw 0 ; index to first character in x-mit buffer
end_tdata dw 0 ; index to first free space in x-mit buffer
size_tdata dw 0 ; number of characters in x-mit buffer
start_rdata dw 0 ; index to first character in rec. buffer
end_rdata dw 0 ; index to first free space in rec. buffer
size_rdata dw 0 ; number of characters in rec. buffer
tdata db tsize dup(?) ; transmit buffer
rdata db rsize dup(?) ; receive buffr
data ends
dgroup group data
page
assume cs:auxhndlr,ds:dgroup,ss:dgroup
auxhndlr segment 'code'
public init_au ; initializes port and interrupt vector
public close_a ; turns off interrupts from the aux port
public dtr_off ; turns off dtr
public dtr_on ; turns on dtr
public crcnt ; returns number of characters in input buffer
public cread ; reads next character in input buffer
public cwcnt ; returns no. of free bytes in output buffer
public cwrit ; writes a character to output buffer
public wlocal ; writes a character to the input buffer
public make_br ; causes a break to be sent
page
;
; int_hndlr - handles interrupts generated by the aux. port
;
dataseg dw 0
int_hndlr proc far
push bp
push ds
push di
push ax
push bx
push cx
push dx
; set up data segment
mov ax,cs:dataseg
mov ds,ax
; find out where interrupt came from and jump to routine to handle it
mov dx,iir
in al,dx
cmp al,rd
jz rx_int ; if it's from the receiver
cmp al,wr
jz tx_int ; if it's from the transmitter
cmp al,lstat
jz lstat_int ; interrupt becuase of line status
cmp al,mstat
jz mstat_int ; interrupt because of modem status
jmp far ptr int_end ; interrupt when no interrupt pending, go away
lstat_int:
mov dx,lsr ; clear interrupt
in al,dx
jmp repoll ; see if any more interrupts
mstat_int:
mov dx,msr ; clear interrupt
in al,dx
jmp repoll ; see if any more interrupts
tx_int:
mov dx,lsr
in al,dx
and al,tcheck
jnz goodtx ; good interrupt
jmp repoll ; see if any more interrupts
goodtx: cmp size_tdata,0 ; see if any more data to send
jne have_data ; if not equal then there is data to send
; if no data to send then reset tx interrupt and return
mov dx,ier
mov al,rxint
out dx,al
jmp repoll
have_data:
mov bx,start_tdata ; bx points to next char. to be sent
mov dx,datreg ; dx equals port to send data to
mov al,tdata[bx] ; get data from buffer
out dx,al ; send data
inc bx ; increment start_tdata
cmp bx,tsize ; see if gone past end
jl ntadj ; if not then skip
sub bx,tsize ; reset to beginning
ntadj: mov start_tdata,bx ; save start_tdata
dec size_tdata ; one less character in x-mit buffer
jmp repoll
rx_int:
mov dx,lsr ; check and see if read is real
in al,dx
and al,rcheck ; look at receive data bit
jnz good_rx ; real, go get byte
jmp repoll ; go look for other interrupts
good_rx:
mov dx,datreg
in al,dx ; get data
cmp size_rdata,rsize ; see if any room
jge repoll ; if no room then look for more interrupts
mov bx,end_rdata ; bx points to free space
mov rdata[bx],al ; send data to buffer
inc size_rdata ; got one more character
inc bx ; increment end_rdata pointer
cmp bx,rsize ; see if gone past end
jl nradj ; if not then skip
sub bx,rsize ; else adjust to beginning
nradj: mov end_rdata,bx ; save value
repoll:
mov dx,lsr ; we always expect receive data, so
in al,dx ; check status to see if any is ready.
and al,rcheck ; get received data bit
jnz good_rx ; yes, go accept the byte
mov dx,ier ; look at transmit condition
in al,dx ; to see if we are enabled to send data
and al,txint
jz int_end ; not enabled, so go away
mov dx,lsr ; we are enabled, so look for tx condition
in al,dx
and al,tcheck
jz int_end
jmp goodtx ; transmitter is finished, go get more data
int_end:
mov dx,ocw2 ; tell the 8259 that I'm done
mov al,eoi
out dx,al
pop dx
pop cx
pop bx
pop ax
pop di
pop ds
pop bp
iret
int_hndlr endp
page
;
; init_au(divisor:word)
; initialize the Intel 8250 and set up interrupt vector to int_hndlr
; divisor is the divisor for the baud rate generator
;
init_au proc far
push bp
mov bp,sp
cli
mov ax,ds
mov cs:dataseg,ax
; reset the UART
mov al,0
mov dx,mcr
out dx,al
mov dx,lsr ; reset line status condition
in al,dx
mov dx,datreg ; reset recsive data condition
in al,dx
mov dx,msr ; reset modem deltas and conditions
in al,dx
; set baud rate with the passed argument
mov dx,lcr
mov al,dla+mode
out dx,al
mov dx,dll
mov al,6[bp] ; low byte of passed argument
out dx,al
mov dx,dlh
mov al,7[bp] ; high byte of passed argument
out dx,al
; set 8250 to 8 bits, no parity
mov dx,lcr
mov al,mode
out dx,al
; set interrupt vector
push ds
mov ax,0
mov ds,ax
mov bx,ds:int_off
mov cx,ds:int_off+2
mov word ptr ds:int_off,offset int_hndlr
mov ds:int_off+2,cs
pop ds
mov int_offset,bx
mov int_segment,cx
; enable interrupts on 8259 and 8250
in al,imr ; set enable bit on 8259
and al,int_mask
out imr,al
mov dx,ier ; enable interrupts on 8250
mov al,rxint
out dx,al
mov dx,mcr ; set dtr and enable int driver
mov al,dtr
out dx,al
sti
pop bp
ret 2
init_au endp
page
;
; close_a - turns off interrupts from the auxiliary port
;
close_a proc far
; turn off 8250
mov dx,ier
mov al,0
out dx,al
; turn off 8259
mov dx,imr
in al,dx
or al,not int_mask
out dx,al
; reset interrupt vector
cli
mov bx,int_offset
mov cx,int_segment
push ds
mov ax,0
mov ds,ax
mov ds:int_off,bx
mov ds:int_off+2,cx
pop ds
sti
ret
close_a endp
page
;
; dtr_off - turns off dtr to tell modems that the terminal has gone away
; and to hang up the phone
;
dtr_off proc far
mov dx,mcr
mov al,dtr_of
out dx,al
ret
dtr_off endp
;
; dtr_on - turns dtr on
;
dtr_on proc far
mov dx,mcr
mov al,dtr
out dx,al
ret
dtr_on endp
page
;
; crcnt - returns number of bytes in the receive buffer
;
crcnt proc far
mov ax,size_rdata ; get number of bytes used
ret
crcnt endp
;
; cread - returns the next character from the receive buffer and
; removes it from the buffer
;
cread proc far
mov bx,start_rdata
mov al,rdata[bx]
mov ah,0
inc bx ; bump start_rdata so it points at next char
cmp bx,rsize ; see if past end
jl L12 ; if not then skip
sub bx,rsize ; adjust to beginning
L12: mov start_rdata,bx ; save the new start_rdata value
dec size_rdata ; one less character
ret
cread endp
page
;
; cwcnt - returns the amount of free space remaining in the transmit buffer
;
cwcnt proc far
mov ax,tsize ; get the size of the x-mit buffer
sub ax,size_tdata ; subtract the number of bytes used
ret
cwcnt endp
;
; cwrit(ch:byte) - the passed character is put in the transmit buffer
;
cwrit proc far
push bp
mov bp,sp
mov bx,end_tdata ; bx points to free space
mov al,6[bp] ; move data from stack to x-mit buffer
mov tdata[bx],al
inc bx ; increment end_tdata to point to free space
cmp bx,tsize ; see if past end
jl L4 ; if not then skip
sub bx,tsize ; adjust to beginning
L4: mov end_tdata,bx ; save new end_tdata
inc size_tdata ; one more character in x-mit buffer
mov dx,ier ; see if tx interrupts are enabled
in al,dx
and al,txint
or al,al
jnz L44
mov al,rxint+txint ; if not then set them
out dx,al
L44: pop bp
ret 2
cwrit endp
;
; wlocal(ch:byte) - writes a character to the input buffer
;
wlocal proc far
push bp
mov bp,sp
cli
cmp size_rdata,rsize ; see if any room
jge L14 ; if no room then quit
mov bx,end_rdata ; bx points to free space
mov al,6[bp] ; get data
mov rdata[bx],al ; send data to buffer
inc size_rdata ; got one more character
inc bx ; increment end_rdata pointer
cmp bx,rsize ; see if gone past end
jl L13 ; if not then skip
sub bx,rsize ; else adjust to beginning
L13: mov end_rdata,bx ; save value
L14: sti
pop bp
ret 2
wlocal endp
page
;
; make_break - causes a break to be sent out on the line
;
make_br proc far
mov dx,lcr ; save the line control register
in al,dx
mov bl,al
mov al,break ; set break condition
out dx,al
mov cx,0 ; wait a while
wait: loop wait
mov al,bl ; restore the line control register
out dx,al
ret
make_br endp
auxhndlr ends
end