	title PGLUE - Packet driver real-mode glue routines

	.286p

	include	data.inc

_DATA	SEGMENT  WORD PUBLIC 'DATA'
_DATA	ENDS
_BSS	SEGMENT PARA PUBLIC 'BSS'
_BSS	ENDS
_TEXT	SEGMENT  para PUBLIC 'CODE'
_TEXT	ENDS

DGROUP	GROUP	_DATA,_BSS

_DATA	SEGMENT

	PUBLIC	_shared
_shared		real_data	<>
n_buf	db	6 dup (0)
nums	db	'0123456789abcdef'

_kbd_ack	db	?
cl_lock		db	0
		align	2

oldint08off	dw	0
oldint08seg	dw	0

oldint28off	dw	0
oldint28seg	dw	0

busyptr		dd	0

rpsgen_off	dw	?
rpsgen_seg	dw	?

	db	512 dup (?)
mystack	label	word
savess	dw	?
savesp	dw	?

_DATA	ENDS

	ASSUME cs:_TEXT, ds:nothing, es:nothing, ss:nothing

	extrn	_pkopen:near
	extrn	_pkclose:near
	extrn	@pkxmit:near

_TEXT	SEGMENT
	packet_funcs	dw	offset init		; 1
			dw	offset shutdown		; 2
	nfuncs	EQU	($ - offset packet_funcs) / 2

init_rpc	PROC	FAR
	mov	dx,offset p_rpc
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP
	mov	rpsgen_off,bx
	mov	rpsgen_seg,es
	mov	ax,_TEXT
	mov	ds,ax
	ret
init_rpc	ENDP

	ASSUME	ds:nothing

	; real procedure entry point
	; called by kernel with:
	; CX	= # bytes in transaction buffer
	; DS:DX = transaction buffer
	; return AX = # bytes returned
	;
; My procedure will use the buffer count to determine what to do.
; If CX =
;	0:	Send packet in xmit buffer in shared memory segment.  Replace
;			xmit length with return code.  As this is called
;			most often, make it efficient.
;	other:	Other function, determined by first byte in transaction
;			buffer.  1 = init, 2 = shutdown.
;	other calling convention: si = second word in buffer (after function
;	code) ds:dx = buffer.
	PUBLIC	p_rpc
p_rpc		PROC	FAR
	jcxz	short xmit
	push	si
	push	di

	mov	si,dx		; put buffer in si
	lodsw			; load al (function code) and ah
	dec	al
	cmp	al,nfuncs
	jae	err
	mov	bl,al
	xor	bh,bh
	shl	bx,1
	mov	ax,cs:packet_funcs[bx]
	call	ax
	jmp	short exit
err:
	xor	ax,ax
exit:
	pop	di
	pop	si
	ret
xmit:
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP
	mov	ax,_shared.xmitlen
	cmp	_shared.arpqueued,2
	mov	bx,offset _shared.xmitbuf
	jnz	sendit
	mov	bx,offset _shared.xmitarp
sendit:
	call	@pkxmit
	mov	_shared.xmitlen,ax
	xor	ax,ax		; return length 0

	ret
	ASSUME	ds:nothing
p_rpc		ENDP

init	PROC	NEAR
	push	ds		; save transaction buffer seg

	mov	ax,DGROUP
	mov	es,ax
	ASSUME	es:DGROUP
	lodsw			; packet class
	push	ax
	lodsw			; packet interrupt number
	push	ax
	add	si,2		; pad
	mov	di,offset _shared.myip
	movsw			; save my ip address in myip
	movsw			; IP address is 4 bytes (2 words)
	mov	si,dx		; save transaction buffer for output

	mov	ax,es
	mov	ds,ax
	ASSUME	ds:DGROUP

	call	_pkopen		; initialize the packet driver
	add	sp,4		; remove 2 arguments
	pop	es		; retrieve trans buf segment
	ASSUME	es:nothing
	mov	es:[si],ax	; return status from pkopen
	or	ax,ax
	jz	init_ok
	mov	ax,2		; return only 2 bytes (status)
	ret

init_ok:
	push	es

	mov	ah,34h		; get DOS busy flag
	int	21h
	mov	word ptr busyptr+2,es
	mov	word ptr busyptr,bx

	mov	ax,03508h
	int	21h
	mov	oldint08off,bx
	mov	oldint08seg,es
	mov	cx,ds		; save ds
	mov	ax,cs
	mov	ds,ax
	ASSUME	ds:_TEXT
	mov	dx,offset clock_int
	mov	ax,02508h
	int	21h

	mov	ds,cx		; restore ds
	ASSUME	ds:DGROUP

	mov	ax,03528h
	int	21h
	mov	oldint28off,bx
	mov	oldint28seg,es
	mov	ax,cs
	mov	ds,ax
	ASSUME	ds:_TEXT
	mov	dx,offset kbd_loop
	mov	ax,02528h
	int	21h

	mov	ds,cx		; restore ds
	ASSUME	ds:DGROUP

	pop	es
	ASSUME	es:nothing
	mov	word ptr es:[si+2],0
	mov	word ptr es:[si+4],offset _shared
	mov	word ptr es:[si+6],ds
	mov	word ptr es:[si+8],size _shared
	mov	dx,si		; restore buffer
	mov	ax,10		; 8 bytes returned

	ret
init	ENDP
	ASSUME	ds:nothing

shutdown	PROC NEAR
	push	ds
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP
	call	_pkclose

	mov	cx,ds		; save ds
	mov	dx,oldint08off
	or	dx,dx
	jz	shut_1
	mov	ax,02508h
	mov	ds,oldint08seg
	ASSUME	ds:nothing
	int	21h
shut_1:
	mov	ds,cx
	assume	ds:DGROUP
	mov	dx,oldint28off
	or	dx,dx
	jz	shut_2
	mov	ax,02528h
	mov	ds,oldint28seg
	ASSUME	ds:nothing
	int	21h
shut_2:

	pop	ds
	ASSUME	ds:nothing
	xor	ax,ax		; returned bytes = 0
	ret
shutdown	ENDP

	PUBLIC  @n_clicks
; u_long _near _fastcall n_clicks(void)
;
;	get the number of timer clicks from BIOS
;
@n_clicks  PROC	NEAR
	mov	ah,0
	int	1ah
	mov	ax,dx		; MSC uses AX-lo, DX-hi
	mov	dx,cx		; return values from interrupt 1A
	ret
@n_clicks ENDP

	PUBLIC	@dfputs
; void _fastcall dfputs(cp)
; char *cp;
@dfputs	PROC NEAR
	ASSUME	ds:DGROUP
	ASSUME	es:nothing
	push	si
	mov	si,bx
put_loop:
	lodsb
	or	al,al
	jz	put_exit
	mov	dl,al
	mov	ah,2
	int	21h
	jmp	short put_loop
put_exit:
	pop	si
	ret
@dfputs	ENDP

	PUBLIC	@printn
@printn PROC NEAR
	xor	bl,bl
	mov	n_buf+4,bl
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+3,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+2,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+1,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf,bl
	mov	bx,offset n_buf
	jmp	short @dfputs
@printn	ENDP

	PUBLIC	@printd
@printd PROC NEAR
	mov	bx,offset n_buf+5
	xor	cl,cl
	mov	[bx],cl
	mov	cx,10		; divide by 10
pd_1:
	xor	dx,dx		; divide number by 10
	div	cx
	add	dx,'0'		; remainder is in dx
	dec	bx
	mov	[bx],dl
	or	ax,ax
	jnz	pd_1		; more to divide
	jmp	short @dfputs
@printd	ENDP

kbd_loop	PROC FAR
	ASSUME	ds:nothing
	push	ds
	push	ax
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP
	pushf
	call	dword ptr [oldint28off]

	jmp	short clock_1

clock_int:
	push	ds
	push	ax
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP
	pushf
	call	dword ptr [oldint08off]

	push	si
	push	ds
	lds	si,busyptr
	lodsb
	pop	ds
	pop	si

	or	al,al
	jnz	clock_exit

clock_1:

	cli
	mov	al,cl_lock
	or	al,al
	jnz	clock_exit
	inc	al
	mov	cl_lock,al

	mov	al,_shared.rps_handle
	or	al,al
	jz	clock_3

	sti

	push	es
	push	bx
	push	cx
	push	dx
	push	si
	push	di

	mov	savesp,sp
	mov	savess,ss
	mov	bx,ds
	mov	ss,bx
	mov	sp,offset DGROUP:mystack

	mov	bx,_shared.prot_ds

	call	dword ptr [rpsgen_off]

;	mov	cx,_shared.xmitlen
;	jcxz	clock_2
;	push	es
;	push	ds
;	push	cx		; xmitlen
;	push	offset _shared.xmitbuf
;	call	_pkxmit
;	add	sp,4
;	xor	ax,ax
;	mov	_shared.xmitlen,ax
;	pop	ds
;	pop	es
clock_2:
	mov	ss,savess
	mov	sp,savesp

	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	es
clock_3:
	cli
	xor	al,al
	mov	cl_lock,al
clock_exit:
	pop	ax
	pop	ds
	ASSUME	ds:nothing
	iret
kbd_loop	ENDP

_TEXT	ENDS
	END	init_rpc
