version	equ	2

	include	defs.asm

;Ported from Bill Doster's il.c, a C-language driver for the Interlan NI5010
;by Russell Nelson.  Any bugs are due to Russell Nelson.
;Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.

;   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.

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

; The various IE command registers
EDLC_XSTAT	equ	0		; EDLC transmit csr
EDLC_XCLR	equ	0		; EDLC transmit "Clear IRQ"
EDLC_XMASK	equ	1		; EDLC transmit "IRQ Masks"
EDLC_RSTAT	equ	2		; EDLC receive csr
EDLC_RCLR	equ	2		; EDLC receive "Clear IRQ"
EDLC_RMASK	equ	3		; EDLC receive "IRQ Masks"
EDLC_XMODE	equ	4		; EDLC transmit Mode
EDLC_RMODE	equ	5		; EDLC receive Mode
EDLC_RESET	equ	6		; EDLC RESET register
EDLC_TDR1	equ	7		; "Time Domain Reflectometry" reg1
EDLC_ADDR	equ	8		; EDLC station address, 6 bytes
					; 0Eh doesn't exist for r/w
EDLC_TDR2	equ	0fh		; "Time Domain Reflectometry" reg2
IE_GP		equ	10h		; GP pointer (word register)
					; 11h is 2nd byte of GP Pointer
IE_RCNT		equ	10h		; Count of bytes in rcv'd packet
					; 11h is 2nd byte of "Byte Count"
IE_MMODE	equ	12h		; Memory Mode register
IE_DMA_RST	equ	13h		; IE DMA Reset.  write only
IE_ISTAT	equ	13h		; IE Interrupt Status.  read only
IE_RBUF		equ	14h		; IE Receive Buffer port
IE_XBUF		equ	15h		; IE Transmit Buffer port
IE_SAPROM	equ	16h		; window on station addr prom
IE_RESET	equ	17h		; any write causes Board Reset

; bits in EDLC_XSTAT, interrupt clear on write, status when read
XS_TPOK		equ	80h		; transmit packet successful
XS_CS		equ	40h		; carrier sense
XS_RCVD		equ	20h		; transmitted packet received
XS_SHORT	equ	10h		; transmission media is shorted
XS_UFLW		equ	08h		; underflow.  iff failed board
XS_COLL		equ	04h		; collision occurred
XS_16COLL	equ	02h		; 16th collision occurred
XS_PERR		equ	01h		; parity error

XS_CLR_UFLW	equ	08h		; clear underflow
XS_CLR_COLL	equ	04h		; clear collision
XS_CLR_16COLL	equ	02h		; clear 16th collision
XS_CLR_PERR	equ	01h		; clear parity error

; bits in EDLC_XMASK, mask/enable transmit interrupts.  register is r/w
XM_TPOK		equ	80h		; =1 to enable Xmt Pkt OK interrupts
XM_RCVD		equ	20h		; =1 to enable Xmt Pkt Rcvd ints
XM_UFLW		equ	08h		; =1 to enable Xmt Underflow ints
XM_COLL		equ	04h		; =1 to enable Xmt Collision ints
XM_COLL16	equ	02h		; =1 to enable Xmt 16th Coll ints
XM_PERR		equ	01h		; =1 to enable Xmt Parity Error ints
					; note: always clear this bit

; bits in EDLC_RSTAT, interrupt clear on write, status when read
RS_PKT_OK	equ	80h		; received good packet
RS_RST_PKT	equ	10h		; RESET packet received
RS_RUNT		equ	08h		; Runt Pkt rcvd.  Len < 64 Bytes
RS_ALIGN	equ	04h		; Alignment error. not 8 bit aligned
RS_CRC_ERR	equ	02h		; Bad CRC on rcvd pkt
RS_OFLW		equ	01h		; overflow for rcv FIFO
RS_VALID_BITS	equ	RS_PKT_OK or RS_RST_PKT or RS_RUNT or RS_ALIGN or RS_CRC_ERR or RS_OFLW
					; all valid RSTAT bits

