; ODIPKT.ASM - Adapter provides Packet Driver interface over ODI
;
; (c) Copyright Daniel D. Lanciani 1991.  All rights reserved.
;
; This unmodified source file and its executable form may be used and
; redistributed freely.  The source may be modified, and the source or
; executable versions built from the modified source may be used and
; redistributed, provided that this notice and the copyright displayed by
; the exectuable remain intact, and provided that the executable displays
; an additional message indicating that it has been modified, and by whom.
;
; Daniel D. Lanciani releases this software "as is", with no express or
; implied warranty, including, but not limited to, the implied warranties
; of merchantability and fitness for a particular purpose.
;
; Please send bug reports to ddl@harvard.harvard.edu.

version	equ	2	; for driver_info
iftype	equ	71	; for driver_info/access_type
nhand	equ	8	; max active handles
mmatch	equ	8	; max length of header match
mmulti	equ	8	; max multicast addresses
pkvec	equ	69h	; default control vector
xbsize	equ	1514	; max receive frame size
alen	equ	6	; address length
stksw	equ	1	; switch stacks in upcall
nopid	equ	1	; use prescan/default instead on pid
defstk	equ	1	; use default instead of prescan

hinfo	struc			; per-handle data
nmatch	dw	-1		; header match length
match	db	mmatch dup (?)	; header match bytes
recvo	dw	?		; receiver offset
recvs	dw	?		; receiver segment
hinfo	ends

CODE	segment word public 'CODE'
	assume cs:CODE, ds:CODE, es:nothing, ss:CODE

	org	100h
stack	label	byte
at100h:	jmp	start

copyright db	'ODIPKT 1.0 beta', 13, 10
	db	'(c) Copyright Daniel Lanciani 1991.  All rights reserved.'
	db	13, 10, 'This software is provided with NO WARRANTY.', 13, 10
	db	'$'
myname	db	'ODIPKT', 0	; for driver_info
class	db	1		; for driver_info
xbusy	db	0		; receive buffer busy
ifdef	stksw
inhere	db	0		; on switched stack
endif
	align	2
savpko	dw	0		; saved vector offset
savpks	dw	0		; saved vector segment
psup	dd	0		; LSL protocol support entry
gsup	dd	0		; LSL general support entry
control	dd	0		; MLID control entry
config	dd	0		; MLID configuration table
asup	dw	0, 0		; for as_send_pkt
board	dw	0		; logical board number
myvec	dw	4 * pkvec	; 4 * my vector
ifndef	nopid
stackid	dw	0		; stackid from LSL
endif
off	dw	12		; header offset for match
fmin	dw	60		; minimum frame size
rmode	dw	3		; current receiver mode
rmmap	dw	0, 1, 5, 7, 7, 15
nmulti	dw	0		; number of multicast addresses
mtab	db	mmulti * alen dup (?)
htab	hinfo	nhand dup (<>)	; the handle table
htabe	label	byte
stab	dw	14 dup (0)	; for get_statistics
ptab	db	1, 9, 14, alen	; for get_parameters
	dw	xbsize, mmulti * alen, 0, 0, 0
sECB	db	52 dup (0)	; transmit ECB
rECB	db	52 dup (0)	; receive ECB
xb	db	xbsize dup (?)	; receive buffer

upcall	proc	far
transcom:push	ds
	push	bp
	mov	ax, cs
	mov	ds, ax
	mov	ax, asup
	or	ax, asup + 2
	jz	trans1
	mov	ax, es:8[si]
	and	ax, ax
	jz	trans2
	mov	ax, 12
	add	stab + 20, 1
	adc	stab + 22, 0
trans2:	les	di, es:46[si]
	call	dword ptr asup
	mov	cs:asup, 0
	mov	cs:asup + 2, 0
trans1:	pop	bp
	pop	ds
	ret
recvcom:cmp	cs:xbusy, 0
	jnz	nobuf
	mov	dx, ds
	cld
	push	di
	mov	cx, 4[di]
	sub	cx, [di]
	mov	si, cs
	mov	es, si
	mov	ds, si
	mov	xbusy, 1
	mov	si, offset rECB
	mov	word ptr 46[si], offset xb
	add	word ptr 46[si], cx
	mov	word ptr 50[si], xbsize
	sub	word ptr 50[si], cx
	mov	ds, dx
	lds	si, [di]
	mov	di, offset xb
	rep	movsb
	mov	si, offset rECB
	pop	di
	mov	ds, dx
	xor	ax, ax
	ret
nobuf:	mov	ax, 8001h
	add	cs:stab + 16, 1
	adc	cs:stab + 18, 0
	and	ax, ax
	ret

recvcom2:push	bp
	push	ds
	push	es
	push	si
	mov	ax, cs
	mov	ds, ax
	cld
	cli
ifdef	stksw
	cmp	inhere, 0
	jz	notbusy
	add	stab + 16, 1
	adc	stab + 18, 0
	jmp	busy
notbusy:inc	inhere
	mov	bx, ss
	mov	cx, sp
	mov	ss, ax
	mov	sp, offset stack
	push	bx
	push	cx
endif
	mov	cx, es:42[si]
	add	cx, es:46[si]
	add	si, 52
	sub	cx, si
	cmp	cx, fmin
	jnc	enuf
	mov	cx, fmin
enuf:	push	es
	push	si
	push	cx
	add	stab, 1
	adc	stab + 2, 0
	add	stab + 8, cx
	adc	stab + 10, 0
	mov	bx, offset htab
recv1:	mov	cx, [bx].nmatch
	cmp	cx, -1
	jz	recv5
	jcxz	recv2
	mov	di, si
	cmp	class, 3
	jnz	norif
	test	byte ptr es:8[di], 80h
	jz	norif
	mov	al, es:14[di]
	and	al, 1fh
	xor	ah, ah
	add	di, ax
norif:	add	di, off
	lea	si, [bx].match
	repe	cmpsb
	jnz	recv5
recv2:	pop	cx
	push	cx
	push	bx
	xor	ax, ax
	call	dword ptr [bx].recvo
	pop	bx
	cld
	mov	ax, es
	or	ax, di
	jz	recv7
	pop	cx
	pop	si
	pop	ds
	push	ds
	push	si
	push	cx
	push	di
	shr	cx, 1
	rep	movsw
	jnc	recv3
	movsb
recv3:	pop	si
	pop	cx
	push	cx
	mov	ax, es
	mov	ds, ax
	push	bx
	mov	ax, 1
	call	dword ptr cs:[bx].recvo
	pop	bx
	cld
	cli
	mov	ax, cs
	mov	ds, ax
recv5:	pop	cx
	pop	si
	pop	es
	add	bx, size hinfo
	cmp	bx, offset htabe
	jnc	recv6
	push	es
	push	si
	push	cx
	jmp	short recv1
recv7:	cli
	mov	ax, cs
	mov	ds, ax
	add	stab + 24, 1
	adc	stab + 26, 0
	jmp	short recv5
recv6:

ifdef	stksw
	pop	cx
	pop	bx
	mov	ss, bx
	mov	sp, cx
	dec	inhere
endif
busy:	mov	xbusy, 0
	pop	si
	pop	es
	pop	ds
	pop	bp
	ret
pcont:	mov	ax, 8008h
	and	ax, ax
	ret
upcall	endp

nofunc:	mov	dh, 11
	jmp	bad

driver_info:pop	bx
	mov	bx, cs
	mov	ds, bx
	mov	bx, version
	mov	ch, class
	mov	dx, iftype
	xor	cl, cl
	mov	si, offset myname
	mov	al, 6
	jmp	good1

access_type:pop	bx
	push	ds
	push	cs
	pop	ds
	cmp	al, class
	jz	access_type1
	mov	dh, 2
	jmp	short access_type5
access_type1:cmp	bx, iftype
	jz	access_type7
	cmp	bx, -1
	jz	access_type7
	mov	dh, 3
	jmp	short access_type5
access_type7:and	dl, dl
	jz	access_type2
	mov	dh, 4
	jmp	short access_type5
access_type2:cmp	cx, mmatch + 1
	jc	access_type3
	mov	dh, 14
	jmp	short access_type5
access_type3:mov	bx, offset htab
access_type4:cmp	[bx].nmatch, -1
	jz	access_type6
	add	bx, size hinfo
	cmp	bx, offset htabe
	jc	access_type4
	mov	dh, 9
access_type5:pop	ds
	jmp	bad1
access_type6:mov	[bx].nmatch, cx
	mov	[bx].recvo, di
	mov	[bx].recvs, es
	mov	di, ds
	mov	es, di
	lea	di, [bx].match
	pop	ds
	rep	movsb
	mov	ax, bx
	jmp	good1

release_type:pop	bx
	mov	cs:[bx].nmatch, -1
	jmp	good1

