Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Routine for IRQ handling from GF1/InterWave chip
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <sound/core.h>
0008 #include <sound/info.h>
0009 #include <sound/gus.h>
0010 
0011 #ifdef CONFIG_SND_DEBUG
0012 #define STAT_ADD(x) ((x)++)
0013 #else
0014 #define STAT_ADD(x) while (0) { ; }
0015 #endif
0016 
0017 irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
0018 {
0019     struct snd_gus_card * gus = dev_id;
0020     unsigned char status;
0021     int loop = 100;
0022     int handled = 0;
0023 
0024 __again:
0025     status = inb(gus->gf1.reg_irqstat);
0026     if (status == 0)
0027         return IRQ_RETVAL(handled);
0028     handled = 1;
0029     /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
0030     if (status & 0x02) {
0031         STAT_ADD(gus->gf1.interrupt_stat_midi_in);
0032         if (gus->gf1.interrupt_handler_midi_in)
0033             gus->gf1.interrupt_handler_midi_in(gus);
0034     }
0035     if (status & 0x01) {
0036         STAT_ADD(gus->gf1.interrupt_stat_midi_out);
0037         if (gus->gf1.interrupt_handler_midi_out)
0038             gus->gf1.interrupt_handler_midi_out(gus);
0039     }
0040     if (status & (0x20 | 0x40)) {
0041         unsigned int already, _current_;
0042         unsigned char voice_status, voice;
0043         struct snd_gus_voice *pvoice;
0044 
0045         already = 0;
0046         while (((voice_status = snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ)) & 0xc0) != 0xc0) {
0047             voice = voice_status & 0x1f;
0048             _current_ = 1 << voice;
0049             if (already & _current_)
0050                 continue;   /* multi request */
0051             already |= _current_;   /* mark request */
0052 #if 0
0053             printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
0054                    "voice_verify = %i\n",
0055                    voice, voice_status, inb(GUSP(gus, GF1PAGE)));
0056 #endif
0057             pvoice = &gus->gf1.voices[voice]; 
0058             if (pvoice->use) {
0059                 if (!(voice_status & 0x80)) {   /* voice position IRQ */
0060                     STAT_ADD(pvoice->interrupt_stat_wave);
0061                     pvoice->handler_wave(gus, pvoice);
0062                 }
0063                 if (!(voice_status & 0x40)) {   /* volume ramp IRQ */
0064                     STAT_ADD(pvoice->interrupt_stat_volume);
0065                     pvoice->handler_volume(gus, pvoice);
0066                 }
0067             } else {
0068                 STAT_ADD(gus->gf1.interrupt_stat_voice_lost);
0069                 snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
0070                 snd_gf1_i_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
0071             }
0072         }
0073     }
0074     if (status & 0x04) {
0075         STAT_ADD(gus->gf1.interrupt_stat_timer1);
0076         if (gus->gf1.interrupt_handler_timer1)
0077             gus->gf1.interrupt_handler_timer1(gus);
0078     }
0079     if (status & 0x08) {
0080         STAT_ADD(gus->gf1.interrupt_stat_timer2);
0081         if (gus->gf1.interrupt_handler_timer2)
0082             gus->gf1.interrupt_handler_timer2(gus);
0083     }
0084     if (status & 0x80) {
0085         if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) {
0086             STAT_ADD(gus->gf1.interrupt_stat_dma_write);
0087             if (gus->gf1.interrupt_handler_dma_write)
0088                 gus->gf1.interrupt_handler_dma_write(gus);
0089         }
0090         if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) {
0091             STAT_ADD(gus->gf1.interrupt_stat_dma_read);
0092             if (gus->gf1.interrupt_handler_dma_read)
0093                 gus->gf1.interrupt_handler_dma_read(gus);
0094         }
0095     }
0096     if (--loop > 0)
0097         goto __again;
0098     return IRQ_NONE;
0099 }
0100 
0101 #ifdef CONFIG_SND_DEBUG
0102 static void snd_gus_irq_info_read(struct snd_info_entry *entry, 
0103                   struct snd_info_buffer *buffer)
0104 {
0105     struct snd_gus_card *gus;
0106     struct snd_gus_voice *pvoice;
0107     int idx;
0108 
0109     gus = entry->private_data;
0110     snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out);
0111     snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in);
0112     snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1);
0113     snd_iprintf(buffer, "timer2 = %u\n", gus->gf1.interrupt_stat_timer2);
0114     snd_iprintf(buffer, "dma write = %u\n", gus->gf1.interrupt_stat_dma_write);
0115     snd_iprintf(buffer, "dma read = %u\n", gus->gf1.interrupt_stat_dma_read);
0116     snd_iprintf(buffer, "voice lost = %u\n", gus->gf1.interrupt_stat_voice_lost);
0117     for (idx = 0; idx < 32; idx++) {
0118         pvoice = &gus->gf1.voices[idx];
0119         snd_iprintf(buffer, "voice %i: wave = %u, volume = %u\n",
0120                     idx,
0121                     pvoice->interrupt_stat_wave,
0122                     pvoice->interrupt_stat_volume);
0123     }
0124 }
0125 
0126 void snd_gus_irq_profile_init(struct snd_gus_card *gus)
0127 {
0128     snd_card_ro_proc_new(gus->card, "gusirq", gus, snd_gus_irq_info_read);
0129 }
0130 
0131 #endif