	.title	TCP/UDP Ethernet Driver

	;	  This driver may use the EQ/EU device driver
	;	which supports internal frame queueing.
	;
	;	  This I/O driver supports the TCP/UDP
	;	task.  This driver uses three EN units:
	;
	;	0 -	recv protocol = EIP
	;	1 -	recv protocol = EARP
	;	2 -
	;	3 -	xmit (protocol not used when xmitting)

	;	DECUS C Calling Format
	;
	;	jsr	r5,csv$		;save r2,r3, and r4
	;				;r5 is parameter base
	;				;c$pmtr(r5) is first argument
	;				;c$pmtr+2(r5) is second argument
	;				;...
	;				;return args in r0
	;	...
	;	user code
	;	...
	;
	;	jmp	cret$		;restore r2-r5 and return
	;	rts	pc		;does the same (cret$ follows csv$)
	;	

	.include	"os.mac"

	.mcall	.lookup	.close	.spfun	.abtio
	.mcall	.exit	.print	.cstat

	MINPKT	=	 32.		;minimum output packet size
	MAXPKT	=	285.		;maximum output packet size
	TCPPKT	=	285.		;buffer length required for a
					;512 byte CREDIT TCP packet
	ARPPKT	=	290.		;buffer length required
					;for an arp packet

	ERRBYT	=	52		;IO error byte

	EARP	=	003010		;0x0608		;protocols
	EIP	=	000010		;0x0008

	SEARP	=	004006		;0x0806		;swapped protocols
	SEIP	=	004000		;0x0800

	enchan	=	0		;offsets
	endev	=	2
	enprot	=	4
	enpkts	=	6
	enbufr	=	10
	enflgs	=	12
		en.alc	=	000001
		en.prt	=	000002
		en.rcv	=	000004
		en.que	=	000010

	ENTLEN	=	14		;table length


	.page
	.sbttl	Configuration Data

	.psect	c$data

en0:	.rad50	/EN0EN0EN0EN0/		;filespecs
en1:	.rad50	/EN1EN1EN1EN1/

en3:	.rad50	/EN3EN3EN3EN3/

.if ne sp$207				;.spfun 207 required
tmpenu =:	en0			;temporary unit
.iff
en2:	.rad50	/EN2EN2EN2EN2/		;temporary
tmpenu	=:	en2			;temporary unit
.endc

tmpchn	=:	12			;temporary channel

setup:	.word	10,	en0,	EIP,	TCPPKT,	buff1,	en.alc!en.prt!en.rcv
	.word	11,	en1,	EARP,	ARPPKT,	buff2,	en.alc!en.prt!en.rcv

setupx:	.word	13,	en3,	0,	0,	0,	en.alc!en.que
	.word	0

ethsts:	.word	0,0			;protocol initialization
ethadd:	.word	0,0,0			;ethernet address

argmnt:	.blkw	6			;argument block
chstat:	.blkw	6			;channel status

pktlst:	.blkw	4.			;packet list
	chnmsk	=	^C1
	pktmsk	=	^C7

pkiptr:	.word	0			;received packet pointer
pkrptr:	.word	0			;retrieved packet pointer

bufupd:	.word	0			;update packet

buff1:	.blkw	TCPPKT			;buffer 1 for IP's
buff2:	.blkw	ARPPKT			;buffer 2 for ARP's

	.psect	c$code


	.page
	.sbttl	Get Ethernet Address

	;
	;	engetaddr(s);	char *s
	;

engetaddr::
	jsr	r5,csv$
	mov	#ethadd,r0		;check for the ethernet address
	mov	(r0)+,r1
	bis	(r0)+,r1
	bis	(r0),r1
	bne	1$			;have one !

	; Lookup the device and assign a channel

;	.lookup	#lkpdev,#tmpchn,#tmpenu
	mov	#lkpdev,r0
	emt	375

.if ne sp$207				;.spfun 207 required
	; Get Physical Address

;	.spfun	#2$,#tmpchn,#207,#ethadd-2,#0,#0
	mov	#2$,r0
	emt	375

.iff					;no .spfun 207
	; Allocate the device

;	.spfun	#2$,#tmpchn,#200,#ethadd-2,#0,#1
	mov	#2$,r0
	mov	#1,3$
	emt	375

	; Deallocate the device

;	.spfun	#2$,#tmpchn,#200,#ethadd-2,#0,#0
	mov	#2$,r0
	clr	3$
	emt	375
