home *** CD-ROM | disk | FTP | other *** search
- 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
-