xref: /openbmc/linux/sound/isa/gus/gus_irq.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  Routine for IRQ handling from GF1/InterWave chip
4c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <sound/core.h>
81da177e4SLinus Torvalds #include <sound/info.h>
91da177e4SLinus Torvalds #include <sound/gus.h>
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #ifdef CONFIG_SND_DEBUG
121da177e4SLinus Torvalds #define STAT_ADD(x)	((x)++)
131da177e4SLinus Torvalds #else
141da177e4SLinus Torvalds #define STAT_ADD(x)	while (0) { ; }
151da177e4SLinus Torvalds #endif
161da177e4SLinus Torvalds 
snd_gus_interrupt(int irq,void * dev_id)177d12e780SDavid Howells irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
181da177e4SLinus Torvalds {
195e2da206STakashi Iwai 	struct snd_gus_card * gus = dev_id;
201da177e4SLinus Torvalds 	unsigned char status;
211da177e4SLinus Torvalds 	int loop = 100;
221da177e4SLinus Torvalds 	int handled = 0;
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds __again:
251da177e4SLinus Torvalds 	status = inb(gus->gf1.reg_irqstat);
261da177e4SLinus Torvalds 	if (status == 0)
271da177e4SLinus Torvalds 		return IRQ_RETVAL(handled);
281da177e4SLinus Torvalds 	handled = 1;
2991f05060STakashi Iwai 	/* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
301da177e4SLinus Torvalds 	if (status & 0x02) {
311da177e4SLinus Torvalds 		STAT_ADD(gus->gf1.interrupt_stat_midi_in);
32c2cbdbb1SIngo Molnar 		if (gus->gf1.interrupt_handler_midi_in)
331da177e4SLinus Torvalds 			gus->gf1.interrupt_handler_midi_in(gus);
341da177e4SLinus Torvalds 	}
351da177e4SLinus Torvalds 	if (status & 0x01) {
361da177e4SLinus Torvalds 		STAT_ADD(gus->gf1.interrupt_stat_midi_out);
37c2cbdbb1SIngo Molnar 		if (gus->gf1.interrupt_handler_midi_out)
381da177e4SLinus Torvalds 			gus->gf1.interrupt_handler_midi_out(gus);
391da177e4SLinus Torvalds 	}
401da177e4SLinus Torvalds 	if (status & (0x20 | 0x40)) {
411da177e4SLinus Torvalds 		unsigned int already, _current_;
421da177e4SLinus Torvalds 		unsigned char voice_status, voice;
435e2da206STakashi Iwai 		struct snd_gus_voice *pvoice;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 		already = 0;
461da177e4SLinus Torvalds 		while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) {
471da177e4SLinus Torvalds 			voice = voice_status & 0x1f;
481da177e4SLinus Torvalds 			_current_ = 1 << voice;
491da177e4SLinus Torvalds 			if (already & _current_)
501da177e4SLinus Torvalds 				continue;	/* multi request */
511da177e4SLinus Torvalds 			already |= _current_;	/* mark request */
521da177e4SLinus Torvalds #if 0
5391f05060STakashi Iwai 			printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
5491f05060STakashi Iwai 			       "voice_verify = %i\n",
5591f05060STakashi Iwai 			       voice, voice_status, inb(GUSP(gus, GF1PAGE)));
561da177e4SLinus Torvalds #endif
571da177e4SLinus Torvalds 			pvoice = &gus->gf1.voices[voice];
581da177e4SLinus Torvalds 			if (pvoice->use) {
591da177e4SLinus Torvalds 				if (!(voice_status & 0x80)) {	/* voice position IRQ */
601da177e4SLinus Torvalds 					STAT_ADD(pvoice->interrupt_stat_wave);
611da177e4SLinus Torvalds 					pvoice->handler_wave(gus, pvoice);
621da177e4SLinus Torvalds 				}
631da177e4SLinus Torvalds 				if (!(voice_status & 0x40)) {	/* volume ramp IRQ */
641da177e4SLinus Torvalds 					STAT_ADD(pvoice->interrupt_stat_volume);
651da177e4SLinus Torvalds 					pvoice->handler_volume(gus, pvoice);
661da177e4SLinus Torvalds 				}
671da177e4SLinus Torvalds 			} else {
681da177e4SLinus Torvalds 				STAT_ADD(gus->gf1.interrupt_stat_voice_lost);
691da177e4SLinus Torvalds 				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
701da177e4SLinus Torvalds 				snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
711da177e4SLinus Torvalds 			}
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds 	}
741da177e4SLinus Torvalds 	if (status & 0x04) {
751da177e4SLinus Torvalds 		STAT_ADD(gus->gf1.interrupt_stat_timer1);
76c2cbdbb1SIngo Molnar 		if (gus->gf1.interrupt_handler_timer1)
771da177e4SLinus Torvalds 			gus->gf1.interrupt_handler_timer1(gus);
781da177e4SLinus Torvalds 	}
791da177e4SLinus Torvalds 	if (status & 0x08) {
801da177e4SLinus Torvalds 		STAT_ADD(gus->gf1.interrupt_stat_timer2);
81c2cbdbb1SIngo Molnar 		if (gus->gf1.interrupt_handler_timer2)
821da177e4SLinus Torvalds 			gus->gf1.interrupt_handler_timer2(gus);
831da177e4SLinus Torvalds 	}
841da177e4SLinus Torvalds 	if (status & 0x80) {
851da177e4SLinus Torvalds 		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
861da177e4SLinus Torvalds 			STAT_ADD(gus->gf1.interrupt_stat_dma_write);
87c2cbdbb1SIngo Molnar 			if (gus->gf1.interrupt_handler_dma_write)
881da177e4SLinus Torvalds 				gus->gf1.interrupt_handler_dma_write(gus);
891da177e4SLinus Torvalds 		}
901da177e4SLinus Torvalds 		if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
911da177e4SLinus Torvalds 			STAT_ADD(gus->gf1.interrupt_stat_dma_read);
92c2cbdbb1SIngo Molnar 			if (gus->gf1.interrupt_handler_dma_read)
931da177e4SLinus Torvalds 				gus->gf1.interrupt_handler_dma_read(gus);
941da177e4SLinus Torvalds 		}
951da177e4SLinus Torvalds 	}
961da177e4SLinus Torvalds 	if (--loop > 0)
971da177e4SLinus Torvalds 		goto __again;
981da177e4SLinus Torvalds 	return IRQ_NONE;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds #ifdef CONFIG_SND_DEBUG
snd_gus_irq_info_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1025e2da206STakashi Iwai static void snd_gus_irq_info_read(struct snd_info_entry *entry,
1035e2da206STakashi Iwai 				  struct snd_info_buffer *buffer)
1041da177e4SLinus Torvalds {
1055e2da206STakashi Iwai 	struct snd_gus_card *gus;
1065e2da206STakashi Iwai 	struct snd_gus_voice *pvoice;
1071da177e4SLinus Torvalds 	int idx;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	gus = entry->private_data;
1101da177e4SLinus Torvalds 	snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out);
1111da177e4SLinus Torvalds 	snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in);
1121da177e4SLinus Torvalds 	snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1);
1131da177e4SLinus Torvalds 	snd_iprintf(buffer, "timer2 = %u\n", gus->gf1.interrupt_stat_timer2);
1141da177e4SLinus Torvalds 	snd_iprintf(buffer, "dma write = %u\n", gus->gf1.interrupt_stat_dma_write);
1151da177e4SLinus Torvalds 	snd_iprintf(buffer, "dma read = %u\n", gus->gf1.interrupt_stat_dma_read);
1161da177e4SLinus Torvalds 	snd_iprintf(buffer, "voice lost = %u\n", gus->gf1.interrupt_stat_voice_lost);
1171da177e4SLinus Torvalds 	for (idx = 0; idx < 32; idx++) {
1181da177e4SLinus Torvalds 		pvoice = &gus->gf1.voices[idx];
1191da177e4SLinus Torvalds 		snd_iprintf(buffer, "voice %i: wave = %u, volume = %u\n",
1201da177e4SLinus Torvalds 					idx,
1211da177e4SLinus Torvalds 					pvoice->interrupt_stat_wave,
1221da177e4SLinus Torvalds 					pvoice->interrupt_stat_volume);
1231da177e4SLinus Torvalds 	}
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
snd_gus_irq_profile_init(struct snd_gus_card * gus)1265e2da206STakashi Iwai void snd_gus_irq_profile_init(struct snd_gus_card *gus)
1271da177e4SLinus Torvalds {
1281bac5e1cSTakashi Iwai 	snd_card_ro_proc_new(gus->card, "gusirq", gus, snd_gus_irq_info_read);
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds #endif
132