;  Russell Nelson, Clarkson University.  September 14, 1989
;  Copyright, 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.

	include	defs.asm

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

	org	80h
phd_dioa	label	byte

	org	100h
start:
	jmp	start_1

their_isr	dd	?
packet_int_no	db	?,?
packet_mode	dw	-1

handle		dw	0
this_mode	dw	?
bogus_type	db	1,2,3,4,5,6,7,8		;totally bogus type code.

signature	db	'PKT DRVR',0
signature_len	equ	$-signature
no_signature_msg	db	"No packet driver at that address",'$'
usage_msg	db	"usage: pktmode <packet_int_no> [<mode>]",'$'
bad_handle_msg	db	"Bad handle error",'$'
bad_mode_msg	db	"Bad mode error",'$'
bad_error_msg	db	"Unknown error",'$'

not_implemented	db	"xx ",'$'
current_mode	db	"-> ",'$'
two_spaces	db	"   ",'$'

mode_names	dw	mode_1_msg,mode_2_msg,mode_3_msg,mode_4_msg
		dw	mode_5_msg,mode_6_msg

mode_1_msg	db	"1) Turn off receiver",CR,LF,'$'
mode_2_msg	db	"2) Receive only packets sent to this interface",CR,LF,'$'
mode_3_msg	db	"3) Mode 2 plus broadcast",CR,LF,'$'
mode_4_msg	db	"4) Mode 3 plus limited multicast",CR,LF,'$'
mode_5_msg	db	"5) Mode 3 plus all multicast",CR,LF,'$'
mode_6_msg	db	"6) All packets",CR,LF,'$'


usage_error:
	mov	dx,offset usage_msg
error:
	mov	ah,9
	int	21h
	jmp	all_done

start_1:
	mov	si,offset phd_dioa+1
	cmp	byte ptr [si],CR	;end of line?
	je	usage_error

	mov	di,offset packet_int_no
	call	get_number
	mov	di,offset packet_mode
	call	get_number

	mov	ah,35h			;get their packet interrupt.
	mov	al,packet_int_no
	int	21h
	mov	their_isr.offs,bx
	mov	their_isr.segm,es

	lea	di,3[bx]
	mov	si,offset signature
	mov	cx,signature_len
	repe	cmpsb
	je	signature_ok
	mov	dx,offset no_signature_msg
	jmp	error
bad_j_1:
	jmp	bad
signature_ok:

	mov	ah,2			;access all packets.
	mov	al,1			;Ethernet class.
	mov	bx,-1			;generic type.
	mov	dl,0			;generic number.
	mov	cx,MAX_P_LEN		;use the max type length.
	mov	si,offset bogus_type
	push	cs			;es:di -> our receiver.
	pop	es
	mov	di,offset our_recv
	pushf
	cli
	call	their_isr
	jc	bad_j_1
	mov	handle,ax

	mov	cx,packet_mode
	cmp	cx,-1
	je	get_mode

	mov	ah,20			;set the receive mode.
	mov	bx,handle
	pushf
	cli
	call	their_isr
	jc	bad_j_1
	jmp	okay
get_mode:
	mov	ah,21			;get the receive mode.
	mov	bx,handle
	pushf
	cli
	call	their_isr
	jc	bad
	mov	packet_mode,ax

	mov	this_mode,1		;start trying with mode 1.
try_mode:
	cmp	this_mode,6		;have we hit the last mode?
	ja	no_more_modes		;yes.

	mov	ah,20			;set the receive mode.
	mov	bx,handle
	mov	cx,this_mode
	pushf
	cli
	call	their_isr
	mov	dx,offset not_implemented
	jc	tried_mode		;we tried it, and it didn't work.
	mov	dx,offset current_mode
	mov	cx,this_mode		;is this the current mode?
	cmp	packet_mode,cx
	je	tried_mode
	mov	dx,offset two_spaces