send_pkt:sti
	push	ds
	mov	bx, ds
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
send_pkt1:cmp	word ptr 8 + sECB, 0
	jg	send_pkt1
	add	stab + 4, 1
	adc	stab + 6, 0
	add	stab + 12, cx
	adc	stab + 14, 0
	mov	word ptr sECB + 42, cx
	mov	word ptr sECB + 46, si
	mov	word ptr sECB + 48, bx
	mov	word ptr sECB + 50, cx
	mov	si, offset sECB
	mov	bx, 12
	call	psup
	sti
send_pkt2:cmp	word ptr 8 + sECB, 0
	jg	send_pkt2
	jnz	send_pkt3
	pop	ds
	jmp	good
send_pkt3:add	stab + 20, 1
	adc	stab + 22, 0
	pop	ds
	mov	dh, 12
	jmp	bad

terminate:push	ds
	mov	ax, cs
	mov	ds, ax
	mov	cx, nmulti
	jcxz	terminate2
	mov	si, offset mtab
terminate1:push	si
	push	cx
	mov	ax, cs
	mov	es, ax
	mov	ax, board
	mov	bx, 3
	call	control
	pop	cx
	pop	si
	add	si, alen
	loop	terminate1
terminate2:xor	ax, ax
	mov	es, ax
	mov	bx, myvec
	mov	ax, savpko
	mov	es:[bx], ax
	mov	ax, savpks
	mov	es:2[bx], ax
ifdef	nopid
	mov	ax, board
ifdef	defstk
	mov	bx, 9
else
	mov	bx, 11
endif
	call	psup
else
	mov	ax, stackid
	mov	bx, 22
	mov	cx, board
	call	psup
	mov	ax, stackid
	mov	bx, 7
	call	psup
endif
	mov	ax, cs
	mov	es, ax
	mov	ah, 49h
	int	21h
	pop	ds
	jmp	good

get_address:cmp	cx, alen
	jnc	get_address1
	mov	dh, 9
	jmp	bad
get_address1:push	ds
	lds	si, cs:config
	add	si, 28
	mov	cx, alen
	rep	movsb
	pop	ds
	mov	cx, alen
	jmp	good

reset_interface:mov	dh, 15
	jmp	bad

get_parameters:mov	di, cs
	mov	es, di
	mov	di, offset ptab
	jmp	good

as_send_pkt:sti
	push	ds
	mov	bx, ds
	mov	ax, cs
	mov	ds, ax
as_send_pkt1:cmp	word ptr 8 + sECB, 0
	jg	as_send_pkt1
	cli
	mov	asup, di
	mov	asup + 2, es
	sti
	mov	es, ax
	add	stab + 4, 1
	adc	stab + 6, 0
	add	stab + 12, cx
	adc	stab + 14, 0
	mov	word ptr sECB + 42, cx
	mov	word ptr sECB + 46, si
	mov	word ptr sECB + 48, bx
	mov	word ptr sECB + 50, cx
	mov	si, offset sECB
	mov	bx, 12
	call	psup
	sti
	pop	ds
	jmp	good

set_rcv_mode:mov	bx, cx
	dec	bx
	cmp	bx, 6
	jnc	set_rcv_mode1
	shl	bx, 1
	push	cx
	mov	ax, cs:rmmap[bx]
	mov	bx, 4
	mov	cx, -1
	call	cs:control
	pop	cx
;	jnz	set_rcv_mode1	; XXX no longer supported by ODI
	mov	cs:rmode, cx
	jmp	good
set_rcv_mode1:mov	dh, 8
	jmp	bad

get_rcv_mode:mov	ax, cs:rmode
	jmp	good

set_multicast_list:mov	ax, cx
	xor	dx, dx
	mov	bx, alen
	div	bx
	and	dx, dx
	jz	set_multicast_list1
	mov	dh, 14
	jmp	bad
set_multicast_list1:cmp	ax, mmulti + 1
	jc	set_multicast_list6
	mov	dh, 9
	jmp	bad
set_multicast_list6:push	ds
	push	cx
	push	ax
	push	es
	push	di
	mov	ax, cs
	mov	ds, ax
	mov	cx, nmulti
	jcxz	set_multicast_list3
	mov	si, offset mtab
set_multicast_list2:push	si
	push	cx
	mov	ax, cs
	mov	es, ax
	mov	ax, board
	mov	bx, 3
	call	control
	pop	cx
	pop	si
	add	si, alen
	loop	set_multicast_list2
