version	equ	0
;History:254,1

;  The following people have contributed to this code: David Horne, Eric
;  Henderson, and Bob Clements.

;  Copyright, 1988-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.

	include	defs.asm

	.286

code	segment	word public
	assume	cs:code, ds:code

;*****************************************************************************
;
;	es3210 controller board offsets
;	IO port definition (BASE in io_addr)
;*****************************************************************************
NE_RESET	equ	04h		;board control bits.
EBASE		equ	10h
EN_OFF		equ	20h
NE_DATAPORT	equ	60h		; es3210 Port Window.

	include	8390.inc

; Shared memory management parameters

SM_TSTART_PG	equ	000h	; First page of TX buffer
SM_RSTART_PG	equ	006h	; Starting page of RX ring
SM_RSTOP_PG	equ	040h	; Last page +1 of RX ring

ram_enable	macro
	endm

reset_8390	macro
	loadport
	setport	NE_RESET
	mov	al,4			;reset the board.
	out	dx,al
	longpause
	mov	al,1			;unreset the board.
	out	dx,al

	endm

terminate_board	macro
	endm

	public	int_no, io_addr, mem_base
int_no		db	2,0,0,0		;must be four bytes long for get_number.
io_addr		dw	0300h,0		; I/O address for card
mem_base	dw	00000h,0	; Shared memory addr

	public	driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class	db	BLUEBOOK, IEEE8023, 0		;from the packet spec
driver_type	dw	54		;from the packet spec
driver_name	db	'es3210',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,

is_186		db	0

	include	movemem.asm

;
;	Block input routine
;	CX = byte count, es:di = buffer location, ax = buffer address

	public	block_input
block_input:
	push	ds
	assume	ds:nothing
	mov	ds,mem_base		; ds:si points at first byte to move
	mov	si,ax

	add	ax,cx			; Find the end of this frame.
	cmp	ah,byte ptr cs:sm_rstop_ptr ; Over the top of the ring?
	jb	rcopy_one_piece		; Go move it

rcopy_wrap:
; Copy in two pieces due to buffer wraparound.
	mov	ah,byte ptr cs:sm_rstop_ptr ; Compute length of first part
	xor	al,al
	sub	ax,si			;  as all of the pages up to wrap point
	sub	cx,ax			; Move the rest in second part
	push	cx			; Save count of second part
	mov	cx,ax			; Count for first move
	shr	cx,2			; convert byte count to dword count
	db	0f3h, 066h, 0a5h	;rep movsd
	mov	si,SM_RSTART_PG*256	; Offset to start of first receive page
	pop	cx			; Bytes left to move
rcopy_one_piece:
;transfer all complete dwords.
	push	cx
	shr	cx,2			; convert byte count to dword count
	db	0f3h, 066h, 0a5h	;rep movsd
	pop	cx

;now take take of any trailing words and/or bytes.
	db	066h, 0adh		;lodsd

	test	cx,2
	je	rcopy_one_word
	stosw
	db	066h, 0c1h, 0e8h, 010h	;shr	eax,16
rcopy_one_word:

	test	cx,1
	je	rcopy_one_byte
	stosb
rcopy_one_byte:

	pop	ds
	ret


	push	ax		; save buffer address
	loadport
	setport EN_CCMD
	pause_
	mov	al,ENC_NODMA+ENC_PAGE0+ENC_START
	out	dx,al
	setport	EN0_RCNTLO	; remote byte count 0
	pause_
	mov	al,cl
	out	dx,al
	setport	EN0_RCNTHI
	pause_
	mov	al,ch
	out	dx,al
	pop	ax		; get our page back
	setport	EN0_RSARLO
	pause_
	out	dx,al		; set as hi address
	setport	EN0_RSARHI
	pause_
	mov	al,ah
	out	dx,al
	setport EN_CCMD
	pause_
	mov	al,ENC_RREAD+ENC_START	; read and start
	out	dx,al
	setport	NE_DATAPORT
	pause_
	inc	cx		; make even
	shr	cx,1		; word count
	rep	insw
	ret
;
;	Block output routine
;	CX = byte count, ds:si = buffer location, ax = buffer address

