Root/
1 | /* |
2 | * Driver for Sound Core PDAudioCF soundcard |
3 | * |
4 | * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.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/core.h> |
22 | #include "pdaudiocf.h" |
23 | #include <sound/initval.h> |
24 | #include <asm/irq_regs.h> |
25 | |
26 | /* |
27 | * |
28 | */ |
29 | irqreturn_t pdacf_interrupt(int irq, void *dev) |
30 | { |
31 | struct snd_pdacf *chip = dev; |
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 IRQ_HANDLED; /* IRQ_NONE here? */ |
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_schedule(&chip->tq); |
45 | if (!(stat & PDAUDIOCF_IRQAKM)) |
46 | stat |= PDAUDIOCF_IRQAKM; /* check rate */ |
47 | } |
48 | if (get_irq_regs() != NULL) |
49 | snd_ak4117_check_rate_and_errors(chip->ak4117, 0); |
50 | return IRQ_HANDLED; |
51 | } |
52 | |
53 | static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
54 | { |
55 | while (size-- > 0) { |
56 | *dst++ = inw(rdp_port) ^ xor; |
57 | inw(rdp_port); |
58 | } |
59 | } |
60 | |
61 | static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
62 | { |
63 | register u16 val1, val2; |
64 | |
65 | while (size-- > 0) { |
66 | val1 = inw(rdp_port); |
67 | val2 = inw(rdp_port); |
68 | inw(rdp_port); |
69 | *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; |
70 | } |
71 | } |
72 | |
73 | static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
74 | { |
75 | while (size-- > 0) { |
76 | *dst++ = inw(rdp_port) ^ xor; |
77 | *dst++ = inw(rdp_port) ^ xor; |
78 | } |
79 | } |
80 | |
81 | static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
82 | { |
83 | register u16 val1, val2, val3; |
84 | |
85 | while (size-- > 0) { |
86 | val1 = inw(rdp_port); |
87 | val2 = inw(rdp_port); |
88 | val3 = inw(rdp_port); |
89 | *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; |
90 | *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; |
91 | } |
92 | } |
93 | |
94 | static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
95 | { |
96 | while (size-- > 0) { |
97 | *dst++ = swab16(inw(rdp_port) ^ xor); |
98 | inw(rdp_port); |
99 | } |
100 | } |
101 | |
102 | static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
103 | { |
104 | register u16 val1, val2; |
105 | |
106 | while (size-- > 0) { |
107 | val1 = inw(rdp_port); |
108 | val2 = inw(rdp_port); |
109 | inw(rdp_port); |
110 | *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); |
111 | } |
112 | } |
113 | |
114 | static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
115 | { |
116 | while (size-- > 0) { |
117 | *dst++ = swab16(inw(rdp_port) ^ xor); |
118 | *dst++ = swab16(inw(rdp_port) ^ xor); |
119 | } |
120 | } |
121 | |
122 | static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
123 | { |
124 | register u16 val1, val2, val3; |
125 | |
126 | while (size-- > 0) { |
127 | val1 = inw(rdp_port); |
128 | val2 = inw(rdp_port); |
129 | val3 = inw(rdp_port); |
130 | *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); |
131 | *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor); |
132 | } |
133 | } |
134 | |
135 | static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
136 | { |
137 | register u16 val1, val2; |
138 | register u32 xval1; |
139 | |
140 | while (size-- > 0) { |
141 | val1 = inw(rdp_port); |
142 | val2 = inw(rdp_port); |
143 | inw(rdp_port); |
144 | xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; |
145 | *dst++ = (u8)(xval1 >> 8); |
146 | *dst++ = (u8)(xval1 >> 16); |
147 | *dst++ = (u8)(xval1 >> 24); |
148 | } |
149 | } |
150 | |
151 | static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) |
152 | { |
153 | register u16 val1, val2; |
154 | register u32 xval1; |
155 | |
156 | while (size-- > 0) { |
157 | val1 = inw(rdp_port); |
158 | val2 = inw(rdp_port); |
159 | inw(rdp_port); |
160 | xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; |
161 | *dst++ = (u8)(xval1 >> 24); |
162 | *dst++ = (u8)(xval1 >> 16); |
163 | *dst++ = (u8)(xval1 >> 8); |
164 | } |
165 | } |
166 | |
167 | static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
168 | { |
169 | register u16 val1, val2, val3; |
170 | register u32 xval1, xval2; |
171 | |
172 | while (size-- > 0) { |
173 | val1 = inw(rdp_port); |
174 | val2 = inw(rdp_port); |
175 | val3 = inw(rdp_port); |
176 | xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; |
177 | xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; |
178 | *dst++ = (u8)(xval1 >> 8); |
179 | *dst++ = (u8)(xval1 >> 16); |
180 | *dst++ = (u8)(xval1 >> 24); |
181 | *dst++ = (u8)(xval2 >> 8); |
182 | *dst++ = (u8)(xval2 >> 16); |
183 | *dst++ = (u8)(xval2 >> 24); |
184 | } |
185 | } |
186 | |
187 | static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) |
188 | { |
189 | register u16 val1, val2, val3; |
190 | register u32 xval1, xval2; |
191 | |
192 | while (size-- > 0) { |
193 | val1 = inw(rdp_port); |
194 | val2 = inw(rdp_port); |
195 | val3 = inw(rdp_port); |
196 | xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; |
197 | xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; |
198 | *dst++ = (u8)(xval1 >> 24); |
199 | *dst++ = (u8)(xval1 >> 16); |
200 | *dst++ = (u8)(xval1 >> 8); |
201 | *dst++ = (u8)(xval2 >> 24); |
202 | *dst++ = (u8)(xval2 >> 16); |
203 | *dst++ = (u8)(xval2 >> 8); |
204 | } |
205 | } |
206 | |
207 | static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off) |
208 | { |
209 | unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; |
210 | unsigned int xor = chip->pcm_xor; |
211 | |
212 | if (chip->pcm_sample == 3) { |
213 | if (chip->pcm_little) { |
214 | if (chip->pcm_channels == 1) { |
215 | pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); |
216 | } else { |
217 | pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); |
218 | } |
219 | } else { |
220 | if (chip->pcm_channels == 1) { |
221 | pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); |
222 | } else { |
223 | pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); |
224 | } |
225 | } |
226 | return; |
227 | } |
228 | if (chip->pcm_swab == 0) { |
229 | if (chip->pcm_channels == 1) { |
230 | if (chip->pcm_frame == 2) { |
231 | pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port); |
232 | } else { |
233 | pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port); |
234 | } |
235 | } else { |
236 | if (chip->pcm_frame == 2) { |
237 | pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); |
238 | } else { |
239 | pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); |
240 | } |
241 | } |
242 | } else { |
243 | if (chip->pcm_channels == 1) { |
244 | if (chip->pcm_frame == 2) { |
245 | pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port); |
246 | } else { |
247 | pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port); |
248 | } |
249 | } else { |
250 | if (chip->pcm_frame == 2) { |
251 | pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); |
252 | } else { |
253 | pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); |
254 | } |
255 | } |
256 | } |
257 | } |
258 | |
259 | void pdacf_tasklet(unsigned long private_data) |
260 | { |
261 | struct snd_pdacf *chip = (struct snd_pdacf *) private_data; |
262 | int size, off, cont, rdp, wdp; |
263 | |
264 | if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) |
265 | return; |
266 | |
267 | if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) |
268 | return; |
269 | |
270 | rdp = inw(chip->port + PDAUDIOCF_REG_RDP); |
271 | wdp = inw(chip->port + PDAUDIOCF_REG_WDP); |
272 | /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */ |
273 | size = wdp - rdp; |
274 | if (size < 0) |
275 | size += 0x10000; |
276 | if (size == 0) |
277 | size = 0x10000; |
278 | size /= chip->pcm_frame; |
279 | if (size > 64) |
280 | size -= 32; |
281 | |
282 | #if 0 |
283 | chip->pcm_hwptr += size; |
284 | chip->pcm_hwptr %= chip->pcm_size; |
285 | chip->pcm_tdone += size; |
286 | if (chip->pcm_frame == 2) { |
287 | unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; |
288 | while (size-- > 0) { |
289 | inw(rdp_port); |
290 | inw(rdp_port); |
291 | } |
292 | } else { |
293 | unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; |
294 | while (size-- > 0) { |
295 | inw(rdp_port); |
296 | inw(rdp_port); |
297 | inw(rdp_port); |
298 | } |
299 | } |
300 | #else |
301 | off = chip->pcm_hwptr + chip->pcm_tdone; |
302 | off %= chip->pcm_size; |
303 | chip->pcm_tdone += size; |
304 | while (size > 0) { |
305 | cont = chip->pcm_size - off; |
306 | if (cont > size) |
307 | cont = size; |
308 | pdacf_transfer(chip, cont, off); |
309 | off += cont; |
310 | off %= chip->pcm_size; |
311 | size -= cont; |
312 | } |
313 | #endif |
314 | spin_lock(&chip->reg_lock); |
315 | while (chip->pcm_tdone >= chip->pcm_period) { |
316 | chip->pcm_hwptr += chip->pcm_period; |
317 | chip->pcm_hwptr %= chip->pcm_size; |
318 | chip->pcm_tdone -= chip->pcm_period; |
319 | spin_unlock(&chip->reg_lock); |
320 | snd_pcm_period_elapsed(chip->pcm_substream); |
321 | spin_lock(&chip->reg_lock); |
322 | } |
323 | spin_unlock(&chip->reg_lock); |
324 | /* printk(KERN_DEBUG "TASKLET: end\n"); */ |
325 | } |
326 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9