/***************************************************************************
* NAME: IRQ.C
** COPYRIGHT:
** "Copyright (c) 1992, by FORTE
**
** "This software is furnished under a license and may be used,
** copied, or disclosed only in accordance with the terms of such
** license and with the inclusion of the above copyright notice.
** This software or any other copies thereof may not be provided or
** otherwise made available to any other person. No title to and
** ownership of the software is hereby transfered."
****************************************************************************
* CREATION DATE: 11/18/92
*--------------------------------------------------------------------------*
* VERSION DATE NAME DESCRIPTION
*> 1.0 11/18/92 Original
***************************************************************************/
#include <stdio.h>
#include <dos.h>
// #include <conio.h>
#include "forte.h"
#include "gf1proto.h"
#include "osproto.h"
/* internal include files */
#include "gf1hware.h"
#include "dma.h"
#include "irq.h"
#include "gf1os.h"
/* #pragma inline */
extern IRQ_ENTRY _gf1_irq[];
extern DMA_ENTRY _gf1_dma[];
extern ULTRA_DATA _gf1_data;
extern void SaveSegRegs();
extern void GetSegRegs();
void
gf1_setvect( int int_number, PVI isr )
{
#ifdef METAWARE
SaveSegRegs();
/* set protected mode irq handler ... */
_setpvect(int_number,isr);
// _setrpvectp(int_number,isr);
#endif
#ifdef WATCOMC
/* set protected mode irq handler ... */
union REGS r;
r.x.eax = 0x0205;
r.h.bl = int_number;
r.x.edx = FP_OFF (isr);
r.w.cx = FP_SEG (isr);
int386 (0x31, &r, &r); /* set prot. vector thru DPMI */
#endif /* WATCOMC */
#ifdef MSOFTC
asm push ds;
asm lds dx,isr;
asm mov ah,0x25;
asm mov al,int_number;
asm int 21h;
asm pop ds;
#endif
#ifdef BORLANDC
asm push ds;
asm lds dx,isr;
asm mov ah,0x25;
_AL = int_number;
asm int 21h;
asm pop ds;
#endif
}
PVI
gf1_getvect( int int_number )
{
#ifdef METAWARE
return(_getpvect(int_number));
#endif
#ifdef WATCOMC
union REGS r;
r.x.eax = 0x0204;
r.h.bl = int_number;
int386 (0x31, &r, &r);
return ((PVI)MK_FP (r.w.cx, r.x.edx));
#endif
#ifdef MSOFTC
asm push ds;
asm mov ah,0x35;
asm mov al,int_number;
asm int 21h;
asm mov dx,es;
asm mov ax,bx;
asm pop ds;
#endif
#ifdef BORLANDC
asm push ds;
asm mov ah,0x35;
_AL = int_number;
asm int 21h;
asm mov dx,es;
asm mov ax,bx;
asm pop ds;
#endif
}
void
ReSetIrqHandlers(int gf1_irq,int midi_irq)
{
int temp_irq;
temp_irq = gf1_irq;
if (temp_irq != 0)
{
if (gf1_irq > 7)
gf1_irq += 0x68;
else
gf1_irq += 0x08;
gf1_setvect (gf1_irq,_gf1_data.old_gf1_vec);
}
if ((temp_irq != midi_irq) && (midi_irq != 0))
{
if (midi_irq > 7)
midi_irq += 0x68;
else
midi_irq += 0x08;
gf1_setvect (midi_irq,_gf1_data.old_midi_vec);
}
}
void
SetIrqs(int gf1_irq,int midi_irq)
{
unsigned char val;
#ifdef MEATWARE
_gf1_data.gf1_sema4 = 0;
_gf1_data.irq_pending = 0;
#endif
if (gf1_irq != 0)
{
/* unmask gf1 interrupt */
val = inp(_gf1_irq[gf1_irq].imr);
val &= _gf1_irq[gf1_irq].mask;
outp(_gf1_irq[gf1_irq].imr,val);
/* send a specific EOI in case of pending interrupt */
outp(_gf1_irq[gf1_irq].ocr,_gf1_irq[gf1_irq].spec_eoi);
}
if ((midi_irq != gf1_irq) && (midi_irq != 0))
{
/* unmask midi interrupt */
val = inp(_gf1_irq[midi_irq].imr);
val &= _gf1_irq[midi_irq].mask;
outp(_gf1_irq[midi_irq].imr,val);
/* send a specific EOI in case of pending interrupt */
outp(_gf1_irq[midi_irq].ocr,_gf1_irq[midi_irq].spec_eoi);
}
/* Un-mask IRQ 2 from first controller if using 2nd controller */
if (midi_irq > 7 || gf1_irq > 7)
{
val = inp(_gf1_irq[2].imr);
val &= _gf1_irq[2].mask;
outp(_gf1_irq[2].imr,val);
/* send a specific EOI in case of pending interrupt */
outp(_gf1_irq[2].ocr,_gf1_irq[2].spec_eoi);
}
}
void
ResetIrqs(int gf1_irq,int midi_irq)
{
unsigned char val;
/* unmask gf1 interrupt */
if ((gf1_irq != 2) && (gf1_irq != 0))
{
/* turn mask bit back on ... */
val = inp(_gf1_irq[gf1_irq].imr);
val |= ~_gf1_irq[gf1_irq].mask;
outp(_gf1_irq[gf1_irq].imr,val);
}
if ((midi_irq != 2) && (midi_irq != 0))
{
/* unmask midi interrupt */
val = inp(_gf1_irq[midi_irq].imr);
val |= ~_gf1_irq[midi_irq].mask;
outp(_gf1_irq[midi_irq].imr,val);
}
}
/* static */ void
handle_dma_tc(void)
{
DMA_ENTRY *tdma;
unsigned char val;
/* First, check to see if we need to service dram dma terminal count */
/* Note: This read also clears the pending irq ... */
ENTER_CRITICAL;
outp(_gf1_data.reg_select,DMA_CONTROL);
val = inp(_gf1_data.data_hi);
LEAVE_CRITICAL;
if (val & DMA_IRQ_PENDING)
{
tdma = &_gf1_dma[_gf1_data.dram_dma_chan-1];
if (tdma->flags & TWO_FLAG)
{
UltraDmaNext(tdma,FALSE); /* handle cross over page */
}
else
{
tdma->flags &= ~DMA_PENDING;
/* show foreground its done */
_gf1_data.flags &= ~DRAM_DMA_BUSY;
tdma->amnt_sent += tdma->cur_size; /* accumulate totals */
/* Call playback processing function.... */
_gf1_data.dram_dma_tc_func();
}
}
/* Now check recording's terminal count */
/* Note: This read also clears the pending irq ... */
ENTER_CRITICAL;
outp(_gf1_data.reg_select,SAMPLE_CONTROL);
val = inp(_gf1_data.data_hi);
LEAVE_CRITICAL;
if (val & ADC_IRQ_PENDING)
{
tdma = &_gf1_dma[_gf1_data.adc_dma_chan-1];
if (tdma->flags & TWO_FLAG)
{
UltraDmaNext(tdma,TRUE); /* handle cross over page */
}
else
{
tdma->flags &= ~DMA_PENDING;
/* show foreground its done */
_gf1_data.flags &= ~ADC_DMA_BUSY;
tdma->amnt_sent += tdma->cur_size; /* accumulate totals */
/* Call ADC processing function.... */
_gf1_data.record_dma_tc_func();
}
}
}
static void
handle_voice(void)
{
unsigned char irq_source;
unsigned int voice;
unsigned long wave_ignore;
unsigned long volume_ignore;
unsigned long voice_bit;
unsigned char temp1;
unsigned char temp2;
/* clear the ignore flags. These flags are needed because we get lots of */
/* 'double' interrupts. This will only allow one interrupt per voice */
wave_ignore = 0L;
volume_ignore = 0L;
/* The GF1 has a fifo (sort of) of all pending wave table irq's. You */
/* should stay here & service ALL pending waveform IRQ's before returning. */
while (TRUE)
{
ENTER_CRITICAL;
outp(_gf1_data.reg_select,GET_IRQV);
irq_source = inp(_gf1_data.data_hi);
LEAVE_CRITICAL;
voice = irq_source & 0x1F; /* pick off the voice # */
irq_source &= (VOICE_VOLUME_IRQ | VOICE_WAVE_IRQ);/* isolate the irq bits */
if (irq_source == (VOICE_VOLUME_IRQ | VOICE_WAVE_IRQ))/* negative logic */
{
break; /* No pending irqs left ... */
}
voice_bit = 1L << (long)voice;
/* See if any waveform irqs first */
if (!(irq_source & VOICE_WAVE_IRQ))
{
/* See if we have already serviced this voice ... */
if (!(wave_ignore & voice_bit))
{
outp(_gf1_data.voice_select,voice);
outp(_gf1_data.reg_select,GET_CONTROL);
temp1 = inp (_gf1_data.data_hi);
outp(_gf1_data.reg_select,GET_VOLUME_CONTROL);
temp2 = inp (_gf1_data.data_hi);
/* If EITHER looping is on OR ROLLOVER is on, don't stop voice */
if (!((temp1 & VC_LOOP_ENABLE) || (temp2 & VC_ROLLOVER)))
{
UltraStopVoice(voice);
wave_ignore |= voice_bit;
}
/* Call waveform processing function.... */
_gf1_data.wavetable_func(voice);
}
}
if (!(irq_source & VOICE_VOLUME_IRQ))
{
if (!(volume_ignore & voice_bit))
{
outp(_gf1_data.voice_select,voice);
outp(_gf1_data.reg_select,GET_VOLUME_CONTROL);
temp1 = inp (_gf1_data.data_hi);
/* If volume looping is enabled, don't stop it */
if (!(temp1 & VL_LOOP_ENABLE))
{
UltraStopVolume(voice);
volume_ignore |= voice_bit;
}
/* Call envelope processing function.... */
_gf1_data.volume_func(voice);
}
}
}
}
static void
gf1_handler(void)
{
unsigned char irq_source;
unsigned int midi_status;
unsigned int data;
#ifdef METAWARE
if (_gf1_data.gf1_sema4)
{
_gf1_data.irq_pending = 1;
return;
}
#endif
/* IRQ's that will be vectored here */
/* 1) DAC sampling. (PC DMA) */
/* 2) Voice Volume Envelope */
/* 3) WAVE table end */
/* 4) DMA to dram. */
/* 5) Possible MIDI */
/* Handle ALL irqs that may be pending */
while (TRUE)
{
/* First, find out who has an interrupt pending */
irq_source = inp(_gf1_data.irq_status);
if (irq_source == 0)
break; /* No more irqs ... */
if (irq_source & DMA_TC_IRQ)
{
handle_dma_tc();
}
if (irq_source & (MIDI_TX_IRQ|MIDI_RX_IRQ))
{
midi_status = (unsigned int)inp(_gf1_data.midi_control);
if (irq_source & MIDI_TX_IRQ)
{
/* Call midi transmit data processing function.... */
_gf1_data.midi_xmit_func(midi_status);
}
if (irq_source & MIDI_RX_IRQ)
{
/* reading data will clear IRQ */
data = (unsigned int)inp(_gf1_data.midi_data);
/* Call midi recieve data processing function.... */
_gf1_data.midi_recv_func(midi_status,data);
}
}
if (irq_source & GF1_TIMER1_IRQ)
{
ENTER_CRITICAL;
outp( _gf1_data.reg_select, TIMER_CONTROL );
outp( _gf1_data.data_hi, _gf1_data.timer_ctrl & ~0x04);
outp( _gf1_data.reg_select, TIMER_CONTROL );
outp( _gf1_data.data_hi, _gf1_data.timer_ctrl );
_gf1_data.timer1_func();
LEAVE_CRITICAL;
}
if (irq_source & GF1_TIMER2_IRQ)
{
ENTER_CRITICAL;
outp( _gf1_data.reg_select, TIMER_CONTROL );
outp( _gf1_data.data_hi, _gf1_data.timer_ctrl & ~0x08);
outp( _gf1_data.reg_select, TIMER_CONTROL );
outp( _gf1_data.data_hi, _gf1_data.timer_ctrl );
_gf1_data.timer2_func();
LEAVE_CRITICAL;
}
if (irq_source & (WAVETABLE_IRQ | ENVELOPE_IRQ))
{
handle_voice();
}
}
_gf1_data.aux_irq_func(); /* aux interrupt handler (ultramax) */
}
#ifdef METAWARE
static _Far _INTERRPT void
#else
static void interrupt
#endif
gf1_irq_handler(void)
{
int irq_num;
#ifdef METAWARE
GetSegRegs();
#endif
irq_num = _gf1_data.gf1_irq_num;
/* clear PC's interrupt controller(s) */
outp(_gf1_irq[irq_num].ocr,_gf1_irq[irq_num].spec_eoi);
/* gotta send EOI to BOTH controllers */
if (irq_num > 7)
outp(OCR1,EOI);
gf1_handler(); /* Go to handler */
}
#ifdef METAWARE
static _Far _INTERRPT void
#else
static void interrupt
#endif
midi_irq_handler(void)
{
int irq_num;
irq_num = _gf1_data.midi_irq_num;
/* clear PC's interrupt controller(s) */
outp(_gf1_irq[irq_num].ocr,_gf1_irq[irq_num].spec_eoi);
/* gotta send EOI to BOTH controllers */
if (irq_num > 7)
outp(OCR1,EOI);
gf1_handler(); /* Go to handler (same for now ...) */
}
/* This is the function that gets executed if no other handler is defined */
void
default_func(void)
{
}
void
SetIrqHandlers(int gf1_irq,int midi_irq)
{
int temp_irq;
temp_irq = gf1_irq;
if (temp_irq != 0)
{
if (gf1_irq > 7)
gf1_irq += 0x68;
else
gf1_irq += 0x08;
_gf1_data.old_gf1_vec = gf1_getvect (gf1_irq);
gf1_setvect (gf1_irq,gf1_irq_handler);
}
if ((midi_irq != 0) && (midi_irq != temp_irq))
{
if (midi_irq > 7)
midi_irq += 0x68;
else
midi_irq += 0x08;
_gf1_data.old_midi_vec = gf1_getvect (midi_irq);
gf1_setvect (midi_irq,midi_irq_handler);
}
}
#ifdef METAWARE
void
leave_critical()
{
_gf1_data.gf1_sema4--;
if (_gf1_data.gf1_sema4 == 0)
{
if (_gf1_data.irq_pending)
{
_gf1_data.irq_pending = 0;
gf1_handler();
}
}
}
#endif