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

gus_irq.c (3997B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Routine for IRQ handling from GF1/InterWave chip
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7#include <sound/core.h>
      8#include <sound/info.h>
      9#include <sound/gus.h>
     10
     11#ifdef CONFIG_SND_DEBUG
     12#define STAT_ADD(x)	((x)++)
     13#else
     14#define STAT_ADD(x)	while (0) { ; }
     15#endif
     16
     17irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
     18{
     19	struct snd_gus_card * gus = dev_id;
     20	unsigned char status;
     21	int loop = 100;
     22	int handled = 0;
     23
     24__again:
     25	status = inb(gus->gf1.reg_irqstat);
     26	if (status == 0)
     27		return IRQ_RETVAL(handled);
     28	handled = 1;
     29	/* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
     30	if (status & 0x02) {
     31		STAT_ADD(gus->gf1.interrupt_stat_midi_in);
     32		if (gus->gf1.interrupt_handler_midi_in)
     33			gus->gf1.interrupt_handler_midi_in(gus);
     34	}
     35	if (status & 0x01) {
     36		STAT_ADD(gus->gf1.interrupt_stat_midi_out);
     37		if (gus->gf1.interrupt_handler_midi_out)
     38			gus->gf1.interrupt_handler_midi_out(gus);
     39	}
     40	if (status & (0x20 | 0x40)) {
     41		unsigned int already, _current_;
     42		unsigned char voice_status, voice;
     43		struct snd_gus_voice *pvoice;
     44
     45		already = 0;
     46		while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) {
     47			voice = voice_status & 0x1f;
     48			_current_ = 1 << voice;
     49			if (already & _current_)
     50				continue;	/* multi request */
     51			already |= _current_;	/* mark request */
     52#if 0
     53			printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
     54			       "voice_verify = %i\n",
     55			       voice, voice_status, inb(GUSP(gus, GF1PAGE)));
     56#endif
     57			pvoice = &gus->gf1.voices[voice]; 
     58			if (pvoice->use) {
     59				if (!(voice_status & 0x80)) {	/* voice position IRQ */
     60					STAT_ADD(pvoice->interrupt_stat_wave);
     61					pvoice->handler_wave(gus, pvoice);
     62				}
     63				if (!(voice_status & 0x40)) {	/* volume ramp IRQ */
     64					STAT_ADD(pvoice->interrupt_stat_volume);
     65					pvoice->handler_volume(gus, pvoice);
     66				}
     67			} else {
     68				STAT_ADD(gus->gf1.interrupt_stat_voice_lost);
     69				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
     70				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
     71			}
     72		}
     73	}
     74	if (status & 0x04) {
     75		STAT_ADD(gus->gf1.interrupt_stat_timer1);
     76		if (gus->gf1.interrupt_handler_timer1)
     77			gus->gf1.interrupt_handler_timer1(gus);
     78	}
     79	if (status & 0x08) {
     80		STAT_ADD(gus->gf1.interrupt_stat_timer2);
     81		if (gus->gf1.interrupt_handler_timer2)
     82			gus->gf1.interrupt_handler_timer2(gus);
     83	}
     84	if (status & 0x80) {
     85		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
     86			STAT_ADD(gus->gf1.interrupt_stat_dma_write);
     87			if (gus->gf1.interrupt_handler_dma_write)
     88				gus->gf1.interrupt_handler_dma_write(gus);
     89		}
     90		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
     91			STAT_ADD(gus->gf1.interrupt_stat_dma_read);
     92			if (gus->gf1.interrupt_handler_dma_read)
     93				gus->gf1.interrupt_handler_dma_read(gus);
     94		}
     95	}
     96	if (--loop > 0)
     97		goto __again;
     98	return IRQ_NONE;
     99}
    100
    101#ifdef CONFIG_SND_DEBUG
    102static void snd_gus_irq_info_read(struct snd_info_entry *entry, 
    103				  struct snd_info_buffer *buffer)
    104{
    105	struct snd_gus_card *gus;
    106	struct snd_gus_voice *pvoice;
    107	int idx;
    108
    109	gus = entry->private_data;
    110	snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out);
    111	snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in);
    112	snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1);
    113	snd_iprintf(buffer, "timer2 = %u\n", gus->gf1.interrupt_stat_timer2);
    114	snd_iprintf(buffer, "dma write = %u\n", gus->gf1.interrupt_stat_dma_write);
    115	snd_iprintf(buffer, "dma read = %u\n", gus->gf1.interrupt_stat_dma_read);
    116	snd_iprintf(buffer, "voice lost = %u\n", gus->gf1.interrupt_stat_voice_lost);
    117	for (idx = 0; idx < 32; idx++) {
    118		pvoice = &gus->gf1.voices[idx];
    119		snd_iprintf(buffer, "voice %i: wave = %u, volume = %u\n",
    120					idx,
    121					pvoice->interrupt_stat_wave,
    122					pvoice->interrupt_stat_volume);
    123	}
    124}
    125
    126void snd_gus_irq_profile_init(struct snd_gus_card *gus)
    127{
    128	snd_card_ro_proc_new(gus->card, "gusirq", gus, snd_gus_irq_info_read);
    129}
    130
    131#endif