home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
packetdrivers.tar.gz
/
pd.tar
/
src
/
ar450.asm
< prev
next >
Wrap
Assembly Source File
|
1995-06-25
|
16KB
|
796 lines
;History:508,1
version equ 0
include defs.asm
; Copyright, 1991-1992, Russell Nelson, Crynwr Software
; 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.
arlan_segment segment at 0
org 000h
ar_signature db ?
org 030h
ar_reset db ?
org 031h
ar_diagnostics db ?
org 040h
ar_node_id db EADDR_LEN dup(?) ;6 byte node address field.
org 046h
ar_node_bcast db EADDR_LEN dup(?) ;6 byte broadcast address.
org 04ch
ar_type db ? ;1 byte hardware type
ar_type_A450 equ 00h
ar_type_A650 equ 01h
ar_type_A670 equ 0bh
ar_type_A670E equ 0ch
ar_type_A650E equ 0dh
ar_type_A440LT equ 0eh
org 04dh
ar_version label word ;Version number.
ar_version_maj db ?
ar_version_min db ?
org 080h
ar_interrupt db ? ;not used by LANCPU
org 081h
ar_control_i db ? ;image of the control register.
org 090h
ar_command db ?
COM_CONF equ 1
COM_RX_ENABLE equ 3
COM_RX_ABORT equ 4
COM_TX_ENABLE equ 5
COM_TX_ABORT equ 6
COM_NOP equ 7
COM_INT equ 80h
org 0a0h
ar_rx_status db ?
org 0a2h
ar_rx_offset dw ? ;start of received datagram
org 0a4h
ar_rx_length dw ? ;length of received datagram
org 0a6h
ar_rx_src db EADDR_LEN dup(?) ;RX source address.
org 0ach
ar_rx_bcast db ? ;<>0 if received frame was bcast.
org 0adh
ar_rx_quality db ? ;indicates quality of received packet.
org 0b0h
ar_tx_status db ?
org 0b1h
ar_tx_quality db ?
org 100h
ar_sys_params label byte
org 108h
ar_irq_level db ? ;IRQ level
org 109h
ar_spreading db 3 dup(?) ;Spread spectrum code ID.
org 10ch
ar_NID dw ? ;Radio address of LAN card.
org 11dh
ar_tx_atten db ? ;attenuation of radio transmitter in db.
org 11eh
ar_system_id dd ? ;system ID.
org 128h
ar_MDS dw ? ;Maximum Datagram Size.
org 12ah
ar_MFS dw ? ;Maximum Frame Size.
org 12ch
ar_max_retry db ?
org 162h
ar_register db ? ;indicates if card must register w/ router.
org 164h
ar_poll_rate dw ? ;<>0 if power saving is used.
org 166h
ar_refresh_rate dw ? ;tens of msecs between registration
;refreshes.
org 168h
ar_name db 16 dup(?)
org 400h
ar_tx_buffer label byte
org 0c00h
ar_rx_buffer label byte
org 1fffh
ar_control db ?
CONTROL_RESET equ 1
CONTROL_CA equ 2
CONTROL_IE equ 4
CONTROL_CLRI equ 8
arlan_segment ends
code segment word public
assume cs:code, ds:code
public int_no
int_no db 0,0,0,0 ;must be four bytes long for get_number.
base_addr dw ? ;The base address of the board.
xmit_bdcast db ?
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK,0 ;from the packet spec
driver_type db 99 ;from the packet spec
driver_name db 'ARLAN 450',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
int_num dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
public rcv_modes
rcv_modes dw 4 ;number of receive modes in our table.
dw 0,0,0,rcv_mode_3
public bad_command_intercept
bad_command_intercept:
;called with ah=command, unknown to the skeleton.
;exit with nc if okay, cy, dh=error if not.
mov dh,BAD_COMMAND
stc
ret
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
include popf.asm
include timeout.asm
include movemem.asm
public send_pkt
send_pkt:
;enter with es:di->upcall routine, (0:0) if no upcall is desired.
; (only if the high-performance bit is set in driver_function)
;enter with ds:si -> packet, cx = packet length.
;if we're a high-performance driver, es:di -> upcall.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
mov es,base_addr
assume es:arlan_segment
cmp cx,ar_MDS ;Is this packet too large?
mov dh,NO_SPACE
ja send_pkt_toobig ;yes, don't bother sending it.
if 0
mov bx,2 ;count the number of times around...
wait_again:
mov ax,10 ;don't wait too long...
call set_timeout
wait_for_xmit:
sti
cmp ar_tx_status,0 ;is the transmit done?
jne xmit_done ;yes, exit now.
call do_timeout
jne wait_for_xmit ;no, wait for it to finish.
cli
inc ar_interrupt ;note that we had to crap out.
mov ar_command,COM_TX_ABORT
call doca
mov ar_tx_status,1
else
sti
wait_for_xmit:
cmp ar_tx_status,0 ;is the transmit done?
jne xmit_done ;yes, exit now.
jmp wait_for_xmit ;no, wait for it to finish.
endif
clc ;pretend we actually sent it.
ret
send_pkt_toobig:
stc
ret
xmit_done:
cli
mov di,offset ar_command + 5
mov xmit_bdcast,0
;check to see if it's an Ethernet broadcast (all ones).
push ds
push si
push cx
mov cx,EADDR_LEN
send_pkt_1:
lodsb
cmp al,0ffh
loope send_pkt_1
jne send_pkt_2 ;not Ethernet broadcast.
inc xmit_bdcast ;remember that it was a broadcast.
mov si,offset ar_node_bcast ;use our broadcast address.
mov ds,base_addr
movsw ;move the broadcast address over.
movsw
movsw
pop cx
pop si
pop ds
add si,EADDR_LEN ;skip the addresses.
jmp short send_pkt_3
send_pkt_2:
pop cx
pop si
pop ds
movsw ;move the destination address over.
movsw
movsw
send_pkt_3:
add si,EADDR_LEN ;skip the addresses.
sub cx,EADDR_LEN+EADDR_LEN ;. .
mov di,offset ar_tx_buffer
mov al,xmit_bdcast
stosb
push cx
call movemem
pop cx
inc cx ;include the broadcast byte.
mov ar_command,COM_TX_ENABLE
mov word ptr ar_command[1],offset ar_tx_buffer
mov word ptr ar_command[3],cx
mov ar_tx_status,0 ;let the board fill it in.
call doca
clc
ret
public set_address
set_address:
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
assume ds:nothing
ret
rcv_mode_3:
;receive mode 3 is the only one we support, so we don't have to do anything.
ret
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, ax = number of addresses,
; cx = number of bytes.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret
public terminate
terminate:
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, dl = packet class.
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
;call this routine to schedule a subroutine that gets run after the
;recv_isr. This is done by stuffing routine's address in place
;of the recv_isr iret's address. This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
extrn schedule_exiting: near
;recv_exiting jumps here to exit, after pushing the flags.
extrn recv_exiting_exit: 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, es:arlan_segment
mov es,base_addr
;clear the interrupt request.
mov al,ar_control_i ;drop the clear interrupt bit.
and al,not CONTROL_CLRI
mov ar_control,al
or al,CONTROL_CLRI ;raise the clear interrupt bit.
mov ar_control,al
cmp ar_rx_status,0 ;was this our receive interrupt?
jne recv_recv
cmp ar_tx_status,0 ;was this our transmit interrupt?
jne recv_xmit
jmp recv_exit
recv_xmit:
jmp recv_exit
recv_recv:
mov di,ar_rx_offset ;get a pointer to the packet.
mov cx,ar_rx_length ;get the length.
dec cx ;omit the "was broadcast" flag.
inc di ;. .
add cx,EADDR_LEN+EADDR_LEN ;add the two headers in.
push es
push di
push cx
mov dl, BLUEBOOK ;assume bluebook Ethernet.
call recv_find
pop cx
pop si
pop ds
assume ds:arlan_segment, es:nothing
mov ax,es ;is this pointer null?
or ax,di
je recv_free ;yes - just free the frame.
push es
push di
push cx
sub cx,EADDR_LEN+EADDR_LEN
mov al,ds:[si-1] ;get the "was broadcast" flag.
cmp al,0 ;was it a broadcast?
je recv_us ;no.
mov ax,0ffffh ;yes, stuff an Ethernet broadcast in.
stosw
stosw
stosw
jmp short recv_source
recv_us:
mov si,offset ar_node_id
movsw
movsw
movsw
recv_source:
mov si,offset ar_rx_src ;move the source address over.
movsw
movsw
movsw
mov si,ar_rx_offset ;get a pointer to the packet.
inc si
rep movsb
pop cx
pop si
pop ds
assume ds:nothing
call recv_copy
recv_free:
movseg ds,cs
assume ds:code
mov es,base_addr
assume es:arlan_segment
enable_receive:
mov ar_rx_status,0 ;clear the current status.
mov ar_command,COM_RX_ENABLE+COM_INT
mov ar_command+1,1 ;receive broadcasts.
call doca
cmp ar_rx_status,0 ;is there another packet?
jne recv_recv ;yes, receive it now.
recv_exit:
ret
doca:
;toggle the CA bit in the control register.
;must be executed with interrupts off to protect ar_control_i.
;return cy if we had a horrible failure.
assume es:arlan_segment
pushf ;make up a fake iret stack frame.
cli
mov al,ar_control_i ;toggle the bit in the image
xor al,CONTROL_CA
mov ar_control_i,al ;and store them both.
mov ar_control,al
popf
mov ax,5 ;wait about 1/7th of a second.
call set_timeout
doca_2:
cmp ar_command,0 ;wait for the command to finish.
je doca_1 ;it did.
call do_timeout
jne doca_2
stc
ret
doca_1:
clc
ret
public timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
iret
;any code after this will not be kept after initialization. Buffers
;used by the program, if any, are allocated from the memory between
;end_resident and end_free_mem.
public end_resident,end_free_mem
end_resident label byte
end_free_mem label byte
public usage_msg
usage_msg db "usage: ar450 [options] <packet_int_no>",CR,LF,'$'
public copyright_msg
copyright_msg db "Packet driver for an ARLAN 450, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
db "Portions Copyright 1990, Russell Nelson",CR,LF,'$'
extrn set_recv_isr: near
;enter with si -> argument string, di -> wword to store.
;if there is no number, don't change the number.
extrn get_number: near
;enter with dx -> argument string, di -> wword to print.
extrn print_number: near
;-> the assigned Ethernet address of the card.
extrn rom_address: byte
public parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
clc
ret
signature db "TELESYSTEM"
signature_len equ $-signature
no_board_msg db "Cannot locate an ARLAN board.",'$'
self_test_msg db "ARLAN board self-tests bad.",'$'
bad_mem_msg db "The on-card memory tests as bad.",'$'
file_not_found db "File not found",'$'
read_trouble db "Trouble reading the file",'$'
timeout_msg_xx db "x"
timeout_msg_x db "x"
timeout_msg db "Timed out waiting for the board",'$'
configure_bad db "The configure attempt failed",'$'
arlan_cfg db "arlan.cfg",0
handle dw ?
int_no_name db "Interrupt number ",'$'
public etopen
etopen:
assume ds:code, es:arlan_segment
;look for the arlan card in memory
mov dx,0c000h
etopen_1:
mov si,offset signature
mov es,dx
mov di,offset ar_signature
mov cx,signature_len
repe cmpsb
je etopen_2
add dx,200h
cmp dx,0de00h
jb etopen_1
mov dx,offset no_board_msg
stc
ret
etopen_2:
mov base_addr,dx
mov ar_control,1 ;reset the board.
mov ax,base_addr ;test the memory.
mov cx,2000h-3
call memory_test
je memory_ok
mov dx,offset bad_mem_msg
stc
ret
memory_ok:
xor di,di ;zero all the memory.
mov cx,2000h-1
xor al,al
rep stosb
mov ar_reset,1 ;set the reset flag.
mov ar_control,0 ;remove the reset.
mov ax,36
call set_timeout
wait_for_reset:
cmp ar_reset,0 ;did it finish resetting yet?
je wait_for_reset_1 ;yes, exit.
call do_timeout
jne wait_for_reset
mov dx,offset timeout_msg
stc
ret
wait_for_reset_1:
;set the reset flag again, so that we can detect if we somehow got reset.
mov ar_reset,1
cmp ar_diagnostics,0ffh ;Did it self-check okay?
je self_test_ok
mov dx,offset self_test_msg
stc
ret
self_test_ok:
mov ar_command,COM_NOP ;do a NOP.
call doca
jnc wait_for_first_nop_1
mov dx,offset self_test_msg
stc
ret
wait_for_first_nop_1:
;;; They say to do another with with COM_INT set...
mov al,ar_irq_level ;copy the interrupt number out of
mov int_no,al ; the configuration file.
mov ax,3d00h ;open for reading.
mov dx,offset arlan_cfg
int 21h
jnc file_found
mov dx,offset file_not_found
stc
ret
file_found:
mov handle,ax
mov ax,4200h
mov bx,handle
xor cx,cx
mov dx,100h ;skip past the first 100h bytes.
int 21h
mov ah,3fh ;read the system parameters.
mov bx,handle
mov cx,100h
mov dx,offset ar_sys_params
push ds
mov ds,base_addr
int 21h
pop ds
jnc no_trouble
mov dx,offset read_trouble
stc
ret
no_trouble:
mov ah,3eh ;close the file.
mov bx,handle
int 21h
cmp int_no,0 ;Does the board know its interrupt
jne set_int_no ; number? go if it does.
mov al,ar_irq_level ;No, so use the one
mov int_no,al ; in the configuration file.
set_int_no:
; do the configure.
mov ar_command,COM_CONF
call doca
jnc wait_for_configure_1 ;it did.
mov dx,offset timeout_msg_x
stc
ret
wait_for_configure_1:
cmp ar_diagnostics,0ffh ;did the configure succeed?
je configure_ok
mov dx,offset configure_bad
stc
ret
configure_ok:
;wait a short while for the AR450. For the AR440, wait up to 15 seconds.
mov ax,36
call set_timeout
wait_for_address:
mov cx,EADDR_LEN ;see if our address is still zeroes.
mov si,offset ar_node_id
xor al,al
wait_for_address_2:
or al,es:[si]
inc si
loop wait_for_address_2
or al,al ;do we have an address yet?
jne wait_for_address_1 ;yes.
call do_timeout
jne wait_for_address
mov dx,offset timeout_msg_xx
stc
ret
wait_for_address_1:
;say that the max we'll send is an Ethernet GIANT packet, less the two
; Ethernet addresses that we don't include in the datagram, plus the one
; broadcast byte that we *do* include.
mov ax,GIANT - EADDR_LEN*2 + 1
mov ax,1023
mov ar_MDS,ax
mov ar_MFS,ax
; reduce the number of retries
mov ar_max_retry,16
;enable reception
call enable_receive
;mark transmission as done
mov ar_tx_status,1
;enable our interrupts.
mov al,ar_control_i
or al,CONTROL_IE or CONTROL_CLRI
mov ar_control_i,al
mov ar_control,al
;get our address
movseg es,cs
mov di,offset rom_address
mov cx,EADDR_LEN ; Move one ethernet address from our copy
mov si,offset ar_node_id ; Copy from the board.
push ds
mov ds,base_addr
rep movsb
pop ds
; Now hook in our interrupt
call set_recv_isr
sti
mov al, int_no ; Get board's interrupt vector
add al, 8
cmp al, 8+8 ; Is it a slave 8259 interrupt?
jb set_int_num ; No.
add al, 70h - 8 - 8 ; Map it to the real interrupt.
set_int_num:
xor ah, ah ; Clear high byte
mov int_num, ax ; Set parameter_list int num.
clc
ret
public print_parameters
print_parameters:
;echo our command-line parameters
mov dx,offset int_no_name
mov di,offset int_no
call print_number
ret
include memtest.asm
code ends
end