set_multicast_list3:pop	si
	pop	ds
	pop	ax
	pop	cx
	mov	bx, cs
	mov	es, bx
	mov	di, offset mtab
	cld
	rep	movsb
	mov	bx, cs
	mov	ds, bx
	mov	nmulti, ax
	mov	cx, ax
	jcxz	set_multicast_list5
	mov	si, offset mtab
set_multicast_list4:push	si
	push	cx
	mov	ax, cs
	mov	es, ax
	mov	ax, board
	mov	bx, 2
	call	control
	pop	cx
	pop	si
	add	si, alen
	loop	set_multicast_list4
set_multicast_list5:pop	ds
	jmp	good

get_multicast_list:mov	di, cs
	mov	es, di
	mov	di, offset mtab
	mov	ax, cs:nmulti
	mov	cx, alen
	mul	cx
	mov	cx, ax
	jmp	good

get_statistics:mov	si, cs
	mov	ds, si
	mov	si, offset stab
	jmp	good

set_address:mov	dh, 13
	jmp	bad

funcs	dw	nofunc
	dw	driver_info
	dw	access_type
	dw	release_type
	dw	send_pkt
	dw	terminate
	dw	get_address
	dw	reset_interface
	dw	nofunc
	dw	nofunc

	dw	get_parameters
	dw	as_send_pkt
	dw	nofunc
	dw	nofunc
	dw	nofunc
	dw	nofunc
	dw	nofunc
	dw	nofunc
	dw	nofunc
	dw	nofunc

	dw	set_rcv_mode
	dw	get_rcv_mode
	dw	set_multicast_list
	dw	get_multicast_list
	dw	get_statistics
	dw	set_address

nfuncs	equ	($ - offset funcs) / 2

intpk	proc	far
	jmp	short dopk
	nop
sig	db	'PKT DRVR', 0
dopk:	cli
	cld
	push	bx
	cmp	ah, nfuncs
	jc	dopk1
	jmp	nofunc

dopk1:	mov	bl, ah
	xor	bh, bh
	shl	bx, 1
	jmp	cs:funcs[bx]

bad:	pop	bx
bad1:	stc
	sti
	ret	2
good:	pop	bx
good1:	clc
	sti
	ret	2
intpk	endp

start:	mov	ax, cs
	mov	ds, ax
	cld

	mov	dx, offset copyright
	mov	ah, 9
	int	21h

	mov	bx, 81h
	call	space
	call	number
	jc	start0
	mov	board, ax
	call	space
	call	number
	jc	start0
	add	ax, ax
	add	ax, ax
	mov	myvec, ax

start0:	xor	ax, ax
	mov	es, ax
	mov	bx, myvec
	les	di, es:[bx]
	add	di, 3
	mov	si, offset sig
	mov	cx, 9
	repe	cmpsb
	jnz	start1
	mov	dx, offset already
pexit:	mov	ah, 9
	int	21h
	int	20h

start1:	xor	ax, ax
	mov	es, ax
	xor	bx, bx
	xor	dx, dx
	mov	ah, 0c0h
start11:push	ax
	int	2fh
	cmp	al, 0ffh
	pop	ax
	jz	start13
start12:inc	ah
	jnz	start11
	mov	dx, offset nolsl
	jmp	pexit
start13:mov	ax, dx
	or	ax, bx
	jz	start12
	mov	di, si
	mov	si, offset lslname
	cld
	mov	cx, 8
	repe	cmpsb
	jz	start14
	xor	bx, bx
	xor	dx, dx
	jmp	start12

start14:mov	word ptr psup, bx
	mov	word ptr psup + 2, dx
	mov	si, cs
	mov	es, si
	mov	si, offset psup
	mov	bx, 2
	call	psup
	mov	ax, word ptr gsup
	or	ax, word ptr gsup + 2
	jnz	start2
	mov	dx, offset lslfail
	jmp	pexit

start2:	mov	bx, 18
	mov	ax, board
	call	psup
	jz	start3
	mov	dx, offset nocont
	jmp	pexit
start3:	mov	word ptr control, si
	mov	word ptr control + 2, es
	mov	ax, board
	xor	bx, bx
	call	control
	jz	start4
	mov	dx, offset noconf
	jmp	pexit
start4:	mov	word ptr config, si
	mov	word ptr config + 2, es
	mov	al, es:114[si]
	cmp	al, 8
	jnc	noloirq
	xor	ah, ah
	add	ax, 8
	mov	word ptr ptab + 12, ax
