
/*

   Name:
   MDMA.C

   Description:
   Some general purpose IRQ routines

   Portability:

   MSDOS:       BC(y)   Watcom(y)       DJGPP(y)
   Win95:       n
   Os2: n
   Linux:       n

   (y) - yes
   (n) - no (not possible or not useful)
   (?) - may be possible, but not tested

 */
#include <dos.h>
#include <conio.h>
#include "mirq.h"

#define OCR1	0x20		/* 8259-1 Operation control register */
#define IMR1	0x21		/* 8259-1 Mask register */

#define OCR2	0xA0		/* 8259-2 Operation control register */
#define IMR2	0xA1		/* 8259-2 Mask register */


BOOL MIrq_IsEnabled(UBYTE irqno)
/*
   Returns true if the specified hardware irq is enabled.
 */
{
    UBYTE imr = (irqno > 7) ? IMR2 : IMR1;	/* interrupt mask register */
    UBYTE msk = 1 << (irqno & 7);	/* interrupt mask */
    return ((inportb(imr) & msk) == 0);
}


BOOL MIrq_OnOff(UBYTE irqno, UBYTE onoff)
/*
   Use to enable or disable the specified irq.
 */
{
    UBYTE imr = (irqno > 7) ? IMR2 : IMR1;	/* interrupt mask register */
    UBYTE ocr = (irqno > 7) ? OCR2 : OCR1;	/* ocr */
    UBYTE msk = 1 << (irqno & 7);	/* interrupt mask */
    UBYTE eoi = 0x60 | (irqno & 7);	/* specific end-of-interrupt */
    BOOL oldstate;

    /* save current setting of this irq */
    oldstate = ((inportb(imr) & msk) == 0);

    if (onoff) {
	outportb(imr, inportb(imr) & ~msk);
	outportb(ocr, eoi);
	if (irqno > 7)
	    MIrq_OnOff(2, 1);
    }
    else {
	outportb(imr, inportb(imr) | msk);
    }

    return oldstate;
}


void MIrq_EOI(UBYTE irqno)
/*
   Clears the specified interrupt request at the interrupt controller.
 */
{
    UBYTE ocr = (irqno > 7) ? OCR2 : OCR1;	/* ocr */
    UBYTE eoi = 0x60 | (irqno & 7);	/* specific end-of-interrupt */

    outportb(ocr, eoi);
    if (irqno > 7)
	outportb(OCR1, 0x20);
}


PVI MIrq_SetHandler(UBYTE irqno, PVI handler)
{
#ifdef __DJGPP__
    _go32_dpmi_seginfo seginfo;
#endif
    PVI oldvect;
    int vecno = (irqno > 7) ? irqno + 0x68 : irqno + 0x8;
#ifdef __DJGPP__
    _go32_dpmi_get_protected_mode_interrupt_vector(vecno, &seginfo);
    oldvect = seginfo.pm_offset;
    seginfo.pm_offset = handler;
    seginfo.pm_selector = _go32_my_cs();
    _go32_dpmi_allocate_iret_wrapper(&seginfo);
    _go32_dpmi_set_protected_mode_interrupt_vector(vecno, &seginfo);
#else
    oldvect = _dos_getvect(vecno);
    _dos_setvect(vecno, handler);
#endif
    return oldvect;
}
