linux/sound/isa/gus/gus_irq.c
<<
>>
Prefs
   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
 132