• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/pci/emu10k1/
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
32irqreturn_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	int timeout = 0;
38
39	while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
40		timeout++;
41		orig_status = status;
42		handled = 1;
43		if ((status & 0xffffffff) == 0xffffffff) {
44			snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n");
45			break;
46		}
47		if (status & IPR_PCIERROR) {
48			snd_printk(KERN_ERR "interrupt: PCI error\n");
49			snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
50			status &= ~IPR_PCIERROR;
51		}
52		if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
53			if (emu->hwvol_interrupt)
54				emu->hwvol_interrupt(emu, status);
55			else
56				snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
57			status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
58		}
59		if (status & IPR_CHANNELLOOP) {
60			int voice;
61			int voice_max = status & IPR_CHANNELNUMBERMASK;
62			u32 val;
63			struct snd_emu10k1_voice *pvoice = emu->voices;
64
65			val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
66			for (voice = 0; voice <= voice_max; voice++) {
67				if (voice == 0x20)
68					val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
69				if (val & 1) {
70					if (pvoice->use && pvoice->interrupt != NULL) {
71						pvoice->interrupt(emu, pvoice);
72						snd_emu10k1_voice_intr_ack(emu, voice);
73					} else {
74						snd_emu10k1_voice_intr_disable(emu, voice);
75					}
76				}
77				val >>= 1;
78				pvoice++;
79			}
80			val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
81			for (voice = 0; voice <= voice_max; voice++) {
82				if (voice == 0x20)
83					val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
84				if (val & 1) {
85					if (pvoice->use && pvoice->interrupt != NULL) {
86						pvoice->interrupt(emu, pvoice);
87						snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
88					} else {
89						snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
90					}
91				}
92				val >>= 1;
93				pvoice++;
94			}
95			status &= ~IPR_CHANNELLOOP;
96		}
97		status &= ~IPR_CHANNELNUMBERMASK;
98		if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
99			if (emu->capture_interrupt)
100				emu->capture_interrupt(emu, status);
101			else
102				snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
103			status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
104		}
105		if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
106			if (emu->capture_mic_interrupt)
107				emu->capture_mic_interrupt(emu, status);
108			else
109				snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
110			status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
111		}
112		if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
113			if (emu->capture_efx_interrupt)
114				emu->capture_efx_interrupt(emu, status);
115			else
116				snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
117			status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
118		}
119		if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
120			if (emu->midi.interrupt)
121				emu->midi.interrupt(emu, status);
122			else
123				snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
124			status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
125		}
126		if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
127			if (emu->midi2.interrupt)
128				emu->midi2.interrupt(emu, status);
129			else
130				snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
131			status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
132		}
133		if (status & IPR_INTERVALTIMER) {
134			if (emu->timer)
135				snd_timer_interrupt(emu->timer, emu->timer->sticks);
136			else
137				snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
138			status &= ~IPR_INTERVALTIMER;
139		}
140		if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
141			if (emu->spdif_interrupt)
142				emu->spdif_interrupt(emu, status);
143			else
144				snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
145			status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
146		}
147		if (status & IPR_FXDSP) {
148			if (emu->dsp_interrupt)
149				emu->dsp_interrupt(emu);
150			else
151				snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
152			status &= ~IPR_FXDSP;
153		}
154		if (status & IPR_P16V) {
155			while ((status2 = inl(emu->port + IPR2)) != 0) {
156				u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
157				struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
158				struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
159
160				//printk(KERN_INFO "status2=0x%x\n", status2);
161				orig_status2 = status2;
162				if(status2 & mask) {
163					if(pvoice->use) {
164						snd_pcm_period_elapsed(pvoice->epcm->substream);
165					} else {
166						snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
167					}
168				}
169				if(status2 & 0x110000) {
170					//printk(KERN_INFO "capture int found\n");
171					if(cvoice->use) {
172						//printk(KERN_INFO "capture period_elapsed\n");
173						snd_pcm_period_elapsed(cvoice->epcm->substream);
174					}
175				}
176				outl(orig_status2, emu->port + IPR2); /* ack all */
177			}
178			status &= ~IPR_P16V;
179		}
180
181		if (status) {
182			unsigned int bits;
183			snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
184			//make sure any interrupts we don't handle are disabled:
185			bits = INTE_FXDSPENABLE |
186				INTE_PCIERRORENABLE |
187				INTE_VOLINCRENABLE |
188				INTE_VOLDECRENABLE |
189				INTE_MUTEENABLE |
190				INTE_MICBUFENABLE |
191				INTE_ADCBUFENABLE |
192				INTE_EFXBUFENABLE |
193				INTE_GPSPDIFENABLE |
194				INTE_CDSPDIFENABLE |
195				INTE_INTERVALTIMERENB |
196				INTE_MIDITXENABLE |
197				INTE_MIDIRXENABLE;
198			if (emu->audigy)
199				bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
200			snd_emu10k1_intr_disable(emu, bits);
201		}
202		outl(orig_status, emu->port + IPR); /* ack all */
203	}
204	if (timeout == 1000)
205		snd_printk(KERN_INFO "emu10k1 irq routine failure\n");
206
207	return IRQ_RETVAL(handled);
208}
209