]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/pci/emu10k1/irq.c
[ALSA] Remove sound/driver.h
[linux-2.6-omap-h63xx.git] / sound / pci / emu10k1 / irq.c
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3  *                   Creative Labs, Inc.
4  *  Routines for IRQ control of EMU10K1 chips
5  *
6  *  BUGS:
7  *    --
8  *
9  *  TODO:
10  *    --
11  *
12  *   This program is free software; you can redistribute it and/or modify
13  *   it under the terms of the GNU General Public License as published by
14  *   the Free Software Foundation; either version 2 of the License, or
15  *   (at your option) any later version.
16  *
17  *   This program is distributed in the hope that it will be useful,
18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *   GNU General Public License for more details.
21  *
22  *   You should have received a copy of the GNU General Public License
23  *   along with this program; if not, write to the Free Software
24  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
25  *
26  */
27
28 #include <linux/time.h>
29 #include <sound/core.h>
30 #include <sound/emu10k1.h>
31
32 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
33 {
34         struct snd_emu10k1 *emu = dev_id;
35         unsigned int status, status2, orig_status, orig_status2;
36         int handled = 0;
37
38         while ((status = inl(emu->port + IPR)) != 0) {
39                 //snd_printk(KERN_INFO "emu10k1 irq - status = 0x%x\n", status);
40                 orig_status = status;
41                 handled = 1;
42                 if ((status & 0xffffffff) == 0xffffffff) {
43                         snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n");
44                         break;
45                 }
46                 if (status & IPR_PCIERROR) {
47                         snd_printk(KERN_ERR "interrupt: PCI error\n");
48                         snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
49                         status &= ~IPR_PCIERROR;
50                 }
51                 if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
52                         if (emu->hwvol_interrupt)
53                                 emu->hwvol_interrupt(emu, status);
54                         else
55                                 snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
56                         status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
57                 }
58                 if (status & IPR_CHANNELLOOP) {
59                         int voice;
60                         int voice_max = status & IPR_CHANNELNUMBERMASK;
61                         u32 val;
62                         struct snd_emu10k1_voice *pvoice = emu->voices;
63
64                         val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
65                         for (voice = 0; voice <= voice_max; voice++) {
66                                 if (voice == 0x20)
67                                         val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
68                                 if (val & 1) {
69                                         if (pvoice->use && pvoice->interrupt != NULL) {
70                                                 pvoice->interrupt(emu, pvoice);
71                                                 snd_emu10k1_voice_intr_ack(emu, voice);
72                                         } else {
73                                                 snd_emu10k1_voice_intr_disable(emu, voice);
74                                         }
75                                 }
76                                 val >>= 1;
77                                 pvoice++;
78                         }
79                         val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
80                         for (voice = 0; voice <= voice_max; voice++) {
81                                 if (voice == 0x20)
82                                         val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
83                                 if (val & 1) {
84                                         if (pvoice->use && pvoice->interrupt != NULL) {
85                                                 pvoice->interrupt(emu, pvoice);
86                                                 snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
87                                         } else {
88                                                 snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
89                                         }
90                                 }
91                                 val >>= 1;
92                                 pvoice++;
93                         }
94                         status &= ~IPR_CHANNELLOOP;
95                 }
96                 status &= ~IPR_CHANNELNUMBERMASK;
97                 if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
98                         if (emu->capture_interrupt)
99                                 emu->capture_interrupt(emu, status);
100                         else
101                                 snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
102                         status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
103                 }
104                 if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
105                         if (emu->capture_mic_interrupt)
106                                 emu->capture_mic_interrupt(emu, status);
107                         else
108                                 snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
109                         status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
110                 }
111                 if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
112                         if (emu->capture_efx_interrupt)
113                                 emu->capture_efx_interrupt(emu, status);
114                         else
115                                 snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
116                         status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
117                 }
118                 if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
119                         if (emu->midi.interrupt)
120                                 emu->midi.interrupt(emu, status);
121                         else
122                                 snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
123                         status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
124                 }
125                 if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
126                         if (emu->midi2.interrupt)
127                                 emu->midi2.interrupt(emu, status);
128                         else
129                                 snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
130                         status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
131                 }
132                 if (status & IPR_INTERVALTIMER) {
133                         if (emu->timer)
134                                 snd_timer_interrupt(emu->timer, emu->timer->sticks);
135                         else
136                                 snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
137                         status &= ~IPR_INTERVALTIMER;
138                 }
139                 if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
140                         if (emu->spdif_interrupt)
141                                 emu->spdif_interrupt(emu, status);
142                         else
143                                 snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
144                         status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
145                 }
146                 if (status & IPR_FXDSP) {
147                         if (emu->dsp_interrupt)
148                                 emu->dsp_interrupt(emu);
149                         else
150                                 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
151                         status &= ~IPR_FXDSP;
152                 }
153                 if (status & IPR_P16V) {
154                         while ((status2 = inl(emu->port + IPR2)) != 0) {
155                                 u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
156                                 struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
157                                 struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
158
159                                 //printk(KERN_INFO "status2=0x%x\n", status2);
160                                 orig_status2 = status2;
161                                 if(status2 & mask) {
162                                         if(pvoice->use) {
163                                                 snd_pcm_period_elapsed(pvoice->epcm->substream);
164                                         } else { 
165                                                 snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
166                                         }
167                                 }
168                                 if(status2 & 0x110000) {
169                                         //printk(KERN_INFO "capture int found\n");
170                                         if(cvoice->use) {
171                                                 //printk(KERN_INFO "capture period_elapsed\n");
172                                                 snd_pcm_period_elapsed(cvoice->epcm->substream);
173                                         }
174                                 }
175                                 outl(orig_status2, emu->port + IPR2); /* ack all */
176                         }
177                         status &= ~IPR_P16V;
178                 }
179
180                 if (status) {
181                         unsigned int bits;
182                         snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
183                         //make sure any interrupts we don't handle are disabled:
184                         bits = INTE_FXDSPENABLE |
185                                 INTE_PCIERRORENABLE |
186                                 INTE_VOLINCRENABLE |
187                                 INTE_VOLDECRENABLE |
188                                 INTE_MUTEENABLE |
189                                 INTE_MICBUFENABLE |
190                                 INTE_ADCBUFENABLE |
191                                 INTE_EFXBUFENABLE |
192                                 INTE_GPSPDIFENABLE |
193                                 INTE_CDSPDIFENABLE |
194                                 INTE_INTERVALTIMERENB |
195                                 INTE_MIDITXENABLE |
196                                 INTE_MIDIRXENABLE;
197                         if (emu->audigy)
198                                 bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
199                         snd_emu10k1_intr_disable(emu, bits);
200                 }
201                 outl(orig_status, emu->port + IPR); /* ack all */
202         }
203         return IRQ_RETVAL(handled);
204 }