^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Creative Labs, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Routines for IRQ control of EMU10K1 chips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * BUGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sound/emu10k1.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct snd_emu10k1 *emu = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int status, status2, orig_status, orig_status2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) int handled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int timeout = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) timeout++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) orig_status = status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) handled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if ((status & 0xffffffff) == 0xffffffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) dev_info(emu->card->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) "Suspected sound card removal\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (status & IPR_PCIERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) dev_err(emu->card->dev, "interrupt: PCI error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) status &= ~IPR_PCIERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (emu->hwvol_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) emu->hwvol_interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (status & IPR_CHANNELLOOP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int voice;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int voice_max = status & IPR_CHANNELNUMBERMASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct snd_emu10k1_voice *pvoice = emu->voices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) for (voice = 0; voice <= voice_max; voice++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (voice == 0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (val & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (pvoice->use && pvoice->interrupt != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) pvoice->interrupt(emu, pvoice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) snd_emu10k1_voice_intr_ack(emu, voice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) snd_emu10k1_voice_intr_disable(emu, voice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) val >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) pvoice++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) for (voice = 0; voice <= voice_max; voice++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (voice == 0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (val & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (pvoice->use && pvoice->interrupt != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pvoice->interrupt(emu, pvoice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) val >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pvoice++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) status &= ~IPR_CHANNELLOOP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) status &= ~IPR_CHANNELNUMBERMASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (emu->capture_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) emu->capture_interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (emu->capture_mic_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) emu->capture_mic_interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (emu->capture_efx_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) emu->capture_efx_interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (emu->midi.interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) emu->midi.interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (emu->midi2.interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) emu->midi2.interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (status & IPR_INTERVALTIMER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (emu->timer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) snd_timer_interrupt(emu->timer, emu->timer->sticks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) status &= ~IPR_INTERVALTIMER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (emu->spdif_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) emu->spdif_interrupt(emu, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (status & IPR_FXDSP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (emu->dsp_interrupt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) emu->dsp_interrupt(emu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) status &= ~IPR_FXDSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (status & IPR_P16V) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) while ((status2 = inl(emu->port + IPR2)) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) orig_status2 = status2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if(status2 & mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if(pvoice->use) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) snd_pcm_period_elapsed(pvoice->epcm->substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dev_err(emu->card->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) status2, mask, pvoice,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) pvoice->use);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if(status2 & 0x110000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* dev_info(emu->card->dev, "capture int found\n"); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if(cvoice->use) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* dev_info(emu->card->dev, "capture period_elapsed\n"); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) snd_pcm_period_elapsed(cvoice->epcm->substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) outl(orig_status2, emu->port + IPR2); /* ack all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) status &= ~IPR_P16V;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) unsigned int bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) dev_err(emu->card->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) "unhandled interrupt: 0x%08x\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) //make sure any interrupts we don't handle are disabled:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bits = INTE_FXDSPENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) INTE_PCIERRORENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) INTE_VOLINCRENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) INTE_VOLDECRENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) INTE_MUTEENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) INTE_MICBUFENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) INTE_ADCBUFENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) INTE_EFXBUFENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) INTE_GPSPDIFENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) INTE_CDSPDIFENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) INTE_INTERVALTIMERENB |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) INTE_MIDITXENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) INTE_MIDIRXENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (emu->audigy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) snd_emu10k1_intr_disable(emu, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) outl(orig_status, emu->port + IPR); /* ack all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (timeout == 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return IRQ_RETVAL(handled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }