; 3COM ethernet support
_3comfound  db '3c50x NIC',0

;The various IE command registers
EDLC_ADDR	equ	00h	;EDLC station address, 6 bytes
EDLC_RCV	equ	06h	;EDLC receive csr
EDLC_XMT	equ	07h	;EDLC transmit csr
IE_GP		equ	08h	;GP pointer
IE_RP		equ	0ah	;Receive buffer pointer
IE_SAPROM	equ	0ch	;window on station addr prom
IE_CSR		equ	0eh	;IE command/status
IE_BFR		equ	0fh	;window on packet buffer
;bits in IE_CSR
IE_RESET	equ	80h	;reset the controller (wo)
IE_XMTBSY	equ	80h	;Transmitter busy (ro)
IE_RIDE		equ	40h	;request interrupt/DMA enable (rw)
IE_DMA		equ	20h	;DMA request (rw)
IE_EDMA		equ	10h	;DMA done (ro)

IE_BUFCTL	equ	0ch	;mask for buffer control field (rw)
IE_LOOP		equ	0ch	;2 bit field in bits 2,3, loopback
IE_RCVEDLC	equ	08h	;gives buffer to receiver
IE_XMTEDLC	equ	04h	;gives buffer to transmit
IE_SYSBFR	equ	00h	;gives buffer to processor

IE_CRC		equ	01h	;causes CRC error on transmit (wo)
IE_RCVBSY	equ	01h	;receive in progress (ro)

BFRSIZ		equ	2048	;number of bytes in a buffer
;Bits in EDLC_RCV, interrupt enable on write, status when read
EDLC_NONE	equ	000h	;match mode in bits 5-6, write only
EDLC_ALL	equ	040h	;promiscuous receive, write only
EDLC_BROAD	equ	080h	;station address plus broadcast
EDLC_MULTI	equ	0c0h	;station address plus multicast

EDLC_STALE	equ	80h	;receive CSR status previously read
EDLC_GOOD	equ	20h	;well formed packets only
EDLC_ANY	equ	10h	;any packet, even those with errors
EDLC_SHORT	equ	08h	;short frame
EDLC_DRIBBLE	equ	04h	;dribble error
EDLC_FCS	equ	02h	;CRC error
EDLC_OVER	equ	01h	;data overflow

EDLC_RERROR	equ	EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
EDLC_RMASK	equ	EDLC_GOOD or EDLC_ANY or EDLC_RERROR

;bits in EDLC_XMT, interrupt enable on write, status when read
EDLC_IDLE	equ	08h	;transmit idle
EDLC_16		equ	04h	;packet experienced 16 collisions
EDLC_JAM	equ	02h	;packet experienced a collision
EDLC_UNDER	equ	01h	;data underflow

_3cBASE dw 300h
_3cIRQ  db 3h

_3c50x_old_isr  dd 0

_3c_recv_isr proc far
        cmp  cs:_3c_isr_active, 0
        je   _3c_no_reenter
        iret
_3c_no_reenter:
        ret
_3c_isr_active db 0
_3c_recv_isr endp

_3c_set_receivemode proc far
; CX = 1 = NONE
; CX = 3 = 
        cmp  cx, 1
        jne  try_rm_3
        mov  al, EDLC_NONE
        jmp  rm_do
try_rm_3:
        cmp  cx, 3
        jne  try_rm_5
        mov  al,EDLC_BROAD or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
        jmp  rm_do
try_rm_5:
        cmp  cx, 5
        jne  try_rm_6
        mov  al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
        jmp  rm_do
try_rm_6:
        cmp  cx, 6
        jne  try_rm_def
        mov  al,EDLC_ALL or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
        jmp  rm_do
try_rm_def:
        mov  al,EDLC_BROAD or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
rm_do:
        mov  ax, _3cBASE
        mov  bx, EDLC_RCV
        add  ax, bx
        mov  dx, ax
        out  dx, al
        in   al, dx  ; flush status
        ret
_3c_set_receivemode endp

_3c_reset proc far
;Pulse IE_RESET
        mov  ax, _3cBASE
        mov  bx, IE_CSR
        add  ax, bx
        mov  dx, ax
        mov  al,IE_RESET
        out  dx,al
	ret
_3c_reset endp

_3c_reset_interface proc far
        call _3c_reset
        mov  al,0
        out  dx,al
	ret
_3c_reset_interface endp

_3c_set_address proc far
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
;
        cmp     cx, 6            ;ensure that their address is okay.
	je	set_address_4
        mov     dh, BAD_ADDRESS
	stc
	jmp	short set_address_done
set_address_4:
        mov  ax, _3cBASE
        mov  bx, EDLC_ADDR
        add  ax, bx
        mov  dx, ax
set_address_1:
	lodsb
	out	dx,al
	inc	dx
	loop	set_address_1
set_address_okay:
        mov     cx, 6          ;return their address length.
	clc
set_address_done:
	ret
_3c_set_address endp

_3c_get_address proc far
;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.
        cmp     cx, 6                   ;make sure that we have enough room.
	jb	get_address_2
        mov     cx, 6             
	xor	bx,bx
get_address_1:
	mov	ax,bx
        mov  ax, _3cBASE
        mov  bx, IE_GP
        add  ax, bx
        mov  dx, ax
	out	dx,ax

        mov  ax, _3cBASE
        mov  bx, IE_SAPROM
        add  ax, bx
        mov  dx, ax

	in	al,dx
	stosb
	inc	bx
	loop	get_address_1

        mov     cx, 6         
	clc
	ret
get_address_2:
	stc
	ret
_3c_get_address endp

; ===========================================================================
detect_3c501 proc far
; AX = BASE PORT ADDRESS
; BL = IRQ 
; ===========================================================================
        mov  _3cBASE, ax
        mov  _3cIRQ, bl

        ; Initialize the ethernet board, set receive type
        call _3c_reset

        push cs
        pop  es
        mov  di, offset MAC
        mov  cx, 6
        call _3c_get_address
        push cs
        pop  ds
        ; see if there is really a 3c501 there
        mov  cx, 6
        mov  si, offset MAC
        mov  di, offset eth_bcast
        repe cmpsb ; not bcast must be real
        jne  got_3c501
no_3c501:
        xor  ax, ax
        mov  _3cBASE, ax
        mov  _3cIRQ, al
        clc
        ret
got_3c501:

        stc
        ret
detect_3c501 endp