RS_CLR_PKT_OK	equ	80h		; clear rcvd packet interrupt
RS_CLR_RST_PKT	equ	10h		; clear RESET packet received
RS_CLR_RUNT	equ	08h		; clear Runt Pckt received
RS_CLR_ALIGN	equ	04h		; clear Alignment error
RS_CLR_CRC_ERR	equ	02h		; clear CRC error
RS_CLR_OFLW	equ	01h		; clear rcv FIFO Overflow

; bits in EDLC_RMASK, mask/enable receive interrupts.  register is r/w
RM_PKT_OK	equ	80h		; =1 to enable rcvd good packet ints
RM_RST_PKT	equ	10h		; =1 to enable RESET packet ints
RM_RUNT		equ	08h		; =1 to enable Runt Pkt rcvd ints
RM_ALIGN	equ	04h		; =1 to enable Alignment error ints
RM_CRC_ERR	equ	02h		; =1 to enable Bad CRC error ints
RM_OFLW		equ	01h		; =1 to enable overflow error ints

; bits in EDLC_RMODE, set Receive Packet mode.  register is r/w
RMD_TEST	equ	80h		; =1 for Chip testing.  normally 0
RMD_ADD_SIZ	equ	10h		; =1 5-byte addr match.  normally 0
RMD_EN_RUNT	equ	08h		; =1 enable runt rcv.  normally 0
RMD_EN_RST	equ	04h		; =1 to rcv RESET pkt.  normally 0

RMD_PROMISC	equ	03h		; receive *all* packets.  unusual
RMD_MULTICAST	equ	02h		; receive multicasts too.  unusual
RMD_BROADCAST	equ	01h		; receive broadcasts & normal. usual
RMD_NO_PACKETS	equ	00h		; don't receive any packets. unusual

; bits in EDLC_XMODE, set Transmit Packet mode.  register is r/w
XMD_COLL_CNT	equ	0f0h		; coll's since success.  read-only
XMD_IG_PAR	equ	008h		; =1 to ignore parity.  ALWAYS set
XMD_T_MODE	equ	004h		; =1 to power xcvr. ALWAYS set this
XMD_LBC		equ	002h		; =1 for loopbakc.  normally set
XMD_DIS_C	equ	001h		; =1 disables contention. normally 0

; bits in EDLC_RESET, write only
RS_RESET	equ	80h		; =1 to hold EDLC in reset state

; bits in IE_MMODE, write only
MM_EN_DMA	equ	80h		; =1 begin DMA xfer, Cplt clrs it
MM_EN_RCV	equ	40h		; =1 allows Pkt rcv.  clr'd by rcv
MM_EN_XMT	equ	20h		; =1 begin Xmt pkt.  Cplt clrs it
MM_BUS_PAGE	equ	18h		; =00 ALWAYS.  Used when MUX=1
MM_NET_PAGE	equ	06h		; =00 ALWAYS.  Used when MUX=0
MM_MUX		equ	01h		; =1 means Rcv Buff on system bus
					; =0 means Xmt Buff on system bus

; bits in IE_ISTAT, read only
IS_TDIAG	equ	80h		; =1 if Diagnostic problem
IS_EN_RCV	equ	20h		; =1 until frame is rcv'd cplt
IS_EN_XMT	equ	10h		; =1 until frame is xmt'd cplt
IS_EN_DMA	equ	08h		; =1 until DMA is cplt or aborted
IS_DMA_INT	equ	04h		; =0 iff DMA done interrupt. 
IS_R_INT	equ	02h		; =0 iff unmasked Rcv interrupt
IS_X_INT	equ	01h		; =0 iff unmasked Xmt interrupt

BFRSIZ		equ	2048	;number of bytes in a buffer

	public	int_no
int_no		db	3,0,0,0		; interrupt number.
io_addr		dw	0300h,0		; I/O address for card (jumpers)
ipkt_size	dw	?
opkt_size	dw	?

	public	driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class	db	BLUEBOOK, IEEE8023, 0		;from the packet spec
