File Index
Files and directories
Sign in
FILE

irq.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/emu10k1/irq.c C
  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
  8#include <linux/time.h>
  9#include <sound/core.h>
 10#include <sound/emu10k1.h>
 11
 12irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
 13{
 14	struct snd_emu10k1 *emu = dev_id;
 15	unsigned int status, orig_status;
 16	int handled = 0;
 17	int timeout = 0;
 18
 19	while ((status = inl(emu->port + IPR)) != 0) {
 20		handled = 1;
 21		if ((status & 0xffffffff) == 0xffffffff) {
 22			dev_info(emu->card->dev,
 23				 "Suspected sound card removal\n");
 24			break;
 25		}
 26		if (++timeout == 1000) {
 27			dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
 28			break;
 29		}
 30		orig_status = status;
 31		if (status & IPR_PCIERROR) {
 32			dev_err(emu->card->dev, "interrupt: PCI error\n");
 33			snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
 34			status &= ~IPR_PCIERROR;
 35		}
 36		if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
 37			if (emu->hwvol_interrupt)
 38				emu->hwvol_interrupt(emu, status);
 39			else
 40				snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
 41			status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
 42		}
 43		if (status & IPR_CHANNELLOOP) {
 44			struct snd_emu10k1_voice *pvoice;
 45			int voice;
 46			int voice_max = status & IPR_CHANNELNUMBERMASK;
 47			u32 val;
 48
 49			val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
 50			pvoice = emu->voices;
 51			for (voice = 0; voice <= voice_max; voice++) {
 52				if (voice == 0x20)
 53					val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
 54				if (val & 1) {
 55					if (pvoice->use && pvoice->interrupt != NULL) {
 56						pvoice->interrupt(emu, pvoice);
 57						snd_emu10k1_voice_intr_ack(emu, voice);
 58					} else {
 59						snd_emu10k1_voice_intr_disable(emu, voice);
 60					}
 61				}
 62				val >>= 1;
 63				pvoice++;
 64			}
 65			val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
 66			pvoice = emu->voices;
 67			for (voice = 0; voice <= voice_max; voice++) {
 68				if (voice == 0x20)
 69					val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
 70				if (val & 1) {
 71					if (pvoice->use && pvoice->interrupt != NULL) {
 72						pvoice->interrupt(emu, pvoice);
 73						snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
 74					} else {
 75						snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
 76					}
 77				}
 78				val >>= 1;
 79				pvoice++;
 80			}
 81			status &= ~(IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK);
 82		}
 83		if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
 84			if (emu->capture_interrupt)
 85				emu->capture_interrupt(emu, status);
 86			else
 87				snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
 88			status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
 89		}
 90		if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
 91			if (emu->capture_mic_interrupt)
 92				emu->capture_mic_interrupt(emu, status);
 93			else
 94				snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
 95			status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
 96		}
 97		if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
 98			if (emu->capture_efx_interrupt)
 99				emu->capture_efx_interrupt(emu, status);
100			else
101				snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
102			status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
103		}
104		if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
105			if (emu->midi.interrupt)
106				emu->midi.interrupt(emu, status);
107			else
108				snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
109			status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
110		}
111		if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
112			if (emu->midi2.interrupt)
113				emu->midi2.interrupt(emu, status);
114			else
115				snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
116			status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
117		}
118		if (status & IPR_INTERVALTIMER) {
119			if (emu->timer)
120				snd_timer_interrupt(emu->timer, emu->timer->sticks);
121			else
122				snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
123			status &= ~IPR_INTERVALTIMER;
124		}
125		if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
126			if (emu->spdif_interrupt)
127				emu->spdif_interrupt(emu, status);
128			else
129				snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
130			status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
131		}
132		if (status & IPR_FXDSP) {
133			if (emu->dsp_interrupt)
134				emu->dsp_interrupt(emu);
135			else
136				snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
137			status &= ~IPR_FXDSP;
138		}
139		if (status & IPR_P16V) {
140			if (emu->p16v_interrupt)
141				emu->p16v_interrupt(emu);
142			else
143				outl(0, emu->port + INTE2);
144			status &= ~IPR_P16V;
145		}
146		if (status & IPR_A_GPIO) {
147			if (emu->gpio_interrupt)
148				emu->gpio_interrupt(emu);
149			else
150				snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE);
151			status &= ~IPR_A_GPIO;
152		}
153
154		if (status) {
155			dev_err(emu->card->dev,
156				"unhandled interrupt: 0x%08x\n", status);
157		}
158		outl(orig_status, emu->port + IPR); /* ack all */
159	}
160
161	return IRQ_RETVAL(handled);
162}
~/ Read-only file preview.