tried_mode:
	mov	ah,9			;print either "  ", "xx", or "->"
	int	21h

	mov	bx,this_mode		;print the name of this mode.
	shl	bx,1
	mov	ah,9
	mov	dx,mode_names[bx-2]
	int	21h

	inc	this_mode		;try the next mode.
	jmp	try_mode

no_more_modes:

	mov	ah,20			;set the receive mode.
	mov	bx,handle
	mov	cx,packet_mode
	pushf
	cli
	call	their_isr

all_done:
	xor	bx,bx			;only release the handle once.
	xchg	bx,handle
	or	bx,bx
	je	all_done_1		;we've already released it.
	mov	ah,3			;release_type
	pushf
	cli
	call	their_isr
	jc	bad
all_done_1:
	int	20h

bad:
	cmp	dh,BAD_HANDLE
	jne	bad_1
	mov	dx,offset bad_handle_msg
	jmp	error
bad_1:
	cmp	dh,BAD_MODE
	jne	bad_2
	mov	dx,offset bad_mode_msg
	jmp	error
bad_2:
	mov	dx,offset bad_error_msg
	jmp	error
okay:
	jmp	all_done


our_recv:
	or	ax,ax			;first or second call?
	jne	our_recv_1		;second -- we ignore the packet
	push	cs
	pop	es
	mov	di,offset our_buffer
our_recv_1:
	retf


	public	get_number
get_number:
	mov	bp,10			;we default to 10.
	jmp	short get_number_0

	public	get_hex
get_hex:
	mov	bp,16
;get a hex number from [si], skipping leading blanks.
;return cy if there are no digits at all.
;return nc, bx:cx = number, and store cx at [di]
get_number_0:
	call	skip_blanks
	call	get_digit		;is there really a number here?
	jc	get_number_3
	or	al,al			;Does the number begin with zero?
	jne	get_number_4		;no.
	mov	bp,8			;yes - they want octal.
get_number_4:

	xor	cx,cx			;get a hex number.
	xor	bx,bx
get_number_1:
	lodsb
	cmp	al,'x'			;did they really want hex?
	je	get_number_5		;yes.
	cmp	al,'X'			;did they really want hex?
	je	get_number_5		;yes.
	call	get_digit		;convert a character into an int.
	jc	get_number_2		;not a digit (neither hex nor dec).
	xor	ah,ah
	cmp	ax,bp			;larger than our base?
	jae	get_number_2		;yes.

	push	ax			;save the new digit.

	mov	ax,bp			;multiply the low word by ten.
	mul	cx
	mov	cx,ax			;keep the low word.
	push	dx			;save the high word for later.
	mov	ax,bp
	mul	bx
	mov	bx,ax			;we keep only the low word (which is our high word)
	pop	dx
	add	bx,ax			;add the high result from earlier.

	pop	ax			;get the new digit back.
	add	cx,ax			;add the new digit in.
	adc	bx,0
	jmp	get_number_1
get_number_5:
	mov	bp,16			;change the base to hex.
	jmp	get_number_1
get_number_2:
	dec	si
	mov	[di],cx			;store the parsed number.
	clc
	ret
get_number_3:
	stc
	ret


	public	skip_blanks
skip_blanks:
	lodsb				;skip blanks.
	cmp	al,' '
	je	skip_blanks
	cmp	al,HT
	je	skip_blanks
	dec	si
	ret


get_digit:
;enter with al = character
;return nc, al=digit, or cy if not a digit.
	cmp	al,'0'			;decimal digit?
	jb	get_digit_1		;no.
	cmp	al,'9'			;. .?
	ja	get_digit_2		;no.
	sub	al,'0'
	clc
	ret
get_digit_2:
	or	al,20h
	cmp	al,'a'			;hex digit?
	jb	get_digit_1
	cmp	al,'f'			;hex digit?
	ja	get_digit_1
	sub	al,'a'-10
	clc
	ret
get_digit_1:
	stc
	ret

our_buffer	label	byte

code	ends

	end	start