driver_type	db	3		;from the packet spec
driver_name	db	'NI5010',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	7		;number of receive modes in our table.
		dw	0               ;There is no mode zero
		dw	rcv_mode_1
		dw	0		;don't want to bother.
		dw	rcv_mode_3
		dw	0		;haven't set up perfect filtering yet.
		dw	rcv_mode_5
		dw	rcv_mode_6

	extrn	is_186: byte		;=0 if 808[68], =1 if 80[123]86.
our_type	dw	?,?
intstat		db	?

	include	popf.asm
	include	io8.asm

	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


	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
	cmp	cx,GIANT		; Is this packet too large?
	ja	send_pkt_toobig

	cmp	cx,RUNT		; minimum length for Ether
	jae	oklen
	mov	cx,RUNT		; make sure size at least RUNT
oklen:
;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
;only in the transmit mode, hence the initial check.

	loadport
	setport	IE_ISTAT
	in	al,dx
	and	al,IS_EN_XMT		;on-going xmit
	je	send_pkt_2

	mov	bx,20000		;try this many times.
send_pkt_3:
	in	al,dx			;if not busy, exit.
	and	al,IS_EN_XMT
	je	send_pkt_2
	dec	bx
	jne	send_pkt_3
	mov	dh,CANT_SEND		;timed out, can't send.
	stc
	ret

send_pkt_toobig:
	mov	dh,NO_SPACE
	stc
	ret

send_pkt_2:

	pushf			; No distractions from the receiver
	cli

; Disable the Receiver
	mov	al, 0		; Mask all Receive Interrupts
	loadport
	setport	EDLC_RMASK
	out	dx,al

	mov	al, 0		; Put Xmt Buffer on System Bus
	setport	IE_MMODE
	out	dx,al

	mov	al, 0FFh	; Clear out any pending Rcv Ints
	setport	EDLC_RCLR
	out	dx,al

	mov	ax, BFRSIZ	; Point GP at beginning of packet
	sub	ax,cx
	setport	IE_GP
	out	dx,ax

	setport	IE_XBUF

	mov	opkt_size,cx	; opkt_size = cx;
	call	repoutsb

; Rewrite where packet starts
	mov	ax,BFRSIZ
	sub	ax,opkt_size
	setport	IE_GP
	out	dx,ax

; Flip Xmt Buffer to EDLC Bus so it can be transmitted
	mov	al, MM_MUX
	setport	IE_MMODE
	out	dx,al

; Begin transmission.
	mov	al, MM_EN_XMT or MM_MUX
	setport	IE_MMODE
	out	dx,al

; Cause interrupt after completion (or if something fails)
	mov	al, XM_TPOK or XM_RCVD or XM_UFLW or XM_COLL or XM_COLL16
	setport	EDLC_XMASK
	out	dx,al

	popf
	clc
	ret


;Set Ethernet address on controller
	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:

	loadport
	setport	EDLC_ADDR
set_address_1:
	lodsb
	out	dx,al
	inc	dx
	loop	set_address_1
set_address_okay:
	mov	cx,EADDR_LEN		;return their address length.
	clc
set_address_done:
	movseg	ds,cs
	assume	ds:code
	ret


;skip past the following two bytes while destroying BX.
skip2	macro
	db	0bbh			;opcode of "mov bx,0000"
	endm

rcv_mode_1:
	mov	al,RMD_NO_PACKETS	;receive nothing
	skip2
rcv_mode_3:
	mov	al,RMD_BROADCAST	;receive individual address+broadcast
	skip2
rcv_mode_5:
	mov	al,RMD_MULTICAST	;receive individual address+group addr(multicast)
	skip2
rcv_mode_6:
	mov	al,RMD_PROMISC + RMD_EN_RUNT	;receive all packets (incl runts).
	loadport
	setport	EDLC_RMODE
	out	dx,al
	in	al,dx			;flush status.
	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:
; put card in held-RESET state
	loadport
	setport	IE_MMODE
	mov	al,0
	out	dx,al

	setport	EDLC_RESET
	mov	al,RS_RESET
	out	dx,al

	ret


	public	reset_interface
reset_interface:
;reset the interface.
;we don't do anything.
	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

	loadport
	setport	IE_ISTAT
	in	al,dx
	mov	intstat,al

