cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}