File Index
Files and directories
Sign in
FILE

gus_irq.c

File preview with syntax highlighting.

linux-6.19.14/sound/isa/gus/gus_irq.c C
  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	if (status & 0x02) {
 30		STAT_ADD(gus->gf1.interrupt_stat_midi_in);
 31		if (gus->gf1.interrupt_handler_midi_in)
 32			gus->gf1.interrupt_handler_midi_in(gus);
 33	}
 34	if (status & 0x01) {
 35		STAT_ADD(gus->gf1.interrupt_stat_midi_out);
 36		if (gus->gf1.interrupt_handler_midi_out)
 37			gus->gf1.interrupt_handler_midi_out(gus);
 38	}
 39	if (status & (0x20 | 0x40)) {
 40		unsigned int already, _current_;
 41		unsigned char voice_status, voice;
 42		struct snd_gus_voice *pvoice;
 43
 44		already = 0;
 45		while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) {
 46			voice = voice_status & 0x1f;
 47			_current_ = 1 << voice;
 48			if (already & _current_)
 49				continue;	/* multi request */
 50			already |= _current_;	/* mark request */
 51#if 0
 52			dev_dbg(gus->card->dev,
 53				"voice = %i, voice_status = 0x%x, voice_verify = %i\n",
 54				voice, voice_status, inb(GUSP(gus, GF1PAGE)));
 55#endif
 56			pvoice = &gus->gf1.voices[voice]; 
 57			if (pvoice->use) {
 58				if (!(voice_status & 0x80)) {	/* voice position IRQ */
 59					STAT_ADD(pvoice->interrupt_stat_wave);
 60					pvoice->handler_wave(gus, pvoice);
 61				}
 62				if (!(voice_status & 0x40)) {	/* volume ramp IRQ */
 63					STAT_ADD(pvoice->interrupt_stat_volume);
 64					pvoice->handler_volume(gus, pvoice);
 65				}
 66			} else {
 67				STAT_ADD(gus->gf1.interrupt_stat_voice_lost);
 68				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
 69				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
 70			}
 71		}
 72	}
 73	if (status & 0x04) {
 74		STAT_ADD(gus->gf1.interrupt_stat_timer1);
 75		if (gus->gf1.interrupt_handler_timer1)
 76			gus->gf1.interrupt_handler_timer1(gus);
 77	}
 78	if (status & 0x08) {
 79		STAT_ADD(gus->gf1.interrupt_stat_timer2);
 80		if (gus->gf1.interrupt_handler_timer2)
 81			gus->gf1.interrupt_handler_timer2(gus);
 82	}
 83	if (status & 0x80) {
 84		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
 85			STAT_ADD(gus->gf1.interrupt_stat_dma_write);
 86			if (gus->gf1.interrupt_handler_dma_write)
 87				gus->gf1.interrupt_handler_dma_write(gus);
 88		}
 89		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
 90			STAT_ADD(gus->gf1.interrupt_stat_dma_read);
 91			if (gus->gf1.interrupt_handler_dma_read)
 92				gus->gf1.interrupt_handler_dma_read(gus);
 93		}
 94	}
 95	if (--loop > 0)
 96		goto __again;
 97	return IRQ_NONE;
 98}
 99
100#ifdef CONFIG_SND_DEBUG
101static void snd_gus_irq_info_read(struct snd_info_entry *entry, 
102				  struct snd_info_buffer *buffer)
103{
104	struct snd_gus_card *gus;
105	struct snd_gus_voice *pvoice;
106	int idx;
107
108	gus = entry->private_data;
109	snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out);
110	snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in);
111	snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1);
112	snd_iprintf(buffer, "timer2 = %u\n", gus->gf1.interrupt_stat_timer2);
113	snd_iprintf(buffer, "dma write = %u\n", gus->gf1.interrupt_stat_dma_write);
114	snd_iprintf(buffer, "dma read = %u\n", gus->gf1.interrupt_stat_dma_read);
115	snd_iprintf(buffer, "voice lost = %u\n", gus->gf1.interrupt_stat_voice_lost);
116	for (idx = 0; idx < 32; idx++) {
117		pvoice = &gus->gf1.voices[idx];
118		snd_iprintf(buffer, "voice %i: wave = %u, volume = %u\n",
119					idx,
120					pvoice->interrupt_stat_wave,
121					pvoice->interrupt_stat_volume);
122	}
123}
124
125void snd_gus_irq_profile_init(struct snd_gus_card *gus)
126{
127	snd_card_ro_proc_new(gus->card, "gusirq", gus, snd_gus_irq_info_read);
128}
129
130#endif
~/ Read-only file preview.