static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status) { unsigned char byte; if (midi->rmidi == NULL) { snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable); return; } spin_lock(&midi->input_lock); if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { mpu401_clear_rx(emu, midi); } else { byte = mpu401_read_data(emu, midi); if (midi->substream_input) snd_rawmidi_receive(midi->substream_input, &byte, 1); } } spin_unlock(&midi->input_lock); spin_lock(&midi->output_lock); if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { if (midi->substream_output && snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { mpu401_write_data(emu, midi, byte); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); } } spin_unlock(&midi->output_lock); }
static void snd_emu10k1_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) { emu10k1_t *emu; emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return); if (up) { int max = 4; unsigned char byte; /* try to send some amount of bytes here before interrupts */ spin_lock_irqsave(&midi->output_lock, flags); while (max > 0) { if (mpu401_output_ready(emu, midi)) { if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || snd_rawmidi_transmit(substream, &byte, 1) != 1) { /* no more data */ spin_unlock_irqrestore(&midi->output_lock, flags); return; } mpu401_write_data(emu, midi, byte); max--; } else { break; } } spin_unlock_irqrestore(&midi->output_lock, flags); snd_emu10k1_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); } }
static int snd_emu10k1_timer_stop(struct snd_timer *timer) { struct snd_emu10k1 *emu; unsigned long flags; emu = snd_timer_chip(timer); spin_lock_irqsave(&emu->reg_lock, flags); snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; }
static void snd_emu10k1_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) { emu10k1_t *emu; emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; emu = midi->emu; snd_assert(emu, return); if (up) snd_emu10k1_intr_enable(emu, midi->rx_enable); else snd_emu10k1_intr_disable(emu, midi->rx_enable); }
static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; emu = midi->emu; if (snd_BUG_ON(!emu)) return; if (up) snd_emu10k1_intr_enable(emu, midi->rx_enable); else snd_emu10k1_intr_disable(emu, midi->rx_enable); }
static int snd_emu10k1_midi_output_close(snd_rawmidi_substream_t * substream) { emu10k1_t *emu; emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return -ENXIO); spin_lock_irqsave(&midi->open_lock, flags); snd_emu10k1_intr_disable(emu, midi->tx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return 0; }
static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; unsigned long flags; int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; spin_lock_irqsave(&midi->open_lock, flags); snd_emu10k1_intr_disable(emu, midi->tx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return err; }
static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return; if (up) { int max = 4; unsigned char byte; /* */ spin_lock_irqsave(&midi->output_lock, flags); while (max > 0) { if (mpu401_output_ready(emu, midi)) { if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || snd_rawmidi_transmit(substream, &byte, 1) != 1) { /* */ spin_unlock_irqrestore(&midi->output_lock, flags); return; } mpu401_write_data(emu, midi, byte); max--; } else { break; } } spin_unlock_irqrestore(&midi->output_lock, flags); snd_emu10k1_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); } }
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) { struct snd_emu10k1 *emu = dev_id; unsigned int status, status2, orig_status, orig_status2; int handled = 0; int timeout = 0; while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) { timeout++; orig_status = status; handled = 1; if ((status & 0xffffffff) == 0xffffffff) { ; break; } if (status & IPR_PCIERROR) { ; snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { if (emu->hwvol_interrupt) emu->hwvol_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { int voice; int voice_max = status & IPR_CHANNELNUMBERMASK; u32 val; struct snd_emu10k1_voice *pvoice = emu->voices; val = snd_emu10k1_ptr_read(emu, CLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, CLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_intr_ack(emu, voice); } else { snd_emu10k1_voice_intr_disable(emu, voice); } } val >>= 1; pvoice++; } val = snd_emu10k1_ptr_read(emu, HLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, HLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_half_loop_intr_ack(emu, voice); } else { snd_emu10k1_voice_half_loop_intr_disable(emu, voice); } } val >>= 1; pvoice++; } status &= ~IPR_CHANNELLOOP; } status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); } if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { if (emu->capture_mic_interrupt) emu->capture_mic_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); } if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { if (emu->capture_efx_interrupt) emu->capture_efx_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); } if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (emu->midi.interrupt) emu->midi.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); } if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { if (emu->midi2.interrupt) emu->midi2.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); } if (status & IPR_INTERVALTIMER) { if (emu->timer) snd_timer_interrupt(emu->timer, emu->timer->sticks); else snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); status &= ~IPR_INTERVALTIMER; } if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { if (emu->spdif_interrupt) emu->spdif_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); } if (status & IPR_FXDSP) { if (emu->dsp_interrupt) emu->dsp_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } if (status & IPR_P16V) { while ((status2 = inl(emu->port + IPR2)) != 0) { u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]); struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice); ; orig_status2 = status2; if(status2 & mask) { if(pvoice->use) { snd_pcm_period_elapsed(pvoice->epcm->substream); } else { ; } } if(status2 & 0x110000) { ; if(cvoice->use) { ; snd_pcm_period_elapsed(cvoice->epcm->substream); } } outl(orig_status2, emu->port + IPR2); /* ack all */ } status &= ~IPR_P16V; } if (status) { unsigned int bits; ; //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_MICBUFENABLE | INTE_ADCBUFENABLE | INTE_EFXBUFENABLE | INTE_GPSPDIFENABLE | INTE_CDSPDIFENABLE | INTE_INTERVALTIMERENB | INTE_MIDITXENABLE | INTE_MIDIRXENABLE; if (emu->audigy) bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; snd_emu10k1_intr_disable(emu, bits); } outl(orig_status, emu->port + IPR); /* ack all */ }
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { emu10k1_t *emu = dev_id; unsigned int status, status2, orig_status, orig_status2; int handled = 0; while ((status = inl(emu->port + IPR)) != 0) { // printk("irq - status = 0x%x\n", status); orig_status = status; handled = 1; if (status & IPR_PCIERROR) { snd_printk("interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { if (emu->hwvol_interrupt) emu->hwvol_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { int voice; int voice_max = status & IPR_CHANNELNUMBERMASK; u32 val; emu10k1_voice_t *pvoice = emu->voices; val = snd_emu10k1_ptr_read(emu, CLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, CLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_intr_ack(emu, voice); } else { snd_emu10k1_voice_intr_disable(emu, voice); } } val >>= 1; pvoice++; } val = snd_emu10k1_ptr_read(emu, HLIPL, 0); for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, HLIPH, 0); if (val & 1) { if (pvoice->use && pvoice->interrupt != NULL) { pvoice->interrupt(emu, pvoice); snd_emu10k1_voice_half_loop_intr_ack(emu, voice); } else { snd_emu10k1_voice_half_loop_intr_disable(emu, voice); } } val >>= 1; pvoice++; } status &= ~IPR_CHANNELLOOP; } status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); } if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { if (emu->capture_mic_interrupt) emu->capture_mic_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); } if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { if (emu->capture_efx_interrupt) emu->capture_efx_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); } if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (emu->midi.interrupt) emu->midi.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); } if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { if (emu->midi2.interrupt) emu->midi2.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); } if (status & IPR_INTERVALTIMER) { if (emu->timer) snd_timer_interrupt(emu->timer, emu->timer->sticks); else snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); status &= ~IPR_INTERVALTIMER; } if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { if (emu->spdif_interrupt) emu->spdif_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); } if (status & IPR_FXDSP) { if (emu->dsp_interrupt) emu->dsp_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } if (status) { unsigned int bits; //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_MICBUFENABLE | INTE_ADCBUFENABLE | INTE_EFXBUFENABLE | INTE_GPSPDIFENABLE | INTE_CDSPDIFENABLE | INTE_INTERVALTIMERENB | INTE_MIDITXENABLE | INTE_MIDIRXENABLE; if (emu->audigy) bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; snd_emu10k1_intr_disable(emu, bits); } outl(orig_status, emu->port + IPR); /* ack all */ }