home *** CD-ROM | disk | FTP | other *** search
- ; Copyright (C) 1993, RF Nets, Cupertino, CA
- ; All Rights Reserved
- ; Author:kevinr@Solaris.com
- ;
- ; ecoupler -
- ; TSR compatible with the FTP Software, inc packet driver interface
- ; specification for any card using the Fujitsu MB86965 EtherCoupler.
- ;
- version equ 1
-
- ; $Id: ecoupler.s%v 1.3 1993/02/10 06:30:26 N6RCE Rel $
- ;
- .286
-
- include defs.asm
- include f965.inc ;Fujitsu 86965 definitions
-
- 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.
- io_addr dw -1,-1 ;selected I/O base address
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
- ;supported classes from pkt drv spec
- driver_class db BLUEBOOK,IEEE8023,0
- driver_type db DR_TYPE ;per the spec.
- driver_name db DR_NAME,0 ;name of the driver.
- driver_function db 2 ;basic and extended only
- 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 7 ;number of receive modes in our table.
- dw 0 ;There is no mode zero
- dw rcv_mode_1
- dw 0
- dw rcv_mode_3
- dw rcv_mode_4
- dw rcv_mode_5
- dw rcv_mode_6
-
- WEC_reg Macro reg,val ;write to an ethercoupler register
- Mov DX,io_addr
- Add DX,reg
- IFNB <val>
- Mov AL,val
- ENDIF
- Out DX,AL
- endm
-
- REC_reg Macro reg ;read a designated ethercoupler register
- ;result into AL
- Mov DX,io_addr
- Add DX,reg
- In AL,DX
- endm
-
- ;
- ;-------------------------------------------------------------------------
- ; Misc. data variables needed by driver
- ;-------------------------------------------------------------------------
- ;
-
- mcast_list_bits db 0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
- mcast_none db 8 dup(0)
- mcast_all db 8 dup(0ffh)
-
- ;------------------------------------------------------------------
- ; keep the following together
- recv_pkt_hdr Equ pkt_status ;
- pkt_status Db 0 ;etherCoupler status byte
- pkt_rsvd1 Db 0 ;reserved byte
- pkt_count Dw 0 ;actual bytes received
- pkt_dst_MAC Db EADDR_LEN dup(0) ;destination MAC addr
- pkt_src_MAC Db EADDR_LEN dup(0) ;source MAC addr
- pkt_type Db MAX_P_LEN dup(?) ;ethernet type field -or- 802.3 length field
- ; keep the above together
- ;------------------------------------------------------------------
-
- 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:
- ret
-
- 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
- cmp cx,RUNT ; minimum length for Ether
- jae oklen
- mov cx,RUNT ; make sure size at least RUNT
- oklen:
- Mov AX,CX
- Mov DX,io_addr
- Add DX,BMPR8 ;output buffer reg addr
- Out DX,AX ;write count into xmit buffer reg
- inc cx ;round up.
- shr CX,1 ;bytes to words
- rep OutSW ;copy pkt buffer to EC xmit buffer
-
- mov ax,18
- call set_timeout
- send_buffer_1:
- REC_reg DLCR0 ;get the transmit status
- test al,TX_DONE ;is it done?
- jne send_buffer_2 ;yes.
- call do_timeout
- jne send_buffer_1
- ;send the packet anyway -- we *can't* be waiting to send a packet *this* long.
- send_buffer_2:
-
- WEC_reg DLCR0,TX_DONE ;clear TX status
- mov Al,TX_START + 1 ;start command + packet_count
- WEC_reg BMPR10 ;and we're off
- 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.
- ;
- ; NOTE: this routine alters (and restores on exit) the
- ; DLCR8-15 register set. It also disables DLC then enables it on exit.
- ;
- ;-----------------------------------------------------------------
- assume ds:code
-
- cmp cx,6 ;chk for correct length
- je sa_01 ;if okay, jmp to continue
- mov dl,BAD_ADDRESS
- stc
- ret
- sa_01: ;come here to continue with setting new MAC address
- mov bl,RBS_DLCRH
- call set_reg_block
- mov cx,6 ;restore length
- clc
- ret
-
- assume ds:code
- rcv_mode_1:
- mov al,0 ;disable the receiver and transmitter.
- jmp initialize_nomulti
- rcv_mode_6:
- mov al,3 ;promiscuous mode
- jmp short initialize_nomulti
- rcv_mode_3:
- mov si,offset mcast_none ;don't accept any multicast frames.
- jmp short initialize_multi
- rcv_mode_4:
- mov si,offset mcast_list_bits ;accept our multicast frames.
- jmp short initialize_multi
- rcv_mode_5:
- mov si,offset mcast_all ;accept any multicast frames.
- initialize_multi:
- call set_hw_multi
- mov al,AF1 ; receive mine, broads, and multis.
- initialize_nomulti:
- WEC_reg DLCR5 ;set the address match list.
- ret
-
-
- set_hw_multi:
- mov bl,RBS_HT
- mov cx,8
- ;
- ;
- set_reg_block:
- ;enter with si -> block of register values to set, bl = register set selection,
- ; cx = count of registers to set (up to 8).
- loadport
- setport DLCR6 ;get register contents
- in al,dx
- mov ah,al ;save a copy.
- or al,DLC_EN ;set DLC high (disable)
- out dx,al ;disable EtherCoupler
-
- setport DLCR7 ;get config register 1
- in al,dx
- push ax ;save 6 and 7.
-
- and al,not RBS ;clear current register setting
- or al,bl ;include the one they want to select.
- out dx,al
-
- setport DLCR8
- srb_01:
- lodsb
- out dx,al ;output to Node ID register
- inc dx
- loop srb_01
-
- loadport
- setport DLCR7 ;restore config reg 1
- pop ax
- out dx,al
-
- setport DLCR6 ;restore it.
- mov al,ah
- out dx,al
- ret
-
-
- public terminate
- terminate:
-
- ;time to get out of Dodge
- ; maks interrupts from the hardware, and disable DLC
- WEC_reg DLCR6,DLC_EN
- WEC_reg DLCR2,0 ;disable all Tx src's of inteerupts
- WEC_reg DLCR3,0 ;ditto for Rx
-
- Mov DX,io_addr
- Add DX,24 ;IDRB0
- Out DX,AL ;claims to reset the EC device
-
- 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
-
- 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.
- ;a specific EOI has already been issued to the 8259. The IRQ line in the
- ;8259 is also masked.
-
- assume ds:code
-
- ;technique: read the status register, and write that back to register,
- ; thereby clearing it.
- ;Then, check for RX Buffer Overflow, if so, increment a counter.
- ;Next, loop on RX BUF not empty (DLCR5).
- ;
- REC_reg DLCR1 ;Rx Status register
- WEC_reg DLCR1 ;reset for next occurrance
- ;we shouldn't ever loose an interrupt 'cause:
- ;the PIC is already cleared, it's edge triggered
- ;and we've now armed the EC to hit us again, after the
- ;processor interrupt mask is turned off.
- Test AL,RX_BUF_OVFL ;RX Buffer overflow?
- Jz rcv_buf_chk ;jump if not buffer overflow
- Call count_in_err
- ;we don't test for pkt arrive interrupt, we'll figure it
- ;out from the RX buffer empty status bit in DLCR5
-
- rcv_buf_chk: ;check for packets in buffer
- REC_reg DLCR5 ;recv mode register
- Test AX,RX_BUF_EMPTY ;any more pkts in buffer?
- Jz rcv_not_empty ;jmp if so (RX_BUF_EMPTY off)
- ; no pkts in buffer..all done
- ;*** Jmp rcv_empty ;
-
- rcv_empty: ;come here after pkt buffer goes empty.
-
- Ret ;back to main ISR
-
-
- rcv_not_empty:
- ;We'll read 9 words from the EC. The first two
- ;contain the recv status and the count, the next
- ;fourteen bytes contain the ethernet header.
- ;we're interested in the type field in bytes at
- ;offset 12 and 13.
- Mov DX,io_addr
- Add DX,BMPR8
- Mov CX,(4+EADDR_LEN+EADDR_LEN+MAX_P_LEN)/2 ;status, count, E hdr, all in words
- Push DS
- Pop ES
- Mov DI,offset recv_pkt_hdr ;where to load
- rep Insw
- Cmp pkt_status,20h ;good status
- Je rcv_good_pkt ;jump if good recv status
- ; bad recv status...skip the packet, increment some counter
-
- jmp rcv_skip_pkt ;go to dump packet routine
- rcv_good_pkt:
- ;come here when good packet recv'ed
- ;prep and call recv_find to see if handler owner wants
- ;the blasted thing!
- ;DL = type (BLUEBOOK or IEEE8023)
- ;CX = length including MAC header
- ;ES:DI = ethernet type field
- mov cx,pkt_count
- mov di,offset pkt_type
- mov dl, BLUEBOOK ;assume bluebook Ethernet.
- mov ax, es:[di]
- xchg ah, al
- cmp ax, 1500
- ja BlueBookPacket
- inc di ;set di to 802.2 header
- inc di
- mov dl, IEEE8023
- BlueBookPacket:
-
- call recv_find ;ES:DI points to buffer on rtn
- ;or 0:0 if don't want packet
- mov ax,es
- or ax,di ;check for any bits on
- je rcv_skip_pkt ;jump if don't want the packet
-
- push es
- push di
-
- mov cx,(EADDR_LEN+EADDR_LEN+MAX_P_LEN)/2 ;header length (in words)
- mov si,offset pkt_dst_mac
- rep movsw
- mov dx,io_addr
- add dx,BMPR8
- mov cx,pkt_count ;orig pkt length
- sub cx,(EADDR_LEN+EADDR_LEN+MAX_P_LEN) ;hdr already taken
- shr cx,1 ;make it into words
- rep insw ;copy remainder of pkt to callers buf
- jnc rcv_not_odd_cnt
- in ax,dx ;allow for odd length packets
- stosb
- rcv_not_odd_cnt:
-
- ; notify handle owner the copy is finished
- pop si
- pop ds
- assume ds:nothing
- mov cx,pkt_count
- Call recv_copy ;let caller know data loaded into his
- ;buffer.
- ;DS:SI->his buffer
- ;CX = packet length
- Push CS
- Pop DS ;data back to our segment
- assume DS:code
-
- Jmp rcv_buf_chk ;go check for more pkts in buffer
-
- rcv_skip_pkt: ;come here to skip a packet
- ;** need to increment some counter **
- REC_reg BMPR14 ;get skip pkt reg contents
- Or AL,SKIP_PKT ;tell EC to skip this packet
- WEC_reg BMPR14 ;do it. Note: chip spec says
- ;this could take up to 300ns
- ;to complete.
- Jmp rcv_buf_chk ;go check for more pkts in buffer
-
- public recv_exiting
- recv_exiting:
- ;called from the recv isr after interrupts have been acknowledged.
- ;Only ds and ax have been saved.
- assume ds:nothing
- ret
-
- include timeout.asm
- include multicrc.asm
-
- 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. 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
-
-
- int_no_name db "Interrupt number ",'$'
- io_addr_name db "I/O port ",'$'
-
- bmpr13_val db 0
-
- 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
-
- ;----------------------------------------------------------------------
- ; initialize ethercoupler and prepare driver for operation
- ;----------------------------------------------------------------------
- public etopen
- etopen:
- call get_board_parameters
-
- WEC_reg DLCR6,DLC_EN ;disable data link ctrler prior to init
- ; DLC shut off, we can now safely init all reg values.
- ; DLCR6 is also config reg 0, so don't need to reload it
- Or AL,SRAM_CYCLE_CLK + BUFFER_BUSW
- ; 100NS SRAM cycle, 8 bit system bus width, 8 bit
- ; buffer bus width
- Or AL,TBS_2_2 ;2 2K Tx Buffer
- Or AL,BS_32 ;total buffer size of 32K bytes
- Out DX,AL
-
- WEC_reg DLCR0,TX_DONE+TX_PKT_RCD+JABBER+COL+COL16
- ;clear Tx status'es and the associated interrupts
- WEC_reg DLCR1,0ffh ;rcv status reg - clear all condx
- WEC_reg DLCR2,0 ;disable all Tx src's of interrupts
- WEC_reg DLCR3,RX_PKT_IE+RX_BUF_OVFL
- WEC_reg DLCR4,LBC ;not loopback, Tx defer to carrier sense
- ;no aloha here!
- WEC_reg DLCR5,0 ;receive mode 1, for now.
- WEC_reg DLCR7,PWRON+RDYPNSEL+RBS_BMPR
- WEC_reg BMPR11,0 ;clear collison controls
- WEC_reg BMPR12,0 ;clear DMA enables
- mov al,bmpr13_val
- WEC_reg BMPR13
- WEC_reg BMPR14,FILTER_SELF_RX
- ;
- ; registers are all set, now setup the station MAC address
- ;
- mov di,io_addr
- mov si,offset rom_address
- call read_mac_addr
-
- mov si,offset rom_address
- mov cx,EADDR_LEN
- call set_address ;turns on the DLC
-
- Call set_recv_isr ;hook ourselves in
-
- REC_reg DLCR6 ;get register contents
- and al,not DLC_EN ;set DLC low (Enable)
- WEC_reg DLCR6 ;enable EtherCoupler
-
- ;if all is okay,
- mov dx,offset end_resident
- clc
- ret
- ;if we got an error,
- EC_problem:
- noEC:
- stc
- ret
-
- public print_parameters
- print_parameters:
- ;echo our command-line parameters
- mov di,offset int_no
- mov dx,offset int_no_name
- call print_number
- mov di,offset io_addr
- mov dx,offset io_addr_name
- call print_number
- ret
-
-