/*************************************************************************** * 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 #include // #include #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