ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / pcmcia / pdaudiocf / pdaudiocf_irq.c
1 /*
2  * Driver for Sound Core PDAudioCF soundcard
3  *
4  * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  */
20
21 #include <sound/driver.h>
22 #include <sound/core.h>
23 #include "pdaudiocf.h"
24 #include <sound/initval.h>
25
26 /*
27  *
28  */
29 void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
30 {
31         pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return);
32         unsigned short stat;
33
34         if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
35                                   PDAUDIOCF_STAT_IS_CONFIGURED|
36                                   PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
37                 return;
38
39         stat = inw(chip->port + PDAUDIOCF_REG_ISR);
40         if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
41                 if (stat & PDAUDIOCF_IRQOVR)    /* should never happen */
42                         snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
43                 if (chip->pcm_substream)
44                         tasklet_hi_schedule(&chip->tq);
45                 if (!(stat & PDAUDIOCF_IRQAKM))
46                         stat |= PDAUDIOCF_IRQAKM;       /* check rate */
47         }
48         if (regs != NULL)
49                 snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
50 }
51
52 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
53 {
54         while (size-- > 0) {
55                 *dst++ = inw(rdp_port) ^ xor;
56                 inw(rdp_port);
57         }
58 }
59
60 static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
61 {
62         register u16 val1, val2;
63
64         while (size-- > 0) {
65                 val1 = inw(rdp_port);
66                 val2 = inw(rdp_port);
67                 inw(rdp_port);
68                 *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
69         }
70 }
71
72 static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
73 {
74         while (size-- > 0) {
75                 *dst++ = inw(rdp_port) ^ xor;
76                 *dst++ = inw(rdp_port) ^ xor;
77         }
78 }
79
80 static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
81 {
82         register u16 val1, val2, val3;
83
84         while (size-- > 0) {
85                 val1 = inw(rdp_port);
86                 val2 = inw(rdp_port);
87                 val3 = inw(rdp_port);
88                 *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
89                 *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
90         }
91 }
92
93 static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
94 {
95         while (size-- > 0) {
96                 *dst++ = swab16(inw(rdp_port) ^ xor);
97                 inw(rdp_port);
98         }
99 }
100
101 static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
102 {
103         register u16 val1, val2;
104
105         while (size-- > 0) {
106                 val1 = inw(rdp_port);
107                 val2 = inw(rdp_port);
108                 inw(rdp_port);
109                 *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
110         }
111 }
112
113 static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
114 {
115         while (size-- > 0) {
116                 *dst++ = swab16(inw(rdp_port) ^ xor);
117                 *dst++ = swab16(inw(rdp_port) ^ xor);
118         }
119 }
120
121 static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
122 {
123         register u16 val1, val2, val3;
124
125         while (size-- > 0) {
126                 val1 = inw(rdp_port);
127                 val2 = inw(rdp_port);
128                 val3 = inw(rdp_port);
129                 *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
130                 *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
131         }
132 }
133
134 static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
135 {
136         register u16 val1, val2;
137         register u32 xval1;
138
139         while (size-- > 0) {
140                 val1 = inw(rdp_port);
141                 val2 = inw(rdp_port);
142                 inw(rdp_port);
143                 xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
144                 *dst++ = (u8)(xval1 >> 8);
145                 *dst++ = (u8)(xval1 >> 16);
146                 *dst++ = (u8)(xval1 >> 24);
147         }
148 }
149
150 static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
151 {
152         register u16 val1, val2;
153         register u32 xval1;
154
155         while (size-- > 0) {
156                 val1 = inw(rdp_port);
157                 val2 = inw(rdp_port);
158                 inw(rdp_port);
159                 xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
160                 *dst++ = (u8)(xval1 >> 24);
161                 *dst++ = (u8)(xval1 >> 16);
162                 *dst++ = (u8)(xval1 >> 8);
163         }
164 }
165
166 static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
167 {
168         register u16 val1, val2, val3;
169         register u32 xval1, xval2;
170
171         while (size-- > 0) {
172                 val1 = inw(rdp_port);
173                 val2 = inw(rdp_port);
174                 val3 = inw(rdp_port);
175                 xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
176                 xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
177                 *dst++ = (u8)(xval1 >> 8);
178                 *dst++ = (u8)(xval1 >> 16);
179                 *dst++ = (u8)(xval1 >> 24);
180                 *dst++ = (u8)(xval2 >> 8);
181                 *dst++ = (u8)(xval2 >> 16);
182                 *dst++ = (u8)(xval2 >> 24);
183         }
184 }
185
186 static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
187 {
188         register u16 val1, val2, val3;
189         register u32 xval1, xval2;
190
191         while (size-- > 0) {
192                 val1 = inw(rdp_port);
193                 val2 = inw(rdp_port);
194                 val3 = inw(rdp_port);
195                 xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
196                 xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
197                 *dst++ = (u8)(xval1 >> 24);
198                 *dst++ = (u8)(xval1 >> 16);
199                 *dst++ = (u8)(xval1 >> 8);
200                 *dst++ = (u8)(xval2 >> 24);
201                 *dst++ = (u8)(xval2 >> 16);
202                 *dst++ = (u8)(xval2 >> 8);
203         }
204 }
205
206 static void pdacf_transfer(pdacf_t *chip, unsigned int size, unsigned int off)
207 {
208         unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
209         unsigned int xor = chip->pcm_xor;
210
211         if (chip->pcm_sample == 3) {
212                 if (chip->pcm_little) {
213                         if (chip->pcm_channels == 1) {
214                                 pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
215                         } else {
216                                 pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
217                         }
218                 } else {
219                         if (chip->pcm_channels == 1) {
220                                 pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
221                         } else {
222                                 pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
223                         }                       
224                 }
225                 return;
226         }
227         if (chip->pcm_swab == 0) {
228                 if (chip->pcm_channels == 1) {
229                         if (chip->pcm_frame == 2) {
230                                 pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
231                         } else {
232                                 pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
233                         }
234                 } else {
235                         if (chip->pcm_frame == 2) {
236                                 pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
237                         } else {
238                                 pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
239                         }
240                 }
241         } else {
242                 if (chip->pcm_channels == 1) {
243                         if (chip->pcm_frame == 2) {
244                                 pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
245                         } else {
246                                 pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
247                         }
248                 } else {
249                         if (chip->pcm_frame == 2) {
250                                 pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
251                         } else {
252                                 pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
253                         }
254                 }
255         }
256 }
257
258 void pdacf_tasklet(unsigned long private_data)
259 {
260         pdacf_t *chip = snd_magic_cast(pdacf_t, (void *)private_data, return);
261         int size, off, cont, rdp, wdp;
262
263         if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
264                 return;
265         
266         if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
267                 return;
268
269         rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
270         wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
271         // printk("TASKLET: rdp = %x, wdp = %x\n", rdp, wdp);
272         size = wdp - rdp;
273         if (size < 0)
274                 size += 0x10000;
275         if (size == 0)
276                 size = 0x10000;
277         size /= chip->pcm_frame;
278         if (size > 64)
279                 size -= 32;
280
281 #if 0
282         chip->pcm_hwptr += size;
283         chip->pcm_hwptr %= chip->pcm_size;
284         chip->pcm_tdone += size;
285         if (chip->pcm_frame == 2) {
286                 unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
287                 while (size-- > 0) {
288                         inw(rdp_port);
289                         inw(rdp_port);
290                 }
291         } else {
292                 unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
293                 while (size-- > 0) {
294                         inw(rdp_port);
295                         inw(rdp_port);
296                         inw(rdp_port);
297                 }
298         }
299 #else
300         off = chip->pcm_hwptr + chip->pcm_tdone;
301         off %= chip->pcm_size;
302         chip->pcm_tdone += size;
303         while (size > 0) {
304                 cont = chip->pcm_size - off;
305                 if (cont > size)
306                         cont = size;
307                 pdacf_transfer(chip, cont, off);
308                 off += cont;
309                 off %= chip->pcm_size;
310                 size -= cont;
311         }
312 #endif
313         spin_lock(&chip->reg_lock);
314         while (chip->pcm_tdone >= chip->pcm_period) {
315                 chip->pcm_hwptr += chip->pcm_period;
316                 chip->pcm_hwptr %= chip->pcm_size;
317                 chip->pcm_tdone -= chip->pcm_period;
318                 spin_unlock(&chip->reg_lock);
319                 snd_pcm_period_elapsed(chip->pcm_substream);
320                 spin_lock(&chip->reg_lock);
321         }
322         spin_unlock(&chip->reg_lock);
323         // printk("TASKLET: end\n");
324 }