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