/*

Name:
MIRQ.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 */


//
//  Returns true if the specified hardware irq is enabled.
//
BOOL MIrq_IsEnabled(UBYTE irqno)
{
    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;
}


/*
    Clears the specified interrupt request at the interrupt controller.
*/
void MIrq_EOI(UBYTE irqno)
{
        outportb(0x20,0x20);
        if(irqno>7) outportb(0xa0,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;
}
