/*
 *  Additional C routines to the PC Parnet interface.
 *  Routines ripped from NOS1229.
 *
 *  CHECK YOUR CABLE(S) & INTERFACE(S) BEFORE USING PARNET!
 */

#define DEBUG 1

#ifdef DEBUG
#include <stdio.h>
#endif
#include <dos.h>
#include "pardev.h"

INTERRUPT (*oldvec)(void); /* original irq vector */
int oldmask; /* original irq mask */
int Isat=0; /* no need to change when you have an AT */

/* stupid inline definition of outportb in dos.h */
#undef outportb

/* Set bit(s) in I/O port */
void
setbit(port,bits)
unsigned port;
char bits;
{
    outportb(port,(char)inportb(port)|bits);
}
/* Clear bit(s) in I/O port */
void
clrbit(port,bits)
unsigned port;
char bits;
{
    outportb(port,(char)(inportb(port) & ~bits));
}

/* Disable given hardware interrupt */
int
maskoff(irq)
unsigned irq;
{
	if(irq < 8){
		setbit(0x21,(char)(1<<irq));
	} else if(irq < 16){
		irq -= 8;
		setbit(0xa1,(char)(1<<irq));
	} else {
		return -1;
	}
	return 0;
}
/* Enable given hardware interrupt */
int
maskon(irq)
unsigned irq;
 {
	if(irq < 8){
		clrbit(0x21,(char)(1<<irq));
	} else if(irq < 16){
		irq -= 8;
		clrbit(0xa1,(char)(1<<irq));
	} else {
		return -1;
	}
	return 0;
}

/* get the interrupt mask */
int
getmask(irq)
unsigned irq;
{
	if(irq < 8)
		return (inportb(0x21) & (1 << irq)) ? 0 : 1;
	else if(irq < 16){
		irq -= 8;
		return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
	} else
		return -1;
}

/* Install hardware interrupt handler.
 * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
 * Note that bus line IRQ2 maps to IRQ9 on the AT
 * For PARnet only IRQ7 will be used, unless your printercard supports
 * different IRQ lines.
 */
int
setirq(irq,handler)
unsigned irq;
INTERRUPT (*handler)();
{
	/* Set interrupt vector */
	if(irq < 8){
		setvect(8+irq,handler);
	} else if(irq < 16){
		Isat = 1;
		setvect(0x70 + irq - 8,handler);
	} else {
		return -1;
	}
	return 0;
}

/* Return pointer to hardware interrupt handler.
 * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
 */
INTERRUPT
(*getirq(irq))()
unsigned int irq;
{
	/* Set interrupt vector */
	if(irq < 8){
		return getvect(8+irq);
	} else if(irq < 16){
		return getvect(0x70 + irq - 8);
	} else {
		return NULLVIFP;
	}
}

/* Initialize parnet */
void
par_init(netaddr,portaddr)
int16 netaddr,portaddr;
{
    disable();  /* disable all interrupts */

	/* Save original interrupt vector and mask state */
    oldvec = getirq(7);
#ifdef DEBUG
    printf("oldvec: %04x:%04x, newvec: %04x:%04x\n",
           FP_SEG(oldvec),FP_OFF(oldvec),FP_SEG(parisr),FP_OFF(parisr));
    fflush(stdout);
#endif
    oldmask = getmask(7);

	/* initialize hardware address and printer port */
#ifdef DEBUG
    printf("par_init: calling paraddress: %04x:%04x(%x,%x)\n",
           FP_SEG(paraddress),FP_OFF(paraddress),netaddr,
           portaddr);fflush(stdout);
#endif
    paraddress(netaddr,portaddr);   /* see parkern.asm */

    /* Set interrupt vector to SIO handler (see parvec.asm) */
    setirq(7,parisr);
    maskon(7);      /* IRQ7 enabled */
    enable();       /* enable all interrupts */
}

int
par_stop(void)
{
    disable();
    setirq(7,oldvec);
    if (oldmask)
        maskon(7);
	else
        maskoff(7);
    enable();
	return 0;
}

