brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 71aa90b Raw
163 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 *                   Creative Labs, Inc.5 *  Routines for IRQ control of EMU10K1 chips6 */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			else40				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			else87				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			else94				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			else101				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			else108				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			else115				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			else122				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			else129				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			else136				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			else143				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			else150				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}163