Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *                   Creative Labs, Inc.
0005  *  Routines for IRQ control of EMU10K1 chips
0006  *
0007  *  BUGS:
0008  *    --
0009  *
0010  *  TODO:
0011  *    --
0012  */
0013 
0014 #include <linux/time.h>
0015 #include <sound/core.h>
0016 #include <sound/emu10k1.h>
0017 
0018 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
0019 {
0020     struct snd_emu10k1 *emu = dev_id;
0021     unsigned int status, status2, orig_status, orig_status2;
0022     int handled = 0;
0023     int timeout = 0;
0024 
0025     while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
0026         timeout++;
0027         orig_status = status;
0028         handled = 1;
0029         if ((status & 0xffffffff) == 0xffffffff) {
0030             dev_info(emu->card->dev,
0031                  "Suspected sound card removal\n");
0032             break;
0033         }
0034         if (status & IPR_PCIERROR) {
0035             dev_err(emu->card->dev, "interrupt: PCI error\n");
0036             snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
0037             status &= ~IPR_PCIERROR;
0038         }
0039         if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
0040             if (emu->hwvol_interrupt)
0041                 emu->hwvol_interrupt(emu, status);
0042             else
0043                 snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
0044             status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
0045         }
0046         if (status & IPR_CHANNELLOOP) {
0047             int voice;
0048             int voice_max = status & IPR_CHANNELNUMBERMASK;
0049             u32 val;
0050             struct snd_emu10k1_voice *pvoice = emu->voices;
0051 
0052             val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
0053             for (voice = 0; voice <= voice_max; voice++) {
0054                 if (voice == 0x20)
0055                     val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
0056                 if (val & 1) {
0057                     if (pvoice->use && pvoice->interrupt != NULL) {
0058                         pvoice->interrupt(emu, pvoice);
0059                         snd_emu10k1_voice_intr_ack(emu, voice);
0060                     } else {
0061                         snd_emu10k1_voice_intr_disable(emu, voice);
0062                     }
0063                 }
0064                 val >>= 1;
0065                 pvoice++;
0066             }
0067             val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
0068             for (voice = 0; voice <= voice_max; voice++) {
0069                 if (voice == 0x20)
0070                     val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
0071                 if (val & 1) {
0072                     if (pvoice->use && pvoice->interrupt != NULL) {
0073                         pvoice->interrupt(emu, pvoice);
0074                         snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
0075                     } else {
0076                         snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
0077                     }
0078                 }
0079                 val >>= 1;
0080                 pvoice++;
0081             }
0082             status &= ~IPR_CHANNELLOOP;
0083         }
0084         status &= ~IPR_CHANNELNUMBERMASK;
0085         if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
0086             if (emu->capture_interrupt)
0087                 emu->capture_interrupt(emu, status);
0088             else
0089                 snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
0090             status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
0091         }
0092         if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
0093             if (emu->capture_mic_interrupt)
0094                 emu->capture_mic_interrupt(emu, status);
0095             else
0096                 snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
0097             status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
0098         }
0099         if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
0100             if (emu->capture_efx_interrupt)
0101                 emu->capture_efx_interrupt(emu, status);
0102             else
0103                 snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
0104             status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
0105         }
0106         if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
0107             if (emu->midi.interrupt)
0108                 emu->midi.interrupt(emu, status);
0109             else
0110                 snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
0111             status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
0112         }
0113         if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
0114             if (emu->midi2.interrupt)
0115                 emu->midi2.interrupt(emu, status);
0116             else
0117                 snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
0118             status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
0119         }
0120         if (status & IPR_INTERVALTIMER) {
0121             if (emu->timer)
0122                 snd_timer_interrupt(emu->timer, emu->timer->sticks);
0123             else
0124                 snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
0125             status &= ~IPR_INTERVALTIMER;
0126         }
0127         if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
0128             if (emu->spdif_interrupt)
0129                 emu->spdif_interrupt(emu, status);
0130             else
0131                 snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
0132             status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
0133         }
0134         if (status & IPR_FXDSP) {
0135             if (emu->dsp_interrupt)
0136                 emu->dsp_interrupt(emu);
0137             else
0138                 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
0139             status &= ~IPR_FXDSP;
0140         }
0141         if (status & IPR_P16V) {
0142             while ((status2 = inl(emu->port + IPR2)) != 0) {
0143                 u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
0144                 struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
0145                 struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
0146 
0147                 /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */
0148                 orig_status2 = status2;
0149                 if(status2 & mask) {
0150                     if(pvoice->use) {
0151                         snd_pcm_period_elapsed(pvoice->epcm->substream);
0152                     } else { 
0153                         dev_err(emu->card->dev,
0154                             "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n",
0155                             status2, mask, pvoice,
0156                             pvoice->use);
0157                     }
0158                 }
0159                 if(status2 & 0x110000) {
0160                     /* dev_info(emu->card->dev, "capture int found\n"); */
0161                     if(cvoice->use) {
0162                         /* dev_info(emu->card->dev, "capture period_elapsed\n"); */
0163                         snd_pcm_period_elapsed(cvoice->epcm->substream);
0164                     }
0165                 }
0166                 outl(orig_status2, emu->port + IPR2); /* ack all */
0167             }
0168             status &= ~IPR_P16V;
0169         }
0170 
0171         if (status) {
0172             unsigned int bits;
0173             dev_err(emu->card->dev,
0174                 "unhandled interrupt: 0x%08x\n", status);
0175             //make sure any interrupts we don't handle are disabled:
0176             bits = INTE_FXDSPENABLE |
0177                 INTE_PCIERRORENABLE |
0178                 INTE_VOLINCRENABLE |
0179                 INTE_VOLDECRENABLE |
0180                 INTE_MUTEENABLE |
0181                 INTE_MICBUFENABLE |
0182                 INTE_ADCBUFENABLE |
0183                 INTE_EFXBUFENABLE |
0184                 INTE_GPSPDIFENABLE |
0185                 INTE_CDSPDIFENABLE |
0186                 INTE_INTERVALTIMERENB |
0187                 INTE_MIDITXENABLE |
0188                 INTE_MIDIRXENABLE;
0189             if (emu->audigy)
0190                 bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
0191             snd_emu10k1_intr_disable(emu, bits);
0192         }
0193         outl(orig_status, emu->port + IPR); /* ack all */
0194     }
0195     if (timeout == 1000)
0196         dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
0197 
0198     return IRQ_RETVAL(handled);
0199 }