block_output:
	assume	ds:nothing

	mov	es,mem_base		; Set up ES:DI at the shared RAM
	mov	di,ax			; ..
	add	cx,3			;round up to next highest dword.
	shr	cx,2
	db	0f3h, 066h, 0a5h	;rep movsd
	clc
	ret

	push	ax		; save buffer address
	add	cx,3		; round up to nearest dword.
	and	cx,0fffch
	loadport
	setport EN_CCMD
	pause_
	mov	al,ENC_NODMA+ENC_START
	out	dx,al		; stop & clear the chip
	setport	EN0_RCNTLO	; remote byte count 0
	pause_
	mov	al,cl
	out	dx,al
	setport	EN0_RCNTHI
	pause_
	mov	al,ch
	out	dx,al
	pop	ax		; get our page back
	setport	EN0_RSARLO
	pause_
	out	dx,al		; set as lo address
	setport	EN0_RSARHI
	pause_
	mov	al,ah
	out	dx,al
	setport EN_CCMD
	pause_
	mov	al,ENC_RWRITE+ENC_START	; write and start
	out	dx,al
	setport	NE_DATAPORT
	pause_
	shr	cx,2		; dword count
	db 0f3h, 066h, 06fh	;rep	outsd

	mov	cx,0
	setport	EN0_ISR
tx_check_rdc:
	in	al,dx
	test	al,ENISR_RDC	; dma done ???
	jnz	tx_start
	loop	tx_check_rdc
	stc
	ret
tx_start:
	clc
	ret


	include	8390.asm

	public	usage_msg
usage_msg	db	"usage: es3210 [-n] [-d] [-w] <packet_int_no> <int_level> <io_addr> <mem_base>",CR,LF,'$'
no_board_msg	db	"No es3210 detected.",CR,LF,'$'
io_addr_funny_msg	label	byte
		db	"No es3210 detected, continuing anyway.",CR,LF,'$'

	public	copyright_msg
copyright_msg	db	"Packet driver for es3210, version "
		db	'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,".",'0'+dp8390_version,CR,LF,'$'

int_no_name	db	"Interrupt number ",'$'
io_addr_name	db	"I/O port ",'$'
mem_base_name	db	"Memory address ",'$'

	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 dx -> name of word, di -> dword to print.
	extrn	print_number: near

	public	parse_args
parse_args:
;exit with nc if all went well, cy otherwise.
	mov	di,offset int_no
	call	get_number
	mov	di,offset io_addr
	call	get_number
	mov	di,offset mem_base
	call	get_number

	cmp	io_addr,-1		;Did they ask for auto-detect?
	je	find_board

	call	detect_board		;no, just verify its existance.
	je	find_board_found

	mov	dx,offset io_addr_funny_msg
	mov	ah,9
	int	21h

	jmp	find_board_found

find_board:
	mov	io_addr,0c80h		;Search for the Ethernet address.
	mov	io_addr+2,0
find_board_0:
	call	detect_board
	je	find_board_found
find_board_again:
	add	io_addr,1000h		;not at this port, try another.
	jnc	find_board_0

	mov	dx,offset no_board_msg	;Tell them that we can't find it.
	mov	ah,9
	int	21h

	stc
	ret
find_board_found:
	clc
	ret

	extrn	etopen_diagn: byte

init_card:
;get the board data. This is (16) bytes starting at remote
;dma address 0. Put it in a buffer called board_data.
	assume	ds:code

	or	endcfg,ENDCFG_WTS

	push	ds
	pop	es		; set es to ds
	mov	di,offset board_data

	loadport			; Get our Ethernet address base.
	setport	EBASE
	mov	cx,EADDR_LEN
read_address_1:
	insb				; get a byte of the eprom address
	inc	dx			; next register
	loop	read_address_1		; go back for rest

	push    ds              ; Copy from card's address to current address
	pop     es

	mov si, offset board_data	; address is at start
	mov di, offset curr_hw_addr
	mov cx, EADDR_LEN       ; Copy one address length
	rep     movsb           ; ..

	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
	mov	di,offset mem_base
	mov	dx,offset mem_base_name
	call	print_number
	ret

detect_board:
;test to see if a board is located at io_addr.
;return nz if not.
	loadport
	setport	EBASE
	in	al,dx			;Check for Interlan's prefix word.
	cmp	al,2
	jne	detect_board_exit

	setport	EBASE+1
	in	al,dx
	cmp	al,7
	jne	detect_board_exit

	setport	EBASE+EADDR_LEN		;first byte following should be 0
	in	al,dx
	cmp	al,0
	jne	detect_board_exit

	setport	EBASE+EADDR_LEN+1	;second byte should be 55h
	in	al,dx
	cmp	al,55h
detect_board_exit:
	ret

code	ends

	end
