version	equ	0

	include	defs.asm
;		ntinet.mac
;
;  macros used for calling c routines.
;
pusharg	macro	seg, off
	ifnb	<seg>
	  push	seg
	$$cnt = $$cnt+2
	endif
	ifnb	<off>
	  push	off
	$$cnt = $$cnt+2
	endif
	endm


ccall	macro	rtn, p1, p2, p3, p4, p5
$$cnt = 0
	ifnb	<p5>
	  pusharg	p5
	endif
	ifnb	<p4>
	  pusharg	p4
	endif
	ifnb	<p3>
	  pusharg	p3
	endif
	ifnb	<p2>
	  pusharg	p2
	endif
	ifnb	<p1>
	  pusharg	p1
	endif
	  call	rtn
	if $$cnt
	  add	sp,$$cnt
	endif
	endm

save	macro	regs
	  irp	arg,<regs>
	  push	arg
	  endm
	endm
	
restore	macro	regs
	  irp	arg,<regs>
	  pop	arg
	  endm
	endm	

;
; LANCE.INC
;
; lance registers
;
CSR0	equ	0		;control and status register 0
CSR1	equ	1
CSR2	equ	2
CSR3	equ	3
;
;-------------------------------------------------------------------------
; control and status register 0
; rap = 0
;
;	|---------------|---------------|---------------|---------------|
;	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| e | b | c | m	| m | r	| t | i	| i | i | r | t	| t | s	| s | i	|
;	| r | a	| e | i	| e | i	| i | d	| n | n | x | x	| d | t	| t | n	|
;	| r | b	| r | s	| r | n	| n | o	| t | e | o | o	| n | o	| r | i	|
;	|   | l	| r | s	| r | t	| t | n	| r | a | n | n	| d | p	| t | t	|
;	|---------------|---------------|---------------|---------------|
;
L_ERR	equ	8000h		;or of babl, cerr, miss, merr (read only)
L_BABL	equ	4000h		;transmit timeout error	(write 1 clear)
L_CERR	equ	2000h		;collision error (sqe error) (write 1 clear)
L_MISS	equ	1000h		;no buffer on receive (write 1 clear)
;
L_MERR	equ	0800h		;bus timeout error (write 1 clear)
L_RINT	equ	0400h		;receive interrupt (write 1 clear)
L_TINT	equ	0200h		;transmit interrupt (write 1 clear)
L_IDON	equ	0100h		;initialization done (write 1 clear)
;
L_INTR	equ	0080h	;interrupt (or of babl,miss,merr,rint,tint,idon
L_INEA	equ	0040h		;interrupt enable
L_RXON	equ	0020h		;receiver on
L_TXON	equ	0010h		;transmitter on
;
L_TDND	equ	0008h		;transmit demand
L_STOP	equ	0004h		;stop
L_STRT	equ	0002h		;start
L_INIT	equ	0001h		;initialize
;
L_MASK	equ	l_babl+l_cerr+l_miss+l_merr+l_rint+l_tint



;-----------------------------------------------------------------------
; control and status register 1
; rap = 1
;
;  Accessable when csr0 stop = 1
;
;	 ---------------------------------------------------------------
;	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                  iadr  (bits 1 - 15)                      | 0 |
;	 ---------------------------------------------------------------
;
; iadr - The low order 16 bits of the address of the first
;         in the initialization Block.
;
;----------------------------------------------------------------------
; control and status register 2
; rap = 2
;
;  Accessable when csr0 stop = 1
;
;	|---------------|---------------|---------------|---------------|
;	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |       iadr (bits 16 - 32)     |
;	 ---------------------------------------------------------------
;
; iadr - (bits 16 - 32) The hi order 8 bits of the address of the first
;         in the initialization Block.
;
;-------------------------------------------------------------------------
; control and status register 3
; rap = 3
;
;  Accessable when csr0 stop = 1
;
;	|---------------|---------------|---------------|---------------|
;	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | b	| a | b	|
;       |                                                   | s	| c | c	|
;	|                                                   | w	| o | o	|
;       |                                                   | p	| n | n	|
;	 ---------------------------------------------------------------
;
L_BSWP	equ	0004			;0 = <0:7> even addresses byte swap 
L_ACON	equ	0002			;0 = ale, 1 = /as
L_BCON	equ	0001			;0 = /bm1, bm0, /hold
;
BUS_MASTER	equ	0		;initialization word
;



;------------------------------------------------------------------------
; initialization block
;
init_block	struc
i_mode	dw	0		;mode register usually 0
i_padr	db	0,0,0,0,0,0	;ethernet address
i_ladrf	db	0,0,0,0,0,0,0,0	;logical address filter (mulitcast filter)
i_rdra	dw	0		;lo order pointer to receive descriptor ring
i_rlen	dw	0		;number of rec descriptors (power of 2)
i_tdra	dw	0		;lo order pointer to transmit descriptor ring
i_tlen	dw	0		;number of xmit descritport (power of 2)
init_block	ends

INITBLK_SZ	equ	SIZE 	init_block

;
;l_mode
;
; offset
;	|---------------|---------------|---------------|---------------|
;   00	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| p | 0	| 0 | 0	| 0 | 0	| 0 | 0	| 0 | i | d | c | d | l	| d | d	|
;	| r | 				    | n | t | o | t | o	| t | r	|
;	| o | 				    | t | r | l | c | o	| x | x	|
;	| m | 				    | l | y | l | r | p	|   |	|
;	 ---------------------------------------------------------------
;
L_PROM	equ	8000h		;promiscuous mode
L_INTL	equ	0040h		;internal loop back
L_DRTY	equ	0020h		;disable retry
L_COLL	equ	0010h		;force collision
L_DTCR	equ	0008h		;disable transmit crc
L_LOOP	equ	00040		;loop back
L_DTX	equ	0002h		;disable transmitter
L_DRX	equ	0001h		;disable receiver
;
RUN_MODE	equ	0		;run mode
XMIT_MODE	equ	l_drx		;disable receiver
RCV_MODE	equ	l_dtx		;disable xmitter
TEST_MODE	equ	l_intl+l_loop	;diagnostics mode
;



; physical address
;
; offset
;	 ---------------------------------------------------------------
;   02	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 0 - 15                         | 0 |
;	 ---------------------------------------------------------------
;
;	 ---------------------------------------------------------------
;   04	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 16 - 31                            |
;	 ---------------------------------------------------------------
;
;	 ---------------------------------------------------------------
;   06	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 32 - 47			        |
;	 ---------------------------------------------------------------
;
;
; Multicast address
;
; offset
;	 ---------------------------------------------------------------
;   08	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 0 - 15                             |
;	 ---------------------------------------------------------------
;
;	 ---------------------------------------------------------------
;   0a	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 16 - 31                            |
;	 ---------------------------------------------------------------
;
;	 ---------------------------------------------------------------
;   0c	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 32 - 47			        |
;	 ---------------------------------------------------------------
;
;	 ---------------------------------------------------------------
;   0e  |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       bits 38 - 63			        |
;	 ---------------------------------------------------------------
;
;
; Receive Descriptor Ring Pointer
;
; offset
;	|---------------|---------------|---------------|---------------|
;   10	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|   rlen    | 0 | 0 | 0 | 0 | 0 |     rdra  (bits 16 - 23)      |
;	 ---------------------------------------------------------------
;
;	|---------------|---------------|---------------|---------------|
;   12	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       rdra  (bits 3 - 15)	    | 0 | 0 | 0 |
;	 ---------------------------------------------------------------
; 	note rings are aligned on quad word boundries
;
;	  		  number of entries
;      			  -----------------
RLEN1	equ	00h	; 1
RLEN2	equ	20h  	; 2
RLEN4	equ	40h  	; 4
RLEN8	equ	60h  	; 8
RLEN16	equ	80h 	; 16
RLEN32	equ	0a0h 	; 32
RLEN64	equ	0c0h 	; 64
RLEN128	equ	0e0h	; 128
;
; Transmit Descriptor Ring Pointer
;
; offset
;	|---------------|---------------|---------------|---------------|
;   14	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|   tlen    | 0 | 0 | 0 | 0 | 0 |     tdra  (bits 16 - 23)      |
;	 ---------------------------------------------------------------
;
;	|---------------|---------------|---------------|---------------|
;   16	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                       tdra  (bits 3 - 15)	    | 0 | 0 | 0 |
;	 ---------------------------------------------------------------
; 	note rings are aligned on quad word boundries
;
;			 number of entries
;       		 -----------------
TLEN1	equ	00h	; 1
TLEN2	equ	20h  	; 2
TLEN4	equ	40h  	; 4
TLEN8	equ	60h  	; 8
TLEN16	equ	80h 	; 16
TLEN32	equ	0a0h 	; 32
TLEN64	equ	0c0h 	; 64
TLEN128	equ	0e0h	; 128
;
;------------------------------------------------------------------------
;
; Receive descriptor ring
;
rec_desc_ring	struc
rd_addr	dw	0		;lo order address of the buffer attached
rd_stat	dw	0		;buffer status and hi order pointer
rd_bcnt	dw	0		;buffer byte count
rd_mcnt	dw	0		;message byte count
rec_desc_ring	ends
RDESCLEN	equ	SIZE rec_desc_ring
;
;
; rmd0
; rd_addr
;
;offset	 ---------------------------------------------------------------
;   00	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                     ladr  (bits 0 - 15)                       |
;	 ---------------------------------------------------------------
;
; lo order 16 bits of the buffer pointed to by this descriptor
;
;
; rmd1
; rd_stat
;
;	|---------------|---------------|---------------|---------------|
;   02	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| o | e | f | o	| c | b	| s | e	|     hadr  (bits 16 - 23)      |
;	| w | r	| r | f	| r | u	| t | n	| 				|
;	| n | r	| a | l	| c | f	| p | p	| 				|
;	|   | 	| m | o	|   | f	|   | 	| 				|
;	 ---------------------------------------------------------------
;
; status and hi order bits of buffer pointer to by this descriptor
;
R_OWN	equ	8000h		;0 = full, host set after read data
R_ERR	equ	4000h
;
; receive status
R_FRAM	equ	2000h		;framing error (cleared by host)
R_OFLO	equ	1000h		;silo overflow (cleared by host)
R_CRC	equ	0800h		;crc error (cleared by host)
R_BUFF	equ	0400h		;buffer error (cleared by host)
R_STP	equ	0200h		;Start of Packet (cleared by host)
R_ENP	equ	0100h		;End of Packet (cleared by host)
;
; rmd2
; rd_bcnt
;
;	|---------------|---------------|---------------|---------------|
;   04	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| 1 | 1 | 1 | 1	|               bcnt                            |
;	 ---------------------------------------------------------------
;
; bcnt - Length of buffer pointed to by this desctriptor, two's compliment
;
RD_MASK	equ	0F000h		;or mask
;
; rmd3
; rd_mcnt
;
;	|---------------|---------------|---------------|---------------|
;   06	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| 0 | 0 | 0 | 0	|               mcnt                            |
;	 ---------------------------------------------------------------
;
; mcnt - Length of message in buffer
;
mcnt_mask	equ	0fffh	;

;------------------------------------------------------------------------
;
; Transmit descriptor ring
;
xmt_desc_ring	struc
td_addr	dw	0		;lo order address of the buffer attached
td_stat	dw	0		;buffer status and hi order pointer
td_bcnt	dw	0		;buffer byte count
td_tdr	dw	0		;errors and tdr count
xmt_desc_ring	ends
TDESCLEN	equ	SIZE xmt_desc_ring
;
;
; tmd0
; td_addr
; 
;	|---------------|---------------|---------------|---------------|
;   00	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	|                     ladr  (bits 0 - 15)                       |
;	 ---------------------------------------------------------------
;
; lo order 16 bits of the buffer pointed to by this descriptor
;
;
; tmd1
; td_stat
;
;	|---------------|---------------|---------------|---------------|
;   02	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| o | e | 0 | m	| o | d	| s | e	|     hadr  (bits 16 - 23)      |
;	| w | r	|   | o	| n | e	| t | n	| 				|
;	| n | r	|   | r	| e | f	| p | p	| 				|
;	|   | 	|   | e	|   | 	|   | 	| 				|
;	 ---------------------------------------------------------------
;
; status and hi order bits of buffer pointer to by this descriptor
;
;
; transmit status
;
T_OWN	equ	8000h		;0 = empty host set when full
T_ERR	equ	4000h
;
T_MORE	equ	1000h		;16 retrys (set by lance, cleared by host)
T_ONE	equ	0800h		;one retry (set by lance, cleared by host)
T_DEF	equ	0400h		;deffered xsmit (setby lance, cleared by host)
T_STP	equ	0200h		;First buffer in packet (set/cleared by host)
T_ENP	equ	0100h		;End of Packet (set/cleared by host
;
;
;
; tmd2
; td_bcnt
;
;	|---------------|---------------|---------------|---------------|
;   04	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| 1 | 1 | 1 | 1	|               bcnt                            |
;	 ---------------------------------------------------------------
;
; bcnt - Length of buffer pointed to by this desctriptor, expressed as a
;        twos compliment negative number.
;
TD_BMASK	equ	0F000h		;or mask
;
;
;
; tmd3
; td_tdr
;
;	|---------------|---------------|---------------|---------------|
;   06	|15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6	| 5 | 4 | 3 | 2 | 1 | 0	|
;	|---------------------------------------------------------------|
;	| b | u | 0 | l	| l | r |   tdr  (time domain reflectometery)   |
;	| u | f	|   | c	| c | t	|					|
;	| f | l	|   | o	| a | r	|					|
;	| f | o	|   | l	| r | y	|					|
;	 ---------------------------------------------------------------
;	only valid if the err bit in tmd1 is set
;
T_BUFF	equ	8000h	;buffer error (set by lance, uflo also set)
T_UFLO	equ	4000h	;silo underflow (set by lance,cleared by host)
T_LCOL	equ	1000h	;late collision (set by lance,cleared by host)
T_LCAR	equ	0800h	;loss of carrier (set by lance,cleared by host)
T_RTRY	equ	0400h	;tried 16 times (set by lance,cleared by host)

;
;  GLBL.INC
;
;  global equates for lance dumb board
;
pt_status	equ	0		;read status port
pt_clrclk	equ	0		;write to clear clock interrupt
pt_etaddr	equ	1		;read ether address rom offset
pt_resetl	equ	1		;write to reset lance
pt_ldata	equ	2		;lance data port 2,3
pt_laddr	equ	4		;lance address port 4,5

st_mask		equ	0ch		;00001100B for (is1 is0)

;int selects
irqn_10	equ	00h			;(is0 is1) = (0 0)
irqn_11	equ	04h			;(0 1)
irqn_12	equ	08h			;(1 0)
irqn_15	equ	0ch			;(1 1)

IRQ10		equ	10

; status port bits

NET_INT	equ	01h		;bit for net interrupt status
CLK_INT	equ	02h		;bit for clock interrupt status
IPL	equ	04h		;ipl bit
HILO	equ	08h		;ram at 0000, or ram at 8000
MINT	equ	net_int+clk_int		;interrupt mask
ADDR	equ	0F0h		;mask for dual port segment


DPLEN	equ	8000h		;length of dual port ram
BUFSIZE equ	1518		;should change to GIANT + 4(CRC)

; Packet sizes = source(6) + destination(6) + type (2) + I field. (803.2 spec)
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Following is the list of variables that need to be adjusted if the dp
;usage is changed:
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

XAREA		equ	5F78H		;start of transmit descriptors
RAREA		equ	0018h		;start of receive descriptors

NUMTDESC	equ	4		;number of transmit descriptors
NUMRDESC	equ	16 		;number of receive descriptors

TBAREA	equ	XAREA+(NUMTDESC*tdesclen)	;xmit buf pool
RBAREA	equ	RAREA+(NUMRDESC*rdesclen)   	;rcv buffer pool

;our data segment is a constant distance from the es!
OUROFFSET	equ	TBAREA + NUMTDESC*BUFSIZE

RLEN	equ	RLEN16			;lance mask for rcv-descriptors
TLEN	equ	TLEN4			;lance mask for snd-descriptors

;the total dp size reserved for lance use
LANCE_SZ equ	INITBLK_SZ+ NUMRDESC*(RDESCLEN+BUFSIZE)+ NUMTDESC*(TDESCLEN+BUFSIZE)

;the end of RAERA
OUTOF_BOUND	equ 	RBAREA		;98; for wrap up checking of r-descs


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

	extrn	maskint:near
	extrn	set_recv_isr: near


	public	int_no, io_addr, base_addr
int_no		db	3,0,0,0		; interrupt number. 
io_addr		dw	0338h,0		; I/O address for card (jumpers)
base_addr	dw  	0d000h,0	; base segment for board (jumper set)

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

nosdesc_msg	db	CR,LF,"no send descriptor.",'$'
chperr_msg	db	CR,LF,"chip doesn't want to finish init",'$'
porterr_msg	db	CR,LF,"wrong port #",'$'
hwerr_msg	db	CR,LF,"hardware error",'$'
initerr_msg	db 	CR,LF,"can't init lance chip",'$'
good_msg	db	CR,LF,"Lance initialized successfully.",'$'
reset_msg	db	CR,LF,"Can't reset the interface",'$'
interr_msg	db	CR,LF,"IRQ# parameter wrong.",'$'

	public	driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class	db	1		;from the packet spec
driver_type	db	100		;--mz?
driver_name	db	'nti',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	4		;number of receive modes in our table.
		dw	0,0,0,rcv_mode_3


	;begin importing data
	public	UNITID, sdesc_cnt, rdesc_cnt, actsdesc, actrdesc
UNITID	db	6 dup (0)		;current ether address of the interface
sdesc_cnt	dw	2		;
rdesc_cnt	dw	8
actsdesc	dw	0
actrdesc	dw	0



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; send_pkt:
;
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	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:
	assume	ds:nothing
	push	es
	call	set_dp

	push	ds
	call	set_ds			;set out ds-->cs

	mov	dx,cx			;a copy of length

	cmp	dx,GIANT		; Is this packet too large?
	ja	send_pkt_toobig

	cmp	dx,RUNT			; minimum length for Ether
	jnb	oklen
	mov	dx,RUNT			; make sure size at least RUNT
oklen:
	mov	bx,[actsdesc]		;get pointer to active snd desc
	mov	cx,0			;set up count down parameters
td10:
	test	es:td_stat[bx],t_own	;have empty buffer?
	jz	dox0			;yes, then send message
	loop	td10			;otherwise, wait for it
	mov	dx,offset nosdesc_msg
	ccall	_dispMSG,dx
	mov	dh,CANT_SEND
	stc				;error ret
	pop	ds
	pop	es
	ret

dox0:
	pop	ds
	mov	cx,dx			;get back the real length
	call	fill			;ds:si - source, es:bx - dest, cx:length
	;ax has the return code, either 0 or 0ffh

	;is chip functioning?
	cmp	ax,0ffh			;fatal error happened last time?
	je	td15			;error!
	clc				;good ret
	pop es
	ret
td15:
	mov	dh,CANT_SEND
	stc
	pop	es
	ret

send_pkt_toobig:
	mov	dh,NO_SPACE
	stc
	pop	ds
	pop	es
	ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; fill - proc the xerror  & copy message to xmit buffer
;
; entry - es:bx points to free xmit descriptor (dest)
;	  ds:si --> source buf pointer
;  	  cx:length of data
;
; exit  - xmit buffer (bx) filled
;	  ax = 0: OK; 0ffh: fatal error happened last send
;	  bx changed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	public	fill
fill:
	assume	ds:nothing
	push	ds				;save theirs

	call	set_ds				;set ours

	call	xmt_errs			;process previous errors
	cmp	ax,0
	je	success
	pop	ds
	ret					;ax == ffh

success:	
	;ds:si - source, es:bx - dest, cx - length
	;simply send whatever given by the application, assuming the
	;destination address and everything has been taken care of

	pop	ds
	push	cx			;save it
	mov	di,es:td_addr[bx]	;get dest buf pointer 
	call	movemem			;ds:si --> es:di
	pop	cx
	
	push	ds
	call	set_ds
	;get the sdesc ready and pump the data out
	neg	cx			;two's compliment
	or	cx,td_bmask		;set these bits
	mov	es:td_bcnt[bx],cx	;set in length to descriptor
	mov	ax,0			;set descriptor status for lance
	or	ax,t_own		;he now owns it
	or	ax,t_stp		;start of packet
	or	ax,t_enp		;end of packet
	mov	es:td_stat[bx],ax	;give it away		
	mov	ax,l_tdnd+l_inea	;tell lance we have data
	call	w_csr	    		;send it

	;all done, update the actsdesc
	add	bx,tdesclen		;point at next descriptor
	dec	word ptr[sdesc_cnt]		;dec counter
	jnz	tfl				;used all?
	mov	word ptr[sdesc_cnt],NUMTDESC	;yes start at begining	
	mov	bx,XAREA
tfl:
	mov	[actsdesc],bx		;set pointer

	mov	ax,0			
	pop	ds
	ret				;good ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; xmt_errs:
;	Check at if the previous send has any errors or not.
; 	entry - es:bx sdesc
;	exit  - ax:0 - ok; ffh:fatal error
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	xmt_errs
xmt_errs:
	mov	ax,es:td_tdr[bx]	;get rest of status
	test	ax,t_more		;more than one retry needed
	jz	xisr2
	call	count_out_err
	jmp	xisr3
xisr2:
	test	ax,t_one		;one retry?
	jz	xisr3			;no
	call	count_out_err
xisr3:
	test	ax,t_lcol		;late collision
	jz	xisr4			;no
	call	count_out_err
xisr4:
	test	ax,t_def		;deferred xmit?
	jz	xisr5
	call	count_out_err
xisr5:
	test	ax,t_lcar		;loss of carrier
	jz	xisr6
	call	count_out_err
xisr6:
	test	ax,t_uflo		;silo underflow?
	jz	xisr7	
	jmp	fatal_err
xisr7:	
	test	ax,t_buff		;buffer error no end
	jz	all_rite		;last sent all right
fatal_err:
	call	count_out_err
	mov	ax,0ffh			;fatal error
	ret				;

all_rite:
	mov	ax,0
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;get_address:
;	We get the interface address from our internal version UNITID. 
;	set_address() could change the value of UNITID.
;
;enter with es:di -> place to put the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	get_address
get_address:
	assume	ds:code
	cmp	cx,EADDR_LEN		;make sure that we have enough room.
	jb	get_address_2
	mov	cx,EADDR_LEN
	lea	si,UNITID
get_address_1:
	call	movemem
	mov	cx,EADDR_LEN
	clc
	ret
get_address_2:
	stc
	ret
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set_address:
;	set current ethernet address in UNITID, also change the init block
;   	
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	set_address
set_address:
	assume	ds:nothing
	push 	ax
	push	di
	push	es
	mov	ax,cs
	mov	es,ax
	
	cmp	cx,EADDR_LEN
	jne	set_address2

	push	si				;save it for later use
	push	cx

	mov	di,offset UNITID
	call	movemem

	;should also change the init_block
	call	set_dp
	mov	di,offset i_padr			
	pop	cx
	pop	si				;get back the old pointer
	call	movemem

	pop	es
	pop	di
	pop	ax
	clc
	ret

set_address2:
	mov	dh,BAD_ADDRESS
	stc
	pop	es
	pop	di
	pop	ax
	ret



rcv_mode_3:
;receive mode 3 is the only one we support, so we don't have to do anything.
	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.
	mov	dh,NO_MULTICAST
	stc
	ret


	public	terminate
terminate:
	ret

	public	reset_interface
reset_interface:
;reset the interface.
	assume	ds:code
	call	hardware		;reset the UNITID
	cmp	al,0
	jne	port_err

	cli

	call	lance_init		;init_blk, xmt, rcv
	cmp	ax,0			;init ok?
	jne	lance_err
	sti
	clc
	ret

lance_err:
	mov	dx,offset initerr_msg
	ccall	_dispMSG,dx
	jmp	error

port_err:	
	mov	dx,offset reset_msg
	ccall	_dispMSG,dx
error:
	mov	dh,CANT_RESET
	stc
	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

;called from the net_isr isr.  All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; risr 
; receive interrupt service routine 
; exit: es,bx not changed
; registers: si,ax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	risr
risr	proc	near
	assume	ds:code
	save	<es,bx>
	call	set_dp			;set es to dual port
begin:
	mov	si,[actrdesc]		;active receive descriptor
	mov	ax,es:rd_stat[si]	;get descriptor status
	test	ax,r_own		;do we own it?
	jnz	risr_done		;this one is not filled

	call	dp_rcv			;lance chip has rev'd a new packet
					;reserve si 
	;One rint might indicate multiple recv's, check at the next one
	add	si,SIZE rec_desc_ring		;point at next descriptor
	cmp	si,OUTOF_BOUND			;RAREA+(numrxbuf-1)*(SIZE rec_desc_ring) = XAREA
	jl	within
	mov	si,RAREA
within:
	mov	[actrdesc],si			;set active pointer
	jmp	begin
risr_done:
	restore <bx,es>
	ret
risr	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  dp_rcv:
;	lance chip has one buffer filled, process it.
;	enter: es:si = actrdesc
;	exit:  actrdesc updated to next desc, si unchanged
;	registers: di,ax,bx
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	dp_rcv
dp_rcv 	proc 	near
	push	si    			;save the old actdesc
	push	es			;gonna be changed in recv_find()

	mov	ax,es:rd_stat[si]	;is it errored packet?
	test	ax,r_err		;
	jz	noerr	     		;no err
	call 	rcverror		;handle the err 
	jmp	clrup

noerr:
	mov 	di,es:rd_addr[si]	;received packet pointer es:di
	add	di,EADDR_LEN + EADDR_LEN;stript off the two ether addresses
					; & get to the packet type field
	mov	cx,es:rd_mcnt[si]	;everything (icl'g addresses)
	and	cx,mcnt_mask		;mask out the reserved bits

	push	ds			;entry value saved

	push	es			;es:di --> rcv'd data (icl'ing type)
	push	di

	call	recv_find		;ask for buffer from application es:di
	mov	ax,es			;is this pointer null?
	or	ax,di
	jz	too_bad			;yes - just free the frame.
	pop	si			;put rcv'd data in ds:si, di->si
	sub	si,EADDR_LEN + EADDR_LEN;we hand everything to the client
	pop	ds			;es->ds

	push	cx
	push	es			;for recv_copy(), es:di is user buf
	push	di			

	call	movemem			;do the copy (including ether header)

	pop	si			;di->si, es->ds
	pop	ds			;ds:si --> user buffer now
	pop	cx			;get back the length
	call	recv_copy

	pop	ds			;original ds restored
	jmp	clrup

too_bad:
	pop	di
	pop	es
	pop	ds
clrup:
	;either a bad or a good packet, we're done with it now
	pop	es			;good old dp seg
	pop	si
	mov	es:rd_stat[si],r_own	;desc reusable now
	ret
dp_rcv	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; eisr
; for lance error service routine
;
; entry - bx has status
; exit  - bx unchanged, ax,cx changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	eisr
eisr	proc	near
	test	bx,l_babl		;transmission timeout?
	jz	eisr1			;no
	call	count_out_err
eisr1:
	test	bx,l_cerr    
	jz	eisr2			;no
	call	count_out_err
eisr2:
	test	bx,l_miss		;missed packet?
	jz	eisr3
	call	count_out_err
eisr3:
	test	bx,l_merr		;bus timeout?
	jz	eisr4			;no
	call	count_out_err		;this is a fatal error
eisr4:
	ret
eisr	endp

	include	movemem.asm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; rcverror:
;	entry	ax has rd_stat
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	rcverror
rcverror	proc	near

	test	ax,r_fram		;framing error?
	jz	rerr0
	call 	count_in_err
rerr0:
	test	ax,r_crc		;crc error?
	jz	rerr1
	call 	count_in_err
rerr1:
	test	ax,r_oflo	  	;silo overflow?
	jz	rerr2
	call 	count_in_err
rerr2:
	test	ax,r_buff		;buffer error?
	jz	rerr3
	call 	count_in_err
rerr3:
	ret
rcverror	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init_csr:
;
; initialize lance registers csr1, csr2, csr3
;  entry - csr0 stop bit must have been set
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	init_csr
init_csr	proc	near
	mov	al,csr1			;set rap to csr1
	call	set_rap
	mov	ax,i_mode		;init block starts at 0
	call	w_csr

	mov	al,csr2			;set rap to csr2
	call	set_rap
	mov	ax,0			;init block upper 8 bits are 0
	call	w_csr

	mov	al,csr3			;set rap for csr3
	call	set_rap
	mov	ax,bus_master		;bswp,acon,bcon
	call	w_csr

	mov	al,csr0			;leave rap at csr0
	call	set_rap
	ret
init_csr	endp	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; r_csr:
;
; read lance csr already selected into ax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	r_csr
r_csr	proc	near
	push	dx
	mov	dx,io_addr		;now data port
	add	dx,pt_ldata
	in	ax,dx
	pop	dx
	ret
r_csr	endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; r_csr0
;
; read lance csr0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	r_csr0
r_csr0	proc	near
	push	dx
	mov	al,csr0			;set rap to csr1
	call	set_rap
	mov	dx,io_addr		;now data port
	add	dx,pt_ldata
	in	ax,dx
	pop	dx
	ret
r_csr0	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set_initblk:  
;
; set up lance initialization block in the dual port  
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;				       ;

	public	set_initblk,si11
set_initblk  proc	near
	push	es
	call	set_dp			;get lance data seg

	mov	ax,run_mode		;mode
	mov	es:[i_mode],ax		;(es = dpseg);1st word in the dp
	lea	si,UNITID		;set in physical address
	mov	di,i_padr		; from the board
si11:
	mov	cx,6
	rep	movsb
;
;forget about the logical address filter for now --mz??
;
	mov	ax,RAREA		;set in pointer to 1ST receive desc.
	mov	es:[i_rdra],ax		;set lo addr (0-15)
	mov	ah,rlen			;set in rlen parameter & hi addr (00s)
	mov	al,0
	mov	es:[i_rlen],ax		;4 rcv descriptors
	mov	ax,XAREA		;pointer to xmit descriptors
	mov	es:[i_tdra],ax
	mov	ah,tlen			;set in tlen parameter 1 = 2
	mov	al,0
	mov 	es:[i_tlen],ax
	pop	es
	ret
set_initblk	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set_dp
;	es<-- cs:base_address
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	set_dp
set_dp:
	assume	cs:code
	push	ax
	mov	ax,cs:[base_addr]
	mov	es,ax
	pop	ax
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set_ds:
; 	ds<--cs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
set_ds:
	push	ax
	mov	ax,cs
	mov	ds,ax
	pop	ax
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set up transmit message descriptors
;
; entry - cx has number of descriptors and buffers to set up
;         bx has pointer of start of descriptors
;         di has pointer to start of buffer area
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	su_tmd
su_tmd	proc	near
	push	es
	call	set_dp			;get lance data seg

	;first set the relative parameters
	mov	[sdesc_cnt],cx		;set in count
	mov	[actsdesc],bx

su_t0:
	mov	es:td_addr[bx],di	;set in pointer
	mov	ax,BUFSIZE		;total size
	neg	ax			;two's compliment
	or	ax,td_bmask		;set these bits
	mov	es:td_bcnt[bx],ax	;set in length to descriptor
	mov	ax,0			;set descriptor status for lance
	or	ax,t_stp		;start of packet
	or	ax,t_enp		;end of packet
	mov	es:td_stat[bx],ax	;give it away		
	mov	es:td_tdr[bx],0
	add	bx,tdesclen		;point at next descriptor
	add	di,BUFSIZE		;and next buffer
	loop	su_t0			;do all
	pop	es
	ret
su_tmd	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set up receive message descriptors
;
; entry - cx has number of descriptors and buffers to set up
;         bx has pointer of start of descriptors
;         di has pointer to start of buffer area
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	su_rmd
su_rmd	proc	near
	push	es
	call	set_dp	;get lance data seg

	mov	[actrdesc],bx  		;pointer to active descriptor
	mov	[rdesc_cnt],cx		;descriptor count
su_r0:
	mov	es:rd_addr[bx],di   	;set in pointer to pointer
	mov	ax,r_own		;set up descriptor status 
	mov	es:rd_stat[bx],ax
	xor	ax,ax			;zero out count
	mov	es:rd_mcnt[bx],ax
	mov	ax,BUFSIZE		;set in length of buffer
	neg	ax			;must be two's compliment
	or	ax,rd_mask		;need these bits set
	mov	es:rd_bcnt[bx],ax
	add	bx,rdesclen		;point at next descriptor
	add	di,BUFSIZE		;and next buffer
	loop	su_r0			;do all
	
	pop	es
	ret
su_rmd	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; lance_reset:
;
; 	reset lance chip; select csr0 and set the stop bit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;		

	public	lance_reset
lance_reset	proc	near
	mov	dx,io_addr		;pop the reset line
	add	dx,pt_resetl	
	out	dx,al
	mov	al,csr0			;set lance address port to csr0
	call	set_rap
	mov	ax,l_stop 		;and set stop bit
	call	w_csr
	ret
lance_reset	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; w_csr:
;
; output ax to lance csr already selected
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	w_csr
w_csr	proc	near
	push	dx
	mov	dx,io_addr		;now data port
	add	dx,pt_ldata
	out	dx,ax
	pop	dx
	ret	
w_csr	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; set_rap:
;
; set lance address port to register in al
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	set_rap
set_rap	proc	near
	push	dx
	mov	dx,io_addr		;get base address
	add	dx,pt_laddr		        ;point at lance address port
	xor	ah,ah			;point at csr
	out	dx,ax
	pop	dx
	ret
set_rap		endp

; hardwre() and lance_init() are TSR just for the 
; support of reset_interface();

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; hardware: 
;	verify the port #;
;	set ethernet addr in _UNITID
;
; exit:
;	[_UNITID] = board ethernet address
;       al = 0 (ok)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	hardware
hardware	proc	near
	;verify the port #
	mov	dx,io_addr
	call	chkaddr
	cmp	al,0			;ok?
	jz	hw1			;yes, use #1
	mov	ax,offset porterr_msg
	ccall	_dispMSG,ax
	jmp	hw_error

hw1:
	;ok, now zero the ram out so that we can use it
	call	set_dp
	call 	zeroram

	;get ether address
	mov	cx,6			;get the ethernet address
	add	dx,pt_etaddr
	mov	bx,offset UNITID	;to here
hw3:
	in	al,dx
	mov	byte ptr[bx],al
	inc	bx
	loop	hw3

	;validate int_no (only support 10,11,12,15)
	
	mov	bl,IRQ10		;assume it's irq10
	mov	dx,io_addr		;port base
	add 	dx,pt_status		;status port
	in	al,dx			;get status
	and	al,st_mask		;get the 2 bits
	cmp	al,irqn_10		;(IS0 IS1)=(0 0) selects irq10
	je	alset
	inc	bl			;try irq11
	cmp	al,irqn_11
	je	alset
	inc	bl			;try irq12
	cmp	al,irqn_12
	je	alset
	mov	bl,15			;try irq15
	cmp	al,irqn_15
	jne	hw_error

alset:
	;did we get the right int_no in bl?
	cmp	bl,int_no
        jmp     ok                      ; #### temp patch, BKC
;	je	ok
	;otherwise, error
	mov	ax,offset interr_msg
	ccall	_dispMSG,ax
hw_error:
	mov	al,0ffh
	ret
ok:
	mov	al,0			;good return code
	ret
hardware	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; chkaddr: check if we are using the right i/o port
;          this is done by reading the port status and comparing
;	   with cs - 800h
;
; entry: 	io_addr == i/o port #
; exit: 	ah -- dual port segment
;		al -- 00h (succ) or ffh (error)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	chkaddr
chkaddr	proc	near
	push	dx

	mov	dx,io_addr
	in	al,dx			;read in status byte
	and	al,addr			;get dp seg, addr = 0f0h
	mov	ah,al			;save

	mov	dx,base_addr
	and	dh,addr
	cmp	al,dh
	je	chk2
	mov	al,0ffh			;error
	pop	dx
	ret
chk2:
	mov	al,0			;ok
	pop	dx
	ret
chkaddr	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; zeroram - zero dual port ram
;    seg in [dpseg]
;    registers: di,cx,al
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	zeroram
zeroram	proc	near
	cld				;auto increment
zram1:	
	mov	di,0			;start at 0;dpseg:di
	mov	cx,dplen		;dual port length
	mov	al,0			;data to go
	rep	stosb			;zero em all
	ret
zeroram	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; lance_init:
;
; init lance chip; first setup init_blk, r & s descriptors in dp
;		   then set the chip to go.
;	exit: ax = 1: error; 0 OK. 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	lance_init, il0, il1
lance_init	proc	near
	call	set_initblk		;set up lance initialization block

	;set up transmit descriptors & buffers
	mov	cx,NUMTDESC		;get no. of transmit blocks to build
	mov	bx,XAREA		;point at descriptor memory pool
	mov	di,TBAREA		;and buffer pool
	call	su_tmd			;set up transmit descriptors

	;set up receive descriptors & buffers
	mov	cx,NUMRDESC		;set up receive descriptors
	mov	bx,RAREA		;descriptor area
	mov	di,RBAREA		;buffer area
	call	su_rmd			;set up receive descriptors

	call	lance_reset		;ensure reset
	call	init_csr		;initialize lance registers
					;also set rap to csr0 with stop set
	;now start the lance initialization action
	CLI
	mov	ax,l_init+l_strt	;write init & start to csr0
	call	w_csr

	;rap = csr0 now, let's check at csr0
   	mov	cx,0
	dec	cx
il0:
	call	r_csr			;get lance status register
	test	ax,l_idon		;init done set?
	jnz	il1
	loop	il0
	;sth wrong with the chip, can't init
	mov	ax,offset chperr_msg
	ccall	_dispMSG,ax
	mov	ax,1			;error return
	ret
il1:
	mov	ax,l_idon+l_inea	;this drives /intr pin to low
	call	w_csr			;enable network ints
	STI
	mov	ax,0			;good return
	ret
lance_init	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  tickscreen
;
;  For debug this routine can be called to tick over the screen at the 
;  specified location.
;
;	c callable:	tickscreen(loc);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	_tickscreen
_tickscreen	proc near
	push	bp
	mov	bp,sp
	save	<ax,bx,ds>
	mov	bx,04[bp]		;get screen position
	add	bx,bx			;*2
IFDEF COLOR
	mov	ax,0b800h
ELSE
	mov	ax,0b000h
ENDIF
	mov	ds,ax
	inc	byte ptr [bx]			;tick it
	restore	<ds,bx,ax>
	pop	bp
	ret
_tickscreen	endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; _dispMSG:
;	c call: dispMSG(&msg);
;	put the '$' terminated message to screen
;	entry: dx - point to the message
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	_dispMSG
_dispMSG proc near
	push	bp
	mov	bp,sp
	push	dx
	mov	dx,4[bp]

	push	ax
	mov	ah,9
	int	21h
	pop	ax

	pop	dx
	pop	bp
	ret
_dispMSG endp


	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

recv_0:
	mov	dx,io_addr		;get the iobase
	add	dx,pt_status		;the read status port
	in	al,dx			;get board status

	test	al,clk_int		;look for clock interrupt
	jz	ni10			;no clock int
	mov	dx,base_addr
	add	dx,pt_clrclk		;reset the ckock
	out 	dx,al
ni10:
	test	al,net_int		;network int bit cleared?
	jnz	nisr5			;look for 0 here, set means none

	call	r_csr			;get lance status register -- in ax
	mov	bx,ax
	and	ax,l_mask	 	;clear out ints and mask any more
	call	w_csr

	test	bx,l_err		;check for errors first
	jz	nisr2			;no error
	call	eisr
nisr2:
	test	bx,l_rint		;test for receive active
	jz	nisr6			;no r_int
	call	risr
nisr6:
	mov 	ax,l_inea		;re-enable the int
	call	w_csr
	jmp	recv_0			;check again for ints
nisr5:
	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


;any code after this will not be kept after initialization.
end_resident	label	byte


	public	usage_msg
usage_msg	db	"usage: nti16 [-n] [-d] [-w] <packet_int_no> <irq_no> <port_no> <base_addr>",CR,LF,'$'

	public	copyright_msg
copyright_msg	db	"Packet driver for nti network device, version ",'0'+version,CR,LF,'$'
		db	"Copyright 1990, Michael Zheng",CR,LF,'$'


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

	public	parse_args
parse_args:
	mov	di,offset int_no
	mov	bx,offset int_no_name
	call	get_number
	mov	di,offset io_addr
	mov	bx,offset io_addr_name
	call	get_number
	mov	di,offset base_addr
	mov	bx,offset base_addr_name
	call	get_number
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; etopen:
;	initialize the interface in order to function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	public	etopen
etopen:


	public	beginbios
beginbios:

	call 	hardware		;decide port #; _UNITID; zeroram
					;and 16-bit board specific:
					;decide the int_no validity --mz!!
	cmp	al,0
	jz	beg0			;ok
	mov	ax,offset hwerr_msg	;error return
	ccall	_dispMSG,ax
	mov	ax, 4c00H
	int	21h			;terminate it
beg0:

	mov	al,int_no
	call	maskint
	call	lance_init		;init the lance chip
	cmp	ax,1			;init error?
	jne	good			;ok

	mov	ax,offset initerr_msg	;can't init message
	ccall	_dispMSG,ax
	stc	
	ret

good:
	call	set_recv_isr

	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	ax,offset good_msg
	ccall	_dispMSG,ax

	mov	dx,offset end_resident	;in paragraphs
	clc
	ret

	public	print_parameters
print_parameters:
;echo our command-line parameters
	mov	di,offset int_no
	mov	bx,offset int_no_name
	call	get_number
	mov	di,offset io_addr
	mov	bx,offset io_addr_name
	call	get_number
	mov	di,offset base_addr
	mov	bx,offset base_addr_name
	call	get_number
	ret

code	ends

	end