; DMA Complete Interrupt.  We don't use DMA, but just in case ...
	test	al,IS_DMA_INT
	jne	recv_isr_3

	mov	al, 0		 ; Reset DMA Interrupt
	setport	IE_DMA_RST
	out	dx,al

recv_isr_3:

; Transmit Complete/Fail Interrupt
	test	intstat,IS_X_INT
	jne	recv_isr_1

	loadport
	setport	EDLC_XSTAT
	in	al,dx
	mov	ah,al

	mov	al, 0			; Disable Xmt IRQ's
	setport	EDLC_XMASK
	out	dx,al

	mov	al, 0FFh		; clr all Xmt IRQ's
	setport	EDLC_XCLR
	out	dx,al

	test	ah,XS_COLL
	je	recv_isr_1
	;Crank counter back to beginning and restart xmt

	mov	ax,BFRSIZ		; Point GP at beginning of packet
	sub	ax,opkt_size
	setport	IE_GP
	out	dx,ax

	mov	al, 0		; De-assert MM_EN_RCV bit Just In Case
	setport	IE_MMODE
	out	dx,al

				; Flip Xmt Buffer to EDLC Bus and restart xmt
	mov	al, MM_EN_XMT or MM_MUX
	setport	IE_MMODE
	out	dx,al

			; Interrupt for all Transmit errors along with TPOK
	mov	al, XM_TPOK or XM_RCVD or XM_UFLW or XM_COLL or XM_COLL16
	setport	EDLC_XMASK
	out	dx,al

	ret			; Wait for it to complete again

recv_isr_1:
	; Is this a Receive Packet Interrupt?
	test	intstat,IS_R_INT
	jne	recv_isr_9_j_1		;no.

	loadport
	setport	EDLC_RSTAT		;get the status of this packet
	in	al,dx
	and	al,RS_VALID_BITS
	cmp	al,RS_PKT_OK		;is it ok?
	jne	recv_isr_7		;yes.

	; Clear the interrupt
	mov	al, 0FFh
	setport	EDLC_RCLR
	out	dx,al

	; Flip Rcv Buffer onto the system bus
	mov	al, MM_MUX
	setport	IE_MMODE
	out	dx,al

	; Get the size of the packet.
	setport	IE_RCNT
	in	ax,dx
	mov	ipkt_size,ax

	cmp	ax,GIANT		;greater than GIANT?
	jbe	recv_isr_8		;no.
recv_isr_7:
	call	count_in_err
recv_isr_9_j_1:
	jmp	recv_isr_9
recv_isr_8:
;Put it on the receive queue

	loadport
	mov	ax,EADDR_LEN+EADDR_LEN			;seek to the type word.
	setport	IE_GP
	out	dx,ax

	setport	IE_RBUF
	in	al,dx			;read the type word out of the board.
	mov	ah,al
	in	al,dx
	xchg	al,ah			;should be in network byte order.
	mov	our_type,ax
	in	al,dx			;read the type word out of the board.
	mov	ah,al
	in	al,dx
	xchg	al,ah			;should be in network byte order.
	mov	our_type+2,ax

	mov	ax,ds			;look up our type.
	mov	es,ax
	mov	di,offset our_type
	mov	cx,ipkt_size

	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

	mov	ax,es			;is this pointer null?
	or	ax,di
	je	recv_isr_9		;yes - just free the frame.

	push	es			;remember where the buffer pointer is.
	push	di

	xor	ax,ax			;seek to the beginning again.
	loadport
	setport	IE_GP
	out	dx,ax

	mov	cx,ipkt_size
	setport	IE_RBUF

	call	repinsb

	pop	si
	pop	ds
	assume	ds:nothing
	mov	cx,ipkt_size
	call	recv_copy		;tell them that we copied it.

	mov	ax,cs			;restore our ds.
	mov	ds,ax
	assume	ds:code

recv_isr_9:

; Prime Interlan card for another Receive
il_rcv_reset:

	; Rcv packet at start of Boards buffer
	mov	ax,0
	loadport
	setport	IE_GP
	out	dx,ax

	; Clear any remaining Interrupt conditions
	mov	al,0FFh
	setport	EDLC_RCLR
	out	dx,al

	; Set MUX to allow EDLC to access Rcv Buffer
	mov	al,0
	setport	IE_MMODE
	out	dx,al

