home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
lan
/
drivrs30
/
slip8250.asm
< prev
next >
Wrap
Assembly Source File
|
1989-06-08
|
15KB
|
635 lines
version equ 1
include defs.asm
;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
;8250 by Russell Nelson. Any bugs are due to Russell Nelson.
; Copyright, 1988, 1989, Russell Nelson
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
code segment byte public
assume cs:code, ds:code
;8250 definitions
;Control/status register offsets from base address
THR equ 0 ;Transmitter holding register
RBR equ 0 ;Receiver buffer register
DLL equ 0 ;Divisor latch LSB
DLM equ 1 ;Divisor latch MSB
IER equ 1 ;Interrupt enable register
IIR equ 2 ;Interrupt ident register
FCR equ 2 ;16550 FIFO control register
LCR equ 3 ;Line control register
MCR equ 4 ;Modem control register
LSR equ 5 ;Line status register
MSR equ 6 ;Modem status register
;8250 Line Control Register
LCR_5BITS equ 0 ;5 bit words
LCR_6BITS equ 1 ;6 bit words
LCR_7BITS equ 2 ;7 bit words
LCR_8BITS equ 3 ;8 bit words
LCR_NSB equ 4 ;Number of stop bits
LCR_PEN equ 8 ;Parity enable
LCR_EPS equ 10h ;Even parity select
LCR_SP equ 20h ;Stick parity
LCR_SB equ 40h ;Set break
LCR_DLAB equ 80h ;Divisor Latch Access Bit
;16550 Line Control Register
FCR_RCVR equ 002h ;Reset Receive FIFO
FCR_XMIT equ 004h ;Reset Transmit FIFO
FCR_1 equ 001h ;One byte FIFO
FCR_4 equ 041h ;Four byte FIFO
FCR_8 equ 081h ;Eight byte FIFO
FCR_14 equ 0c1h ;Fourteen byte FIFO
;8250 Line Status Register
LSR_DR equ 1 ;Data ready
LSR_OE equ 2 ;Overrun error
LSR_PE equ 4 ;Parity error
LSR_FE equ 8 ;Framing error
LSR_BI equ 10h ;Break interrupt
LSR_THRE equ 20h ;Transmitter line holding register empty
LSR_TSRE equ 40h ;Transmitter shift register empty
;8250 Interrupt Identification Register
IIR_IP equ 1 ;0 if interrupt pending
IIR_ID equ 6 ;Mask for interrupt ID
IIR_RLS equ 6 ;Receiver Line Status interrupt
IIR_RDA equ 4 ;Receiver data available interrupt
IIR_THRE equ 2 ;Transmitter holding register empty int
IIR_MSTAT equ 0 ;Modem status interrupt
;8250 interrupt enable register bits
IER_DAV equ 1 ;Data available interrupt
IER_TxE equ 2 ;Tx buffer empty interrupt
IER_RLS equ 4 ;Receive line status interrupt
IER_MS equ 8 ;Modem status interrupt
;8250 Modem control register
MCR_DTR equ 1 ;Data Terminal Ready
MCR_RTS equ 2 ;Request to Send
MCR_OUT1 equ 4 ;Out 1 (not used)
MCR_OUT2 equ 8 ;Master interrupt enable (actually OUT 2)
MCR_LOOP equ 10h ;Loopback test mode
;8250 Modem Status Register
MSR_DCTS equ 1 ;Delta Clear-to-Send
MSR_DDSR equ 2 ;Delta Data Set Ready
MSR_TERI equ 4 ;Trailing edge ring indicator
MSR_DRLSD equ 8 ;Delta Rx Line Signal Detect
MSR_CTS equ 10h ;Clear to send
MSR_DSR equ 20h ;Data set ready
MSR_RI equ 40h ;Ring indicator
MSR_RLSD equ 80h ;Received line signal detect
;Slip Definitions
FR_END equ 0c0h ;Frame End
FR_ESC equ 0dbh ;Frame Escape
T_FR_END equ 0dch ;Transposed frame end
T_FR_ESC equ 0ddh ;Transposed frame escape
public int_no
int_no db 4,0,0,0 ; interrupt number.
io_addr dw 03f8h,0 ; I/O address for COM1.
baud_rate dw 12c0h,0 ; We support baud rates higher than 65535.
baudclk label word
dd 115200 ;1.8432 Mhz / 16
public driver_class, driver_type, driver_name
driver_class db 6,0,0,0 ;from the packet spec
driver_type db 0,0,0,0 ;from the packet spec
driver_name db 'SLIP8250',0 ;name of the driver.
recv_buf_size dw 3000 ;receive buffer size
recv_buf dw ? ;->receive buffer
recv_buf_end dw ? ;->after end of buffer
recv_buf_head dw ? ;->next character to get
recv_buf_tail dw ? ;->next character to store
recv_cnt dw ? ;number of characters in the queue.
send_buf_size dw 3000 ;send buffer size
send_buf dw ? ;->send buffer
send_buf_end dw ? ;->after end of buffer
send_buf_head dw ? ;->next character to get
send_buf_tail dw ? ;->next character to store
send_cnt dw ? ;number of characters in the queue.
public send_pkt
send_pkt:
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
push cs
pop es
mov di,send_buf_tail
mov bx,send_cnt
mov al,FR_END ;Flush out any line garbage
call send_char
;Copy input to output, escaping special characters
send_pkt_1:
lodsb
cmp al,FR_ESC ;escape FR_ESC with FR_ESC and T_FR_ESC
jne send_pkt_2
mov al,FR_ESC
call send_char
mov al,T_FR_ESC
jmp short send_pkt_3
send_pkt_2:
cmp al,FR_END ;escape FR_END with FR_ESC and T_FR_END
jne send_pkt_3
mov al,FR_ESC
call send_char
mov al,T_FR_END
send_pkt_3:
call send_char
loop send_pkt_1
mov al,FR_END ;terminate it with a FR_END
call send_char
mov send_buf_tail,di
mov send_cnt,bx
;Enable transmitter buffer empty interrupt.
mov ah,IER_TxE
loadport
setport IER
call setbit
clc
ret
send_char:
;stuff the character in al into the transmit buffer, but only if there
;is enough room, otherwise ignore the char.
assume ds:nothing
cmp bx,send_buf_size ;too many chars?
je send_char_1 ;yes.
inc bx ;count up a char.
stosb ;store the char.
cmp di,send_buf_end ;do we need to wrap around?
jne send_char_1 ;no.
mov di,send_buf ;yes - reload with beginning.
send_char_1:
ret
public get_address
get_address:
;get the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:code
mov cx,0
clc
ret
public set_address
set_address:
;set the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc if okay, or cy, dh=error if any errors.
assume ds:nothing
clc
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
ret
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type.
extrn recv_find: near
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near
extrn count_in_err: near
extrn count_out_err: near
public recv
recv:
;called from the recv isr. All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
assume ds:code
recv_2:
loadport
setport IIR
in al,dx ;any interrupts at all?
test al,IIR_IP
jne recv_1 ;no.
and al,IIR_ID
cmp al,IIR_RDA ;Receiver interrupt
jne recv_3
call asyrxint
jmp recv_2
recv_3:
cmp al,IIR_THRE ;Transmit interrupt
jne recv_4
call asytxint
jmp recv_2
recv_4:
;process IIR_RLS here.
recv_1:
ret
;Process 8250 receiver interrupts
asyrxint:
asyrxint_2:
loadport
setport LSR
in al,dx
test al,LSR_DR
je asyrxint_1
setport RBR
in al,dx
;Process incoming data;
; If buffer is full, we have no choice but
; to drop the character
mov cx,recv_cnt
cmp cx,recv_buf_size
je asyrxint_1
push ds
pop es
mov di,recv_buf_tail
stosb
cmp di,recv_buf_end ;did we hit the end of the buffer?
jne asyrxint_3 ;no.
mov di,recv_buf ;yes - wrap around.
asyrxint_3:
mov recv_buf_tail,di
inc recv_cnt
cmp al,FR_END ;might this be the end of a frame?
jne asyrxint_4 ;no.
call recv_frame
asyrxint_4:
jmp asyrxint_2
asyrxint_1:
ret
recv_frame:
mov si,recv_buf_head ;process characters.
mov bx,recv_cnt
mov cx,0 ;count up the size here.
recv_frame_1:
call recv_char ;get a char.
je recv_frame_2 ;go if no more chars.
cmp al,FR_ESC ;an escape?
je recv_frame_1 ;yes - don't count this char.
inc cx ;no - count this one.
jmp recv_frame_1
recv_frame_2:
jcxz recv_frame_3 ;count zero? yes - just free the frame.
;we don't need to set the type because none are defined for SLIP.
push si ;save si in case we reject it.
push bx
mov di,0 ;but we avoid any segment end trouble.
call recv_find ;look up our type.
pop bx
pop si
mov ax,es ;is this pointer null?
or ax,di
je recv_frame_3 ;yes - just free the frame.
push cx
push es ;remember where the buffer pointer is.
push di
mov si,recv_buf_head ;process characters.
mov bx,recv_cnt
recv_frame_4:
call recv_char
je recv_frame_6 ;yes - we're all done.
cmp al,FR_ESC ;an escape?
jne recv_frame_5 ;no - just store it.
call recv_char ;get the next character.
je recv_frame_6
cmp al,T_FR_ESC
mov al,FR_ESC ;assume T_FR_ESC
je recv_frame_5 ;yup, that's it - store FR_ESC
mov al,FR_END ;nope, store FR_END
recv_frame_5:
stosb ;store the byte.
jmp recv_frame_4
recv_frame_6:
mov recv_buf_head,si ;we're skipped to the end.
mov recv_cnt,bx
pop si ;now give the frame to the client.
pop ds
pop cx
assume ds:nothing
call recv_copy
push cs
pop ds
assume ds:code
ret
recv_frame_3:
mov recv_buf_head,si ;remember the new starting point.
mov recv_cnt,bx
ret
recv_char:
;enter with si -> receive buffer, bx = receive count. Wrap around if needed.
;return with nz, al = next char. Return zr if there are no more chars in
; this frame.
lodsb
cmp si,recv_buf_end
jb recv_char_1
mov si,recv_buf
recv_char_1:
dec bx
je recv_char_2
cmp al,FR_END
recv_char_2:
ret
;Handle 8250 transmitter interrupts
asytxint:
mov si,send_buf_head
mov cx,send_cnt
asytxint_2:
loadport ;can we load another character?
setport LSR
in al,dx
test al,LSR_THRE
je asytxint_1 ;no.
lodsb ;fill up the transmit buffer.
cmp si,send_buf_end ;have we hit the end yet?
jb asytxint_3 ;no.
mov si,send_buf
asytxint_3:
setport THR
out dx,al
loop asytxint_2 ;keep sending until we run out.
;No more characters to transmit -- disable transmit interrupts.
setport IER ;Disable transmit interrupts
mov ah,IER_TxE
call clrbit
;Call completion interrupt here
asytxint_1:
mov send_cnt,cx
mov send_buf_head,si
ret
;Set bit(s) in I/O port
setbit:
;enter with dx = port, ah = bit to set.
in al,dx
or al,ah
out dx,al
ret
;Clear bit(s) in I/O port
clrbit:
;enter with dx = port, ah = bit to set.
in al,dx
not al ;perform an and-not using DeMorgan's.
or al,ah
not al
out dx,al
ret
;any code after this will not be kept after initialization.
end_resident label byte
public usage_msg
usage_msg db "usage: SLIP8250 packet_int_no [driver_class] [int_no] [io_addr] [baud_rate]",CR,LF," [send_buf_size] [recv_buf_size]",CR,LF
db " The driver_class should be SLIP, KISS, AX.25, or a number.",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for SLIP8250, version ",'0'+majver,".",'0'+version,CR,LF
db "Portions Copyright 1988 Phil Karn",CR,LF,'$'
approximate_msg db "Warning: This baud rate can only be approximated using the 8250",CR,LF
db "because it is not an even divisor of 115200",CR,LF,'$'
class_name db "Interface class ",'$'
kiss_name db "KISS",CR,LF,'$'
ax25_name db "AX.25",CR,LF,'$'
slip_name db "SLIP",CR,LF,'$'
int_no_name db "Interrupt number ",'$'
io_addr_name db "I/O port ",'$'
baud_rate_name db "Baud rate ",'$'
send_buf_name db "Send buffer size ",'$'
recv_buf_name db "Receive buffer size ",'$'
extrn set_recv_isr: near
;enter with si -> argument string, di -> word to store.
;if there is no number, don't change the number.
extrn get_number: near
;enter with si -> argument string.
;skip spaces and tabs. Exit with si -> first non-blank char.
extrn skip_blanks: near
public parse_args
parse_args:
call skip_blanks
mov al,[si] ;now classify the argument.
or al,20h ;convert to lower case (assuming letter).
cmp al,'k'
jne parse_args_2
mov driver_class,10 ;KISS, from packet spec.
mov dx,offset kiss_name
jmp short parse_args_1
parse_args_2:
cmp al,'s'
jne parse_args_3
mov driver_class,6 ;SLIP, from packet spec.
mov dx,offset slip_name
jmp short parse_args_1
parse_args_3:
cmp al,'a'
jne parse_args_4
mov driver_class,9 ;AX.25, from packet spec.
mov dx,offset ax25_name
jmp short parse_args_1
parse_args_4:
mov di,offset driver_class
mov bx,offset class_name
call get_number
jmp short parse_args_6
parse_args_1:
push dx
mov dx,offset class_name
mov ah,9
int 21h
pop dx
mov ah,9
int 21h
parse_args_5:
mov al,[si] ;skip to the next blank or CR.
cmp al,' '
je parse_args_6
cmp al,CR
je parse_args_6
inc si ;skip the character.
jmp parse_args_5
parse_args_6:
mov di,offset int_no
mov bx,offset int_no_name
call get_number
mov di,offset io_addr
mov bx,offset io_addr_name
call get_number
mov di,offset baud_rate
mov bx,offset baud_rate_name
call get_number
mov di,offset send_buf_size
mov bx,offset send_buf_name
call get_number
mov di,offset recv_buf_size
mov bx,offset recv_buf_name
call get_number
ret
public etopen
etopen:
pushf
cli
loadport ;Purge the receive data buffer
setport RBR
in al,dx
;Enable FIFO, set FIFO trigger level to 8
mov al,FCR_8
setport FCR
out dx,al
;Set line control register: 8 bits, no parity
mov al,LCR_8BITS
setport LCR
out dx,al
;Turn on receive interrupt enable in 8250, leave transmit
; and modem status interrupts turned off for now
mov al,IER_DAV
setport IER
out dx,al
;Set modem control register: assert DTR, RTS, turn on 8250
; master interrupt enable (connected to OUT2)
mov al,MCR_DTR or MCR_RTS or MCR_OUT2
setport MCR
out dx,al
;compute the divisor given the baud rate.
mov dx,baudclk+2
mov ax,baudclk
mov bx,0
asy_speed_1:
inc bx
sub ax,baud_rate
sbb dx,baud_rate+2
jnc asy_speed_1
dec bx
add ax,baud_rate
adc dx,baud_rate+2
or ax,dx
je asy_speed_2
mov dx,offset approximate_msg
mov ah,9
int 21h
asy_speed_2:
loadport ;Purge the receive data buffer
setport RBR
in al,dx
mov ah,LCR_DLAB ;Turn on divisor latch access bit
setport LCR
call setbit
mov al,bl ;Load the two bytes of the divisor.
setport DLL
out dx,al
mov al,bh
setport DLM
out dx,al
mov ah,LCR_DLAB ;Turn off divisor latch access bit
setport LCR
call clrbit
call set_recv_isr ;Set interrupt vector to SIO handler
;set up the various pointers.
mov dx,offset end_resident
mov send_buf,dx
mov send_buf_head,dx
mov send_buf_tail,dx
add dx,send_buf_size
mov send_buf_end,dx
mov recv_buf,dx
mov recv_buf_head,dx
mov recv_buf_tail,dx
add dx,recv_buf_size
mov recv_buf_end,dx
popf
clc ;indicate no errors.
ret
code ends
end