.endc

	; Close the channel

	.close	#tmpchn

1$:	mov	#ethadd,r0		;return the ethernet address
	mov	c$pmtr(r5),r1
	mov	(r0)+,(r1)+
	mov	(r0)+,(r1)+
	mov	(r0),(r1)
	rts	pc

.if ne sp$207				;.spfun 207 required
;	.spfun	#2$,#tmpchn,#207,#ethadd-2,#0,#0
2$:	.byte	tmpchn,32
	.word	0		;blk
	.word	ethadd-2	;buf
	.word	0		;wcnt
	.byte	377,207
	.word	0
.iff 					;no .spfun 207
;	.spfun	#2$,#tmpchn,#200,#ethadd-2,#0,(#0 or #1)
2$:	.byte	tmpchn,32
3$:	.word	0		;blk
	.word	ethadd-2	;buf
	.word	0		;wcnt
	.byte	377,200
	.word	0
.endc

;	.lookup	#lkpdev,#tmpchn,#tmpenu
lkpdev:	.byte	tmpchn,1
	.word	tmpenu
	.word	0

	.page
	.sbttl	Open all EN channels

	;
	;	enopen();
	;

enopen::
	jsr	r5,csv$
	clr	-(sp)			;error count
	mov	#setup,r2		;set up table

	; Lookup the device and assign a channel

;	.lookup	#7$,enchan(r2),endev(r2)
1$:	mov	#7$,r0
	movb	enchan(r2),(r0)
	mov	endev(r2),2(r0)
	emt	375
	bcc	2$
	inc	(sp)

	; Allocate the device

2$:	bit	#en.alc,enflgs(2)
	beq	3$
;	.spfun	#8$,enchan(r2),#200,#ethadd-2,#0,#1
	mov	#8$,r0
	movb	enchan(r2),(r0)
	emt	375
	bcc	3$
	inc	(sp)

	; Set up the receiver protocols

3$:	bit	#en.prt,enflgs(r2)
	beq	4$
	clr	ethsts
	mov	enprot(r2),ethsts+2	;load protocol
;	.spfun	#9$,enchan(r2),#202,#ethsts,#0,#1
	mov	#9$,r0
	movb	enchan(r2),(r0)
	emt	375
	bcc	4$
	inc	(sp)

	; Start up the designated receivers

4$:	bit	#en.rcv,enflgs(r2)
	beq	5$
;	.spfun	#10$,enchan(r2),#205,enbufr(r2),enpkts(r2),#0,#cmpltn
	mov	#10$,r0
	movb	enchan(r2),(r0)
	mov	enbufr(r2),4(r0)
	mov	enpkts(r2),6(r0)
	emt	375
	bcc	5$
	inc	(sp)

	; Enable Frame queueing

5$:
.if ne sp$206				;.spfun 206 required
	bit	#en.que,enflgs(r2)
	beq	6$
;	.spfun	#11$,enchan(r2),#206,#ethsts,#0,#1
	mov	#11$,r0
	movb	enchan(r2),(r0)
	emt	375
	bcc	6$
	inc	(sp)
.endc

6$:	add	#ENTLEN,r2
	tst	(r2)
	bne	1$

	mov	(sp)+,r0	;exit status
	rts	pc

;	.lookup	#7$,enchan(r2),endev(r2)
7$:	.byte	0,1
	.word	0
	.word	0

;	.spfun	#8$,enchan(r2),#200,#ethadd-2,#0,#1
8$:	.byte	0,32
	.word	1		;blk
	.word	ethadd-2	;buf
	.word	0		;wcnt
	.byte	377,200
	.word	0

;	.spfun	#9$,enchan(r2),#202,#ethsts,#0,#1
9$:	.byte	0,32
	.word	1		;blk
	.word	ethsts		;buf
	.word	0		;wcnt
	.byte	377,202
	.word	0

;	.spfun	#10$,enchan(r2),#205,enbufr(r2),enpkts(r2),#0,#cmpltn
10$:	.byte	0,32
	.word	0		;blk
	.word	0		;buf
	.word	0		;wcnt
	.byte	377,205
	.word	cmpltn

.if ne sp$206			;.spfun 206 required
;	.spfun	#11$,enchan(r2),#206,#ethsts,#0,#1
11$:	.byte	0,32
	.word	1		;blk
	.word	ethsts		;buf
	.word	0		;wcnt
	.byte	377,206
	.word	0