;
;	Next section commented out to make promiscous mode work.
;	It makes no sense to reset the receive mode after each
;	received packet. M.K.
;
	; Enable Receive of Normal and Broadcast Packets only.
;	mov	al,RMD_BROADCAST
;	setport	EDLC_RMODE
;	out	dx,al

	; Enable Receive Interrupts
	mov	al,MM_EN_RCV
	setport	IE_MMODE
	out	dx,al

	; Unmask *all* Receive related interrupts
	mov	al,0FFh
	setport	EDLC_RMASK
	out	dx,al

	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.  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: NI5010 [options] <packet_int_no> <hardware_irq> <io_addr>",CR,LF,'$'

	public	copyright_msg
copyright_msg	db	"Packet driver for the Interlan NI5010, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
		db	"Portions Copyright 1988 Bill Doster",CR,LF,CR,LF
		db	"Promiscous mode fixed by Martin Knoblauch (22-Aug-90).",CR,LF
		db	"Flame <XBR2D96D@DDATHD21.BITNET> for related problems",CR,LF,CR,LF,'$'

no_ni5010_msg	db	"No NI5010 found at that address.",CR,LF,'$'
ether_bdcst	db	EADDR_LEN dup(-1)	;ethernet broadcast address.

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

	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

;-> 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.
	mov	di,offset int_no
	call	get_number
	mov	di,offset io_addr
	call	get_number
	clc
	ret


no_ni5010_error:
	mov	dx,offset no_ni5010_msg
	stc
	ret


	public	etopen
etopen:
;  Initialize the Ethernet board, set receive type.
;
;  check for correct EPROM location
;
	mov	al,int_no
	call	maskint			;disable these interrupts.

	; Hold up EDLC RESET while the board is configured
	mov	al,RS_RESET
	loadport
	setport	EDLC_RESET
	out	dx,al

	; Hardware reset of Interlan Board
	mov	al,0
	setport	IE_RESET
	out	dx,al

	call	set_recv_isr

	mov	al,XMD_LBC
	loadport
	setport	EDLC_XMODE
	out	dx,al

	movseg	es,ds
	mov	di,offset rom_address
	mov	cx,EADDR_LEN+3		;get three extra signature bytes.
	xor	bx,bx
get_address_1:
	mov	ax,bx
	loadport
	setport	IE_GP
	out	dx,ax

	setport	IE_SAPROM
	in	al,dx
	stosb
	inc	bx
	loop	get_address_1

	mov	si,offset rom_address
	mov	cx,EADDR_LEN
	call	set_address

;See if there really is a ni5010 there.
	cmp	rom_address+EADDR_LEN+0,0
	jne	no_ni5010
	cmp	rom_address+EADDR_LEN+1,055h
	jne	no_ni5010
	cmp	rom_address+EADDR_LEN+2,0aah
	jne	no_ni5010

	mov	cx,EADDR_LEN
	mov	di,offset ether_bdcst
	repe	cmpsb
	jne	have_ni5010		;not broadcast address -- must be real.
no_ni5010:
	jmp	no_ni5010_error		;not there -- no ni5010.
have_ni5010:

	; Only enable Transmit-type interrupts while Transmitting
	mov	al,0
	loadport
	setport	EDLC_XMASK
	out	dx,al

	; Establish generic Transmit mode
	mov	al,XMD_IG_PAR or XMD_T_MODE or XMD_LBC
	setport	EDLC_XMODE
	out	dx,al

	; Clear any startup related Transmit interrupts
	mov	al,0FFh
	setport	EDLC_XCLR
	out	dx,al

	; Establish generic Receive mode
	mov	al,RMD_BROADCAST
	setport	EDLC_RMODE
	out	dx,al

	; Reset Rcv State to allow receives
	call	il_rcv_reset

	; Finally un-reset the EDLC
	mov	al,0
	loadport
	setport	EDLC_RESET
	out	dx,al

	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	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

code	ends

	end
