i82586_version	equ	1
DAN	equ	1

;
; Code that is common between 82586 implementations.
;

; Ported from Tim Krauskopf's micnet.asm, an assembly language
; driver for the MICOM-Interlan NI5210, by Russell Nelson.  Any bugs
; are due to Russell Nelson.
; Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.
; Updated to support 1500 byte MTU April 27, 1989 By Brad Clements.

; Copyright, 1988, 1989, Russell Nelson

;   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.

;
;  Structure elements specific to the Intel 82586 chip
;
BUF_COUNT EQU	28			; number of buffers
XMIT_MTU EQU	1500+14			; size of xmit buffer (1500 MTU +
					;   14 bytes for Ethernet headers

SCB	EQU	BASE_OFFSET + 10	; system control block base
CCBPTR	EQU	BASE_OFFSET + 26	; offset of configure command block
TCBPTR	EQU	BASE_OFFSET + 44	; xmit CB offset
TBDPTR	EQU	BASE_OFFSET + 60	; xmit BD offset
TBUFPTR	EQU	BASE_OFFSET + 68	; xmit buffer offset
FDBASE	EQU	TBUFPTR+XMIT_MTU	; base addr for 30 frame descriptors
FDSIZE  EQU     BUF_COUNT * 22
BDBASE	EQU	FDBASE+FDSIZE		; base address for 30 buffer descriptors
BDASIZE	EQU     BUF_COUNT * 10
BUFBASE	EQU	BDBASE+BDASIZE		; base address for 30 200 byte buffers
BUFFTOP EQU     BUFBASE+BUF_COUNT*200
ISCPTR	EQU	BASE_OFFSET + 01feeh	; my address for ISCP, points to SCB
SCPTR	EQU	BASE_OFFSET + 01ff6h	; hardwired address for SCP

if2
        %out Buffer top is BUFFTOP
if BUFFTOP gt ISCPTR
        %out Warning, buffers extend beyond ISCPTR, reduce BUF_COUNT.
endif
endif
BDSTAT	EQU	0			; status word in BD
BDLINK	EQU	2			; 16pointer to next BD
BDPTR	EQU	4			; 24pointer to actual buffer
BDSIZE	EQU	8			; size of the buffer
;
SSTAT	EQU	0			; status word for SCB
SCOM	EQU	2			; command word in SCB
SCBL	EQU	4			; 16pointer to command block list
SRFA	EQU	6			; 16pointer to receive frame list
SERRS	EQU	8			; 4 words of error counts
;
FDSTAT	EQU	0			; status word for frame
FDEOL	EQU	2			; end of FD list flag
FDLINK	EQU	4			; 16pointer to next FD
FDPTR	EQU	6			; 16pointer to list of BD's
;
TSTAT	EQU	0			; status word for xmit
TCOM	EQU	2			; command to transmit
TLINK	EQU	4			; 16pointer to next command (always ffff)
TPTR	EQU	6			; 16pointer to xmit TBD
TTRIES	EQU	8			; number of transmit retries
;
MCSTAT	equ	0			; status word for multicast
MCCOM	equ	2			; command to setup multicast
MCLINK	equ	4			; 16pointer to next command (always ffff)
MCCNT	equ	6			; number of multicast addresses.

	public	rcv_modes
rcv_modes	dw	7		;number of receive modes in our table.
		dw	0               ;There is no mode zero
		dw	0
		dw	rcv_mode_2
		dw	rcv_mode_3
		dw	rcv_mode_4	;haven't set up perfect filtering yet.
		dw	0
		dw	rcv_mode_6

firstfd		dw	FDBASE		; start of FD queue
lastfd		dw	0		; end of the FD chain
lastbd		dw	0		; end of the BD chain
flag		dw	0


;
; Configuration block for 82586, this comprises one config command
;  Parameters taken from MICOM driver
;
CBCONF	DW	0		; status word
	DW	8002H		; end of command list + configure command
	DW	0ffffh		; link to next command (not used)
	DW	080CH		; fifo=8, byte count=C
	DW	2E00H		; important! Addr (AL) not inserted on the fly!
	DW	6000H		; IFS = 60h
	DW	0F200H		; retry=F, slot time=200h
CBCONF_FLAGS	label	byte
	DW	0		; flags, set to 1 for promiscuous
CBCONF_MINLEN	label	byte
	DW	40H		; min frame length=40h


	include	timeout.asm

	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


	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.
;exit with nc if ok, or else cy if error, dh set to error number.
	assume	ds:nothing
	mov	es,base_addr		; base for board

	mov	word ptr es:[SCB+SCBL],TCBPTR; say where xmit command is

	cmp	cx,XMIT_MTU		; Is this packet too large?
	ja	send_pkt_toobig

	mov	dx,cx			; save a copy, might be less than 60, ok

	cmp	dx,RUNT			; minimum length for Ether
	jnb	oklen
	mov	dx,RUNT			; make sure size at least RUNT
oklen:
	mov	di,TBUFPTR		; start of xmit buffer

;
;  check for previous xmit
;
xwait:
	mov	bx,word ptr es:[SCB+SCOM]	; is command zeroed yet?
	or	bx,bx
	jnz	xwait				; not there yet, wait for it
;
;  move the data using word moves.
;
	call	movemem
;
;  put the correct size into the TBD
;
	or	dx,08000h			; end of frame bit flag
	mov	word ptr es:[TBDPTR],dx		; store it
	mov	word ptr es:[TCBPTR],0		; zero status wd
	mov	word ptr es:[TCBPTR+TCOM],08004h; xmit command in TCB
	mov	word ptr es:[SCB+SCOM],0100h	; execute command

	call	doca

	clc
	ret
send_pkt_toobig:
	mov	dh,NO_SPACE
	stc
	ret


	include	movemem.asm

	public	get_address
get_address:
;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.
	assume	ds:code
	cmp	cx,EADDR_LEN		;make sure that we have enough room.
	jb	get_address_2
	mov	cx,EADDR_LEN
	mov	dx,io_addr		; Get our IO base address.
	cld
get_address_1:
	in	al,dx			; get a byte of the eprom address
	stosb				; put it away
	add	dx,GET_ADDR_INC		; next register
	loop	get_address_1		; go back for rest
	mov	cx,EADDR_LEN
	clc
	ret
get_address_2:
	stc
	ret


rcv_mode_2:
	and	CBCONF_FLAGS,not 3
	or	CBCONF_FLAGS,2		;disable broadcasts.
	mov	CBCONF_MINLEN,40h
	jmp	short reconfigure
rcv_mode_4:
rcv_mode_3:
	and	CBCONF_FLAGS,not 3	;clear promiscuous mode.
	mov	CBCONF_MINLEN,40h
	jmp	short reconfigure
rcv_mode_6:
	and	CBCONF_FLAGS,not 3
	or	CBCONF_FLAGS,1		;set promiscuous mode.
	mov	CBCONF_MINLEN,0		;allow runts.
reconfigure:
	mov	es,base_addr		;get the base address for the board.
	mov	si,offset CBCONF	; configure command
	mov	di,CCBPTR		; where command will reside
	mov	cx,9
	rep	movsw			; copy to board
;
;  issue the configure command
;
	mov	word ptr es:[SCB+SCOM],0100h	; do-command command
	mov	word ptr es:[SCB+SCBL],CCBPTR	; where conf command is
	mov	word ptr es:[SCB+SERRS],0	; zero errs field
	mov	word ptr es:[SCB+SERRS+2],0	; zero errs field
	mov	word ptr es:[SCB+SERRS+4],0	; zero errs field
	mov	word ptr es:[SCB+SERRS+6],0	; zero errs field
	call	doca
	mov	ax,18
	call	set_timeout
reconfigure_1:
	mov	ax,word ptr es:[CCBPTR]	; get status word
	test	ax,08000h		; is command complete?
	jnz	reconfigure_2		; we're okay.
	call	do_timeout		;did we time out yet?
	jne	reconfigure_1		;not yet.
	stc				;timeout -- uh-oh.
	ret
reconfigure_2:
	clc
	ret


	public	set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, cx = number of addresses.
;return nc if we set all of them, or cy,dh=error if we didn't.
	assume	ds:code
	mov	es,base_addr
	mov	word ptr es:[SCB+SCBL],TBUFPTR	;use the transmit buffer.

	mov	es:[TBUFPTR+MCSTAT],word ptr 0	;status word
	mov	es:[TBUFPTR+MCCOM],word ptr 08003h	;command word for mc-setup + EL
	mov	es:[TBUFPTR+MCLINK],word ptr -1		;no command link.
	mov	di,TBUFPTR+MCCNT
	mov	ax,cx			;store the count.
	stosw
	rep	movsb

	call	doca
	mov	ax,18
	call	set_timeout
set_multicast_1:
	mov	ax,word ptr es:[TBUFPTR+MCSTAT]	; get status word
	test	ax,08000h		; is command complete?
	jnz	set_multicast_2		; we're okay.
	call	do_timeout		;did we time out yet?
	jne	set_multicast_1		;not yet.
	mov	dh,NO_MULTICAST		;for some reason we can't do multi's.
	stc
	ret
set_multicast_2:
	clc
	ret


	public	terminate
terminate:
	assume	ds:code
	ret

	public	reset_interface
reset_interface:
;reset the interface.
;we don't do anything.
	assume	ds:nothing
	ret


;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type.
	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:
	mov	flag, 1
;called from the recv isr.  All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
recv1:
	mov	ds,base_addr	; base for board
	assume	ds:nothing

	mov	ax,ds:[SCB+SSTAT]	;get the status.
recv_isr_1:
	cmp	word ptr ds:[SCB+SCOM],0 ;are we done yet?
	jne	recv_isr_1		;no -- keep waiting.

	and	ax,0f000h		;isolate the ACK bits.
  if DAN
	jz	recv_isr_2
  endif
	mov	ds:[SCB+SCOM],ax	;make a command to
					;acknowledge the interrupt.
	call	doca
recv_isr_2:
	cmp	word ptr ds:[SCB+SCOM],0 ;are we done yet?
	jne	recv_isr_2		;no -- keep waiting.

;  Get whatever packets are on the board
;
	mov	bx,firstfd	; get addr of first FD in list
	mov	ax,[bx+FDSTAT]	; status word of frame
	test	ax,08000h	; frame written?
	jnz	okframe

	jmp	ru_start	; no, restore receiver if necessary
frame_bad:
	call	count_in_err
ptrupdate_j_1:
	jmp	ptrupdate

;  we have a frame, read it in
;
okframe:
	test	ax,02000h		;check frame OK bit
	jz	frame_bad		;bad, fix it.
	mov	si,[bx+FDPTR]		;get pointer to buffer descriptor
	xor	cx,cx			;start with zero bytes.
countbuf:				;es:di is already set to receive packet
	mov	dx,si			;save a copy of current BD ptr
	mov	ax,[si+BDSTAT]		;get status and count word for BD
	test	ax,04000h		;is count field there?
	jz	ptrupdate_j_1		;no - we give up here.
	add	cl,al			;add the count into cx.
	adc	ch,0
	mov	si,[si+BDLINK]		;go to next BD in list
	test	ax,8000h		;is this the last frame?
	je	countbuf		;no - keep counting.

	push	bx
	push	cx

	mov	ax,cs			;we need ds = code.
	mov	ds,ax
	assume	ds:code

	mov	es,base_addr		;get a pointer to their type.
	mov	di,es:[bx+FDPTR]	;get pointer to buffer descriptor
	mov	di,es:[di+BDPTR]	;get offset of data
	add	di,EADDR_LEN+EADDR_LEN	;skip the ethernet addreses and
					;  point to the packet type.

	call	recv_find		;look up our type.

	pop	cx
	pop	bx
	mov	ds,base_addr		;restore ds to the board.
	assume	ds:nothing

	mov	ax,es			;is this pointer null?
	or	ax,di
	je	ptrupdate		;yes - just free the frame.

	push	cx
	push	es			;remember where the buffer pointer is.
	push	di
  if DAN
	push	cx
  endif

	mov	si,[bx+FDPTR]		;get pointer to buffer descriptor
copybuf:
	mov	dx,si			;save a copy of current BD ptr
	xor	ch,ch			;200 bytes is largest this can be
	mov	cl,[si+BDSTAT]		;get count word for BD
	mov	si,[si+BDPTR]		;get offset of data
  if DAN
	pop	ax
	sub	ax, cx
	jc	copydone
	push	ax
  ENDIf
	call	movemem
	mov	si,dx			;get back current BD ptr
	test	[si+BDSTAT],8000h	;check EOF bit
	mov	si,[si+BDLINK]		;go to next BD in list
	jz	copybuf			;not done, keep copying it.

  if DAN
	pop	cx
copydone:
  endif
	pop	si			;now give the frame to the client.
	pop	ds
	pop	cx
	assume	ds:nothing

	call	recv_copy
;
;  we are done with the frame, do the list management
;
ptrupdate:
	push	cs
	pop	ds
	assume	ds:code
	mov	es,base_addr		; reload board segment

	mov	si,es:[bx+FDPTR]	; first BD in frame list
nextbd:
	mov	cx,es:[si+BDSTAT]	; count word for BD, EOF bit
	test	cx,08000h		; EOF bit, if set, save si in lastbd
	jnz	dolastbd
	mov	word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
	cmp	si,lastbd		; see if we are wrapping
	jz	dolastbd		; yes, just undo it
	mov	si,es:[si+BDLINK]	; follow link
	jmp	nextbd
dolastbd:
	mov	di,lastbd		; where end of BD list is now
	mov	lastbd,si		; store last known BD
	mov	word ptr es:[si+BDSIZE],08000h+200	; end of list here
	mov	word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
; size field for not end of list
	mov	word ptr es:[di+BDSIZE],200	; remove old end-of-list

;
;  update the FD list flags, new end-of-list
;
	mov	word ptr es:[bx+FDEOL],08000h	; store new EOL
	mov	word ptr es:[bx+FDSTAT],0	; clear status word for frame
	mov	di,lastfd		; get old end-of-list
	mov	word ptr es:[di+FDEOL],0 ; zero old one
	mov	lastfd,bx		; update stored pointer
	mov	si,es:[bx+FDLINK]	; where next fd is
	mov	firstfd,si		; store that info for next time
  if DAN
	jmp	recv1
  endif

ru_start:
; re-start receive unit
;
;  check to see if the receiver went off because of no resources
;  and restart receiver if necessary
;
	push	cs
	pop	ds
	mov	es,base_addr
	mov	ax,es:[SCB+SSTAT]	; status word for SCB
	and	ax,070h		; receiver status
	cmp	al,020h		; receiver has no resources
	jnz	hasres
  if DAN
	cmp	flag, 1
	jnz	ru_start1
	mov	flag, 0
	jmp	recv1
  endif

ru_start1:
	call	count_out_err
;
;  setup lists for starting the RU on the chip
;  we know that there isn't anything in the buffer that we want
;

	mov	bx,firstfd	; get first FD on free list (assume free)
	mov	word ptr es:[SCB+SRFA],bx	; put into SCB
	mov	si,lastbd	; pointer to a BD, end of chain
	mov	ax,word ptr es:[si+BDLINK]	; pointer to next BD
	mov	word ptr es:[bx+FDPTR],ax	; set to start of BDs
;
;
;  Start the RU, doesn't need CB, only SCB parms.
;   command, to start receiving again
;
	mov	word ptr es:[SCB+SSTAT],0	; clear status word
	mov	word ptr es:[SCB+SCOM],010h	; start RU
	call	doca
hasres:
recv_isr_end:
	cmp	word ptr es:[SCB+SCOM],0 ;are we done yet?
	jne	recv_isr_end		;no -- keep waiting.
	ret


	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


	public	set_address
set_address:
	assume	ds:nothing
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
	cmp	cx,EADDR_LEN		;ensure that their address is okay.
	je	set_address_4
	mov	dh,BAD_ADDRESS
	stc
	jmp	short set_address_done
set_address_4:

;  Next step, load our address into the board
;     reuses the space that the configure command used, with different command
;
	mov	es,base_addr		; set to base address
	mov	word ptr es:[SCB+SCBL],CCBPTR	; say where conf command is

	mov	di,CCBPTR		; start of config command block
	xor	ax,ax
	stosw				; zero status word for commmand
	mov	ax,8001h		; IA setup command + EL
	stosw
	xor	ax,ax
	dec	ax
	stosw				; set link value to -1 (unused)

	rep	movsb			; move their ethernet address in.
;
;  start the IA setup command
;
	mov	word ptr es:[SCB+SCOM],0100h	; do-command command
	call	doca
	xor	cx,cx			; timeout
set_address_1:
	mov	ax,word ptr es:[CCBPTR]	; get status word
	test	ax,08000h		; is command complete?
	loopz	set_address_1
	jnz	set_address_okay
	stc
	mov	dh,-1			; no error in the list applies.
	jmp	short set_address_done
set_address_okay:
	mov	cx,EADDR_LEN		;return their address length.
	clc
set_address_done:
	push	cs
	pop	ds
	assume	ds:code
	ret


end_resident	label	byte

timeout_msg	db	"Timed out while initializing the board.",CR,LF,'$'
int_no_name	db	"Interrupt number ",'$'
io_addr_name	db	"I/O port ",'$'
base_addr_name	db	"Memory address ",'$'
our_address	db	6 dup(?)	;temporarily hold our address

tdr_ok_msg	db	"TDR Ok",CR,LF,'$'
tdr_none_msg	db	"Your Ethernet card doesn't seem to be plugged in.",CR,LF,'$'
tdr_open_msg	db	" clocks away is an OPEN",CR,LF,'$'
tdr_short_msg	db	" clocks away is a SHORT",CR,LF,'$'

mem8_16		db	2		; 1 for 16k, 2 for 8k

	extrn	set_recv_isr: near
	extrn	maskint: 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

;enter with ax = number to print.
	extrn	decout: near

	public	parse_args
parse_args:
	mov	di,offset int_no
	call	get_number
	mov	di,offset io_addr
	call	get_number
	mov	di,offset base_addr
	call	get_number
	sub	base_addr,BASE_OFFSET shr 4
	clc
	ret


timeout_error:
	mov	dx,offset timeout_msg
	jmp	short error
error:
	mov	ah,9
	int	21h
	stc
	ret

;
;  data for configuring and setting up the board
;
;  chip always looks at SCP for config info which points to ISCP for the
;  pointer to the CONTROL BLOCK which handles everything from there.
;  Kind of indirect, but it works.
;
SCP	DB	0			; bus use flag (0=16 bit, 1=8 bit).
	DB	5 DUP(0)		; unused
	DW	ISCPTR			; 24pointer to ISCP offset
	DW	0			; high part
;
; Intermediate SCP
;
ISCP	DW	1		; busy flag
	DW	SCB		; 16pointer to SCB
	DW	0,0		; base for all 16 pointers, lo, hi
				; board is hardwired to 0 for these values
;
; CB for xmit, followed by BD for xmit, copied together
;
TCB	DW	0		; status word
	DW	08004H		; command word for xmit + EL
	DW	0ffffh		; no command link
	DW	TBDPTR		; 16pointer to xmit BD
	DW	0,0,0,0		; no addressing used here
;
; BD template for xmit
TBD	DW	0
	DW	0		; next BD pointer, unused
	DW	TBUFPTR		; 24pointer to xmit buffer
	DW	0		; high part of pointer

	public	etopen
etopen:
	mov	al,int_no
	call	maskint			;disable these interrupts.

;  Initialize the Ethernet board, set receive type.
;
;  check for correct EPROM location
;
	call	check_board

;
;  Turn off interrupts, I don't want them
;
  ifdef IOINTOF
	loadport
	setport IOINTOF
	out	dx,al
  endif
;
;  Disconnect from network
;
  ifdef IODIS
	loadport
	setport	IODIS
	out	dx,al
  endif

;
;  Initialize the Ethernet board.
;
	mov	es,base_addr	; set to base address

;
;  Intermediate SCP
;
	mov	si,offset ISCP	; addr of pre-set values
	mov	di,ISCPTR
	mov	cx,4		; 4 words
	rep	movsw		; install ISCP

;
;  Now discern the end of memory by repeatedly re-initializing the board
;  until the BUSY flag in the ISCP gets reset.
;
	mov	di,SCPTR

re_discern:
	push	di
	mov	si,offset SCP	; get pre-set values
	mov	cx,5		; 5 words
	rep	movsw		; install SCP
	pop	di

  ifdef IORESET
;
;  Reset the chip
;
	loadport
	setport	IORESET
	out	dx,al
  endif
;
;  Issue a CA to initialize the chip after reset
;
	call	lbca

	mov	ax,2			;don't wait too long.
	call	set_timeout
confwait:
	cmp	byte ptr es:[ISCPTR],0	;did it clear the busy flag?
	je	confok			;yes.
	call	do_timeout
	jne	confwait

	add	di,2000h		;go up another 8K.
	jnc	re_discern		;try this next higher address.
confbad:
	sti
	jmp	timeout_error

confok:
	call	reconfigure
	jc	confbad

;
;  Ask the board for the Ethernet address, and then use set_address to set it.
;
	push	ds
	pop	es
	mov	di,offset our_address
	mov	cx,EADDR_LEN
	call	get_address

	mov	si,offset our_address
	mov	cx,EADDR_LEN
	call	set_address
	jnc	store_address_2
	sti
	jmp	timeout_error
store_address_2:
;
;  IA sent, setup all of the other data structures on the board
;  start with xmit command descriptors
;
	mov	si,offset TCB		; template for xmit
	mov	di,TCBPTR		; where it goes on board
	mov	cx,12			; copies CB and BD for xmit
	rep	movsw
;
;  Set up frame and buffer descriptors, 30 each
;
	mov	cx,BUF_COUNT		; # of FDs
	mov	di,FDBASE		; base addr for FDs
fdloop:
	xor	ax,ax
	mov	bx,di			; save pointer
	stosw				; clear status wd
	stosw				; clear EL field
	add	bx,22			; points to next one
	mov	es:[di],bx		; put in link ptr
	inc	di
	inc	di
	dec	ax
	stosw				; clear BD ptr to -1
	add	di,14
	loop	fdloop

	sub	di,20			; point back to last EL field
	mov	ax,08000h		; end of list
	stosw				; put into last FD
	sub	di,4			; back to beginning of last FD
	mov	lastfd,di		; save the pointer
	mov	word ptr es:[di+FDLINK],FDBASE	; make list circular,
						; from last to first

	mov	ax,BDBASE		; first BD
	mov	word ptr es:[FDBASE+FDPTR],ax	; put it in the first FD frame
;
;  now BDs
	mov	cx,BUF_COUNT
	mov	di,BDBASE		; start of BD area
	mov	dx,BUFBASE		; start of buffer area
bdloop:
	xor	ax,ax
	mov	bx,di			; save pointer
	stosw				; zero status field
	add	bx,10			; point to next record
	mov	es:[di],bx		; put in link ptr
	inc	di
	inc	di
	mov	es:[di],dx		; address of buffer, lo part
	inc	di
	inc	di
	stosw				; zero out high part
	mov	ax,200
	stosw				; store length field
	add	dx,ax			; add in length of buffer, updates ptr
	loop	bdloop

	sub	di,2			; back to last BD size field
	mov	ax,08000h+200		; end of list + 200
	stosw				; mark end of list
	sub	di,8			; back to last BDLINK field
	mov	ax,BDBASE
	stosw				; put link to beginning of list here
	sub	di,4			; back to beginning of last BD
	mov	lastbd,di		; save pointer to end of list
  ifdef IOENA
;
;  configure to connect to network
;
	loadport
	setport	IOENA			; enable network
	out	dx,al			; any al value
  endif
;
; Test to see if the network is okay.
;
	mov	di,CCBPTR		; start of config command block
	xor	ax,ax			; zero status word for commmand
	stosw
	mov	ax,8005h		; TDR command + EL
	stosw
	xor	ax,ax
	dec	ax
	stosw				; set link value to -1 (unused)
	inc	ax
	stosw				; zero time result.

	mov	word ptr es:[SCB+SCOM],0100h	; do-command command

	call	lbca

	xor	cx,cx			; timeout
do_tdr_1:
	mov	ax,word ptr es:[CCBPTR]	; get status word
	test	ax,08000h		; is command complete?
	loopz	do_tdr_1
	mov	ax,word ptr es:[CCBPTR+6]
	jnz	do_tdr_2
	mov	ax,2000h		; treat a timeout as an open
do_tdr_2:
	test	ax,8000h
	mov	dx,offset tdr_ok_msg
	jne	do_tdr_3
	mov	dx,offset tdr_short_msg
	test	ax,2000h
	je	do_tdr_4
	mov	dx,offset tdr_none_msg
	cmp	ax,2000h
	je	do_tdr_3
	mov	dx,offset tdr_open_msg
do_tdr_4:
	push	dx
	and	ax,2048-1
	xor	dx,dx
	call	decout
	pop	dx
do_tdr_3:
	mov	ah,9
	int	21h

;
;  Start the RU, doesn't need CB, only SCB parms.
;   command, to start receiving
;
	mov	word ptr es:[SCB+SSTAT],0		; clear status word
	mov	word ptr es:[SCB+SRFA],FDBASE	; set to frame descriptors
	mov	word ptr es:[SCB+SCOM],010h	; start RU
	call	lbca
;
; Now reset CX, FR, CNA, and RNR so that we don't get a spurious interrupt.
;
store_ack_1:
	cmp	word ptr es:[SCB+SCOM],0 ;are we done yet?
	jne	store_ack_1		;no -- keep waiting.

	mov	ax,es:[SCB+SSTAT]	;get the status.
	and	ax,0f000h		;isolate the ACK bits.
	mov	es:[SCB+SCOM],ax	;make a command to
					;acknowledge the interrupt.
	call	doca
;
; 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.

	mov	dx,offset end_resident
	clc
	ret

	public	print_parameters
print_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 base_addr
	mov	dx,offset base_addr_name
	call	print_number
	ret
