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