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