; PARnet interrupt handler
; 03-JUN-93 <S.A.Pechler@bdk.tue.nl>

	.MODEL	MEMMOD,C
	%MACS

        if @Datasize NE 0
           extrn   parint:far,maskoff:far,maskon:far
        else
           extrn   parint:near,maskoff:near,maskon:near
        endif

	.DATA
Isat    dw      0
int_no  dw      7               ; IRQ level used (=printer IRQ)
savess	dw	?		; saved SS during the stack swap.
savesp	dw	?		; saved SP
Intstk  dw      512 dup(?)      ; Interrupt working stack
Stktop  equ     $               ; SP set here when entering interrupt

	.CODE
dbase   dw      @Data           ;to get the right DS

eoi     PROC
        cmp     Isat,1
        jne     @@1             ; Only one 8259, so skip this stuff
        mov     al,0bh          ; read in-service register from
        out     0a0h,al         ; secondary 8259
        nop                     ; settling delay
        nop
        nop
        in      al,0a0h         ; get it
        or      al,al           ; Any bits set?
        jz      @@1             ; nope, not a secondary interrupt
        mov     al,20h          ; Get EOI instruction
        out     0a0h,al         ; Secondary 8259 (PC/AT only)
@@1:    mov     al,20h          ; 8259 end-of-interrupt command
        out     20h,al          ; Primary 8259
        ret
eoi     ENDP

	public parisr
        if @Datasize NE 0
        label parisr far
        else
        label parisr near
        endif

        push    ds
; Now switch stacks, push remaining registers, and do remaining interrupt work.
        mov     ds,cs:dbase        ; establish interrupt data segment

        mov     savesp,sp
	mov	savess,ss

	mov	ss,cs:dbase	; stack segment = data segment
        mov     sp,offset Stktop; initalize stacktop
	cld

        push    ax
	push	bx
	push	cx
        push    dx
	push	si
	push	di
	push	bp
	push	es

; The following comment is wrong in that we now do a specific EOI command,
; and because we don't enable interrupts (even though we should).

; Chips & Technologies 8259 clone chip seems to be very broken.  If you
; send it a Non Specific EOI command, it clears all In Service Register
; bits instead of just the one with the highest priority (as the Intel
; chip does and clones should do).  This bug causes our interrupt
; routine to be reentered if: 1. we reenable processor interrupts;
; 2. we reenable device interrupts; 3. a timer or other higher priority
; device interrupt now comes in; 4. the new interrupting device uses
; a Non Specific EOI; 5. our device interrupts again.  Because of
; this bug, we now completely mask our interrupts around the call
; to "parint", the real device interrupt handler.  This allows us
; to send an EOI instruction to the 8259 early, before we actually
; reenable device interrupts.  Since the interrupt is masked, we
; are still guaranteed not to get another interrupt from our device
; until the interrupt handler returns.  This has another benefit:
; we now no longer prevent other devices from interrupting while our
; interrupt handler is running.  This is especially useful if we have
; other (multiple) packet drivers trying to do low-latency transmits.
        mov     ax,int_no       ; Disable further device interrupts
        push    ax
        call    maskoff
        inc     sp
        inc     sp

        call    eoi

        sti                             ; Interrupts are now completely safe
        mov  ax,0
        push ax
        call    parint                  ; user interrupt routine
        inc sp
        inc sp

	cli				;interrupts *must* be off between
					;here and the stack restore, because
					;if we have one of our interrupts
					;pending, we would trash our stack.
        mov     ax,int_no       ; Now reenable device interrupts
        push    ax
        call    maskon
        inc     sp
        inc     sp

	pop	es
	pop	bp
	pop	di
	pop	si
        pop     dx
	pop	cx
	pop	bx
        pop     ax

	mov	ss,savess
	mov	sp,savesp

	pop	ds
	iret

; Convert 32-bit int in network order to host order (dh, dl, ah, al)
; Called from C as
; int32 get32(char *cp);

	public	get32
get32	proc
	arg	cp:ptr
	if	@Datasize NE 0
		uses	ds,si
		lds	si,cp	; ds:si = cp
	else
		uses	si
		mov	si,cp	; ds:si = cp (ds already set)
	endif

	cld
	lodsw
	mov	dh,al	; high word to dx, a-swapping as we go
	mov	dl,ah
	lodsw
	xchg	al,ah	; low word stays in ax, just swap
	ret
get32	endp

; Convert 16-bit int in network order to host order (ah, al)
; Called from C as
; int16 get16(char *cp);

	public	get16
get16	proc
	arg	cp:ptr
	if	@Datasize NE 0
		uses	ds,si
		lds	si,cp	; ds:si = cp
	else
		uses	si
		mov	si,cp	; ds:si = cp (ds already set)
	endif

	lodsw		; note: direction flag is don't-care
	xchg	al,ah	; word stays in ax, just swap
	ret
get16	endp

; Convert 32-bit int to network order, returning new pointer
; Called from C as
; char *put32(char *cp,int32 x);

	public	put32
put32	proc
	arg	cp:ptr,x:dword
	if	@Datasize NE 0
		uses	ds,di
		les	di,cp	; es:di = cp
		mov	ax,ss	; our parameter is on the stack, and ds might not
		mov	ds,ax	;   be pointing to ss.
	else
		uses	di
		mov	di,cp	; es:di = cp
		mov	ax,ds	; point es at data segment
		mov	es,ax
	endif

	cld
	mov	ax,word ptr (x+2)	; read high word of machine version
	xchg	ah,al			; swap bytes
	stosw				; output in network order
	mov	ax,word ptr x		; read low word of machine version
	xchg	ah,al			; swap bytes
	stosw				; put in network order

	mov	ax,di	; return incremented output pointer
	if	@Datasize NE 0
		mov	dx,es	; upper half of pointer
	endif
	ret
put32	endp

; Convert 16-bit int to network order, returning new pointer
; Called from C as
; char *put16(char *cp,int16 x);

	public	put16
put16	proc
	arg	cp:ptr,x:word
	uses	di
	if	@Datasize NE 0
		les	di,cp	;es:di = cp
	else
		mov	di,cp	; es:di = cp
		mov	ax,ds
		mov	es,ax
	endif
	cld
	mov	ax,x	; fetch source word in machine order
	xchg	ah,al	; swap bytes
	stosw		; save in network order
	mov	ax,di	; return new output pointer to user
	if	@Datasize NE 0
		mov	dx,es	; upper half of pointer
	endif
	ret
put16   endp


	end
