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