;
; Process a PXE interrupt
;
		section .text16

PXEIRQ_MAX	equ 100		; Max spurious interrupts in a timer tick

		global pxe_isr
pxe_isr:
		cld
		pusha
		push ds
		push es
		push fs
		push gs

		xor ax,ax
		mov ds,ax	
		mov es,ax

		mov bx,PXENV_UNDI_ISR
		mov di,pxenv_undi_isr_buf

		mov cx,pxenv_undi_isr_buf.size/2
		push di
		rep stosw
		pop di
		
		mov byte [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_IN_START

		call pxenv
		mov ax,[__jiffies]
		jc .notus

		cmp word [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_OUT_OURS
		jne .notus

		; Its ours - set the flag for the return to PM.
		; We need to EOI this ourselves, so that the
		; leftover BC doesn't get control.
		mov byte [pxe_irq_pending],1
		inc dword [pxe_irq_count]

		cmp byte [pxe_irq_vector], 8
		mov al,0x20		; Non-specific EOI
		jb .pri_pic

		out 0xA0, al		; Secondary PIC
.pri_pic:
		out 0x20,al		; Primary PIC

		mov [pxeirq_last],ax
		mov word [pxeirq_deadman],PXEIRQ_MAX

.exit:
		pop gs
		pop fs
		pop es
		pop ds
		popa
		iret

.notus:
		cmp ax,[pxeirq_last]
		jne .reset_timeout
		dec word [pxeirq_deadman]
		jz .timeout

.chain:
		pop gs
		pop fs
		pop es
		pop ds
		popa
		jmp 0:0
		global pxe_irq_chain
pxe_irq_chain	equ $-4

.reset_timeout:
		mov [pxeirq_last],ax
		mov word [pxeirq_deadman],PXEIRQ_MAX
		jmp .chain

		; Too many spurious interrupts, shut off the interrupts
		; and go to polling mode
.timeout:
		mov al,[pxe_irq_vector]
		mov dx,21h
		movzx cx,al
		shl cx,7-3
		add dx,cx
		and al,7
		xchg ax,cx
		mov ch,1
		shl ch,cl
		in al,dx
		or al,ch
		out dx,al
		or byte [pxe_need_poll],1
		jmp .exit


; Emulate a PXE interrupt from the polling thread
		global pxe_poll
pxe_poll:
		pushf
		cli
		cld
		pusha
		push ds
		push es
		push fs
		push gs

		mov bx,PXENV_UNDI_ISR
		mov di,pxenv_undi_isr_buf

		mov cx,pxenv_undi_isr_buf.size/2
		push di
		rep stosw
		pop di
		
		mov byte [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_IN_START

		call pxenv
		jc .notus

		cmp word [pxenv_undi_isr_buf.funcflag],PXENV_UNDI_ISR_OUT_OURS
		jne .notus

		; Its ours - set the flag for the return to PM.
		; We need to EOI this ourselves, so that the
		; leftover BC doesn't get control.
		mov byte [pxe_irq_pending],1

.notus:
		pop gs
		pop fs
		pop es
		pop ds
		popa
		popf
		ret

		section .bss16
		alignb 4
pxenv_undi_isr_buf:
.status:	resw 1
.funcflag:	resw 1
.bufferlength:	resw 1
.framelen:	resw 1
.framehdrlen:	resw 1
.frame:		resw 2
.prottype:	resb 1
.pkttype:	resb 1
.size		equ $-pxenv_undi_isr_buf

		alignb 4
pxeirq_last	resw 1
pxeirq_deadman	resw 1

		global pxe_irq_count
pxe_irq_count	resd 1			; PXE IRQ counter
		global pxe_irq_vector
pxe_irq_vector	resb 1			; PXE IRQ vector
		global pxe_irq_pending
pxe_irq_pending	resb 1			; IRQ pending flag
		global pxe_need_poll
pxe_need_poll	resb 1			; Bit 0 = need polling
					; Bit 1 = polling active

		section .text16