noloirq:mov	ax, es:60[si]
	cmp	ax, 4
	jz	istok
	cmp	ax, 11
	jz	istok
	cmp	ax, 3
	jz	is8023
	cmp	ax, 5
	jz	is8023
	cmp	ax, 10
	jz	is8023
	jmp	short gottype
istok:	mov	off, 14
	mov	ax, es:40[si]
	add	ax, 14
	cmp	ax, xbsize + 1
	jc	istok1
	mov	ax, xbsize
istok1:	mov	word ptr ptab + 4, ax
	mov	class, 3
	mov	fmin, 14
	jmp	short gottype
is8023:	mov	off, 14
	mov	class, 11
gottype:

ifdef	nopid
	mov	rinfo, offset recvcom
	mov	rinfo + 2, cs
	mov	rinfo + 4, offset pcont
	mov	rinfo + 6, cs
	mov	si, cs
	mov	es, si
	mov	si, offset rinfo
	mov	ax, board
ifdef	defstk
	mov	bx, 8
else
	mov	bx, 10
endif
	call	psup
	jz	start5
	mov	dx, offset rfail
	jmp	pexit
else
	mov	rinfo, offset sname
	mov	rinfo + 2, cs
	mov	rinfo + 4, offset recvcom
	mov	rinfo + 6, cs
	mov	rinfo + 8, offset pcont
	mov	rinfo + 10, cs
	mov	si, cs
	mov	es, si
	mov	si, offset rinfo
	mov	bx, 6
	call	psup
	jz	start51
	mov	dx, offset rfail
	jmp	pexit
start51:mov	stackid, bx
	mov	ax, bx
	mov	bx, 21
	mov	cx, board
	call	psup
	jz	start5
	mov	ax, stackid
	mov	bx, 7
	call	psup
	mov	dx, offset bfail
	jmp	pexit
endif

start5:	mov	word ptr sECB + 10, offset transcom
	mov	word ptr sECB + 12, cs
	mov	word ptr sECB + 14, -1
	mov	ax, board
	mov	word ptr sECB + 22, ax
	mov	word ptr sECB + 44, 1

	mov	word ptr rECB + 10, offset recvcom2
	mov	word ptr rECB + 12, cs
	mov	word ptr rECB + 14, -1
	mov	ax, board
	mov	word ptr rECB + 22, ax
	mov	word ptr rECB + 44, 1
	mov	word ptr rECB + 48, cs

	xor	ax, ax
	mov	es, ax
	pushf
	cli
	mov	bx, myvec
	mov	ax, es:[bx]
	mov	savpko, ax
	mov	ax, es:2[bx]
	mov	savpks, ax
	mov	es:[bx], offset intpk
	mov	es:2[bx], cs
	popf

	mov	dx, offset goodins
	mov	ah, 9
	int	21h

	mov	es, ds:[2ch]
	mov	ah, 49h
	int	21h
	mov	word ptr ds:[2ch], 0

	mov	cx, 5
	xor	bx, bx
cloop:	mov	ah, 3eh
	int	21h
	inc	bx
	loop	cloop

	mov	dx, offset start
	int	27h

number:	xor	ax, ax
	mov	cx, -1
number1:cmp	byte ptr [bx], '0'
	jc	number2
	cmp	byte ptr [bx], '9' + 1
	jnc	number2
	xor	cx, cx
	mov	dx, 10
	mul	dx
	mov	dl, byte ptr [bx]
	sub	dl, '0'
	xor	dh, dh
	add	ax, dx
	inc	bx
	jmp	short number1
number2:add	cx, 1
	ret

space:	cmp	byte ptr [bx], ' '
	jz	space1
	cmp	byte ptr [bx], 9
	jz	space1
	ret
space1:	inc	bx
	jmp	short space

ifdef	nopid
rinfo	dw	4 dup (0)
else
sname	db	6, 'ODIPKT', 0
rinfo	dw	6 dup (0)
bfail	db	'Failed to bind protocol stack', 13, 10, '$'
endif
lslname	db	'LINKSUP$'
already	db	'A driver is already installed at this vector.', 13, 10, '$'
goodins	db	'ODIPKT is installed and ready.', 13, 10, '$'
nolsl	db	'The Link Support Layer is not loaded.', 13, 10, '$'
lslfail	db	'The Link Support Layer failed to init.', 13, 10, '$'
nocont	db	'Cannot get MLID control entry', 13, 10, '$'
noconf	db	'Cannot get MLID configuration', 13, 10, '$'
rfail	db	'Failed to register protocol stack', 13, 10, '$'

CODE	ends
	end	at100h