.endc

	.page
	.sbttl	Close all EN channels

	;
	;	enclose();
	;

enclose::
	jsr	r5,csv$

.if ne sp$211				;.spfun 211 required
;	.spfun	#2$,#13,#211,#ethsts,#0,#0
	mov	#2$,r0			;abort job i/o
	emt	375			;SJ - Monitors
.endc

	mov	#setup,r2		;set up table

	; Abort all pending i/o

1$:	.abtio	enchan(r2)

	; Close the channel

	.close	enchan(r2)

	add	#ENTLEN,r2
	tst	(r2)
	bne	1$

	rts	pc

.if ne sp$211			;.spfun 211 required
;	.spfun	#2$,enchan(r2),#206,#ethsts,#0,#1
2$:	.byte	13,32		;use xmit channel
	.word	0		;blk
	.word	ethsts		;buf
	.word	0		;wcnt
	.byte	377,211
	.word	0
.endc

	.page
	.sbttl	Receive Ethernet Packets

	;
	;	packet_buffer = enrecv();
	;

enrecv::
	jsr	r5,csv$
	cmp	pkrptr,pkiptr		; any packets ?
	bne	1$
	clr	bufupd			; no packets
	clr	r0
	rts	pc

1$:	mov	pkrptr,r2
	mov	pktlst(r2),r1		; extract packet pointer
	add	#2,r2
	bic	#pktmsk,r2
	mov	r2,pkrptr	

	mov	r1,bufupd		; save for enupdate
	mov	enbufr(r1),r0
	rts	pc


	.page
	.sbttl	Transmit Ethernet Packets

	;
	;	int enxmit((char *)ptr, size)
	;
	;
	;	The packet presented to enxmit() is
	;	expected to have 2 words prefixed to
	;	the actual data packet.
	;
	;	DLAYER contains the 2 word prefix.
	;

enxmit::
	jsr	r5,csv$
	mov	c$pmtr(r5),r3		;packet buffer address
	mov	#-1,(r3)		;preset status flag to error
	mov	#setupx,r2		;unit select
	mov	r3,enbufr(r2)		;save for error reports
	mov	c$pmtr+2(r5),r1		;byte count
	inc	r1			;round bytes to words
	asr	r1
	cmp	#MINPKT,r1		;bound the packet
	blos	1$			;from MINPKT to MAXPKT
	mov	#MINPKT,r1		;words
	br	2$
1$:	cmp	#MAXPKT,r1
	blo	3$			;packet length error
2$:	mov	r1,2(r3)		;set packet length
;	.spfun	#4$,enchan(r2),#204,r3,r1,#0
	mov	#4$,r0
	movb	enchan(r2),(r0)
	mov	r3,4(r0)
	mov	r1,6(r0)
	emt	375
3$:	mov	(r3),r0			;return i/o status
	rts	pc

;	.spfun	#4$,enchan(r2),#204,r3,r1,#0
4$:	.byte	0,32
	.word	0		;blk
	.word	0		;buf
	.word	0		;wcnt
	.byte	377,204
	.word	0


	.page
	.sbttl	Update Buffer Usage

	;
	;	enupdate()
	;

enupdate::
	jsr	r5,csv$
	mov	bufupd,r2		;a buffer used ?
	beq	1$			;no - skip
	clr	bufupd			;reclaim buffer
;	.spfun	#2$,enchan(r2),#205,enbufr(r2),enpkts(r2),#0,#cmpltn
	mov	#2$,r0
	movb	enchan(r2),(r0)
	mov	enbufr(r2),4(r0)
	mov	enpkts(r2),6(r0)
	emt	375
1$:	rts	pc

;	.spfun	#2$,enchan(r2),#205,enbufr(r2),enpkts(r2),#0,#cmpltn
2$:	.byte	0,32
	.word	0		;blk
	.word	0		;buf
	.word	0		;wcnt
	.byte	377,205
	.word	cmpltn


	.page
	.sbttl	Receive Completion Routine

cmpltn:	bic	#chnmsk,r1		; compute packet pointer
	beq	1$			; channel 10
	mov	#ENTLEN,r1		; channel 11
1$:	add	#setup,r1
	mov	pkiptr,r0
	mov	r1,pktlst(r0)		; put entry into packet list
	add	#2,r0
	bic	#pktmsk,r0
	mov	r0,pkiptr	
	jsr	pc,resume		;resume any suspension
	rts	pc


	.end
