diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/dmasound/dmasound_atari.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/dmasound/dmasound_atari.c')
-rw-r--r-- | sound/oss/dmasound/dmasound_atari.c | 1600 |
1 files changed, 1600 insertions, 0 deletions
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c new file mode 100644 index 000000000000..8daaf87664ba --- /dev/null +++ b/sound/oss/dmasound/dmasound_atari.c | |||
@@ -0,0 +1,1600 @@ | |||
1 | /* | ||
2 | * linux/sound/oss/dmasound/dmasound_atari.c | ||
3 | * | ||
4 | * Atari TT and Falcon DMA Sound Driver | ||
5 | * | ||
6 | * See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits | ||
7 | * prior to 28/01/2001 | ||
8 | * | ||
9 | * 28/01/2001 [0.1] Iain Sandoe | ||
10 | * - added versioning | ||
11 | * - put in and populated the hardware_afmts field. | ||
12 | * [0.2] - put in SNDCTL_DSP_GETCAPS value. | ||
13 | * 01/02/2001 [0.3] - put in default hard/soft settings. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/soundcard.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/atariints.h> | ||
27 | #include <asm/atari_stram.h> | ||
28 | |||
29 | #include "dmasound.h" | ||
30 | |||
31 | #define DMASOUND_ATARI_REVISION 0 | ||
32 | #define DMASOUND_ATARI_EDITION 3 | ||
33 | |||
34 | extern void atari_microwire_cmd(int cmd); | ||
35 | |||
36 | static int is_falcon; | ||
37 | static int write_sq_ignore_int; /* ++TeSche: used for Falcon */ | ||
38 | |||
39 | static int expand_bal; /* Balance factor for expanding (not volume!) */ | ||
40 | static int expand_data; /* Data for expanding */ | ||
41 | |||
42 | |||
43 | /*** Translations ************************************************************/ | ||
44 | |||
45 | |||
46 | /* ++TeSche: radically changed for new expanding purposes... | ||
47 | * | ||
48 | * These two routines now deal with copying/expanding/translating the samples | ||
49 | * from user space into our buffer at the right frequency. They take care about | ||
50 | * how much data there's actually to read, how much buffer space there is and | ||
51 | * to convert samples into the right frequency/encoding. They will only work on | ||
52 | * complete samples so it may happen they leave some bytes in the input stream | ||
53 | * if the user didn't write a multiple of the current sample size. They both | ||
54 | * return the number of bytes they've used from both streams so you may detect | ||
55 | * such a situation. Luckily all programs should be able to cope with that. | ||
56 | * | ||
57 | * I think I've optimized anything as far as one can do in plain C, all | ||
58 | * variables should fit in registers and the loops are really short. There's | ||
59 | * one loop for every possible situation. Writing a more generalized and thus | ||
60 | * parameterized loop would only produce slower code. Feel free to optimize | ||
61 | * this in assembler if you like. :) | ||
62 | * | ||
63 | * I think these routines belong here because they're not yet really hardware | ||
64 | * independent, especially the fact that the Falcon can play 16bit samples | ||
65 | * only in stereo is hardcoded in both of them! | ||
66 | * | ||
67 | * ++geert: split in even more functions (one per format) | ||
68 | */ | ||
69 | |||
70 | static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount, | ||
71 | u_char frame[], ssize_t *frameUsed, | ||
72 | ssize_t frameLeft); | ||
73 | static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount, | ||
74 | u_char frame[], ssize_t *frameUsed, | ||
75 | ssize_t frameLeft); | ||
76 | static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount, | ||
77 | u_char frame[], ssize_t *frameUsed, | ||
78 | ssize_t frameLeft); | ||
79 | static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount, | ||
80 | u_char frame[], ssize_t *frameUsed, | ||
81 | ssize_t frameLeft); | ||
82 | static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount, | ||
83 | u_char frame[], ssize_t *frameUsed, | ||
84 | ssize_t frameLeft); | ||
85 | static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount, | ||
86 | u_char frame[], ssize_t *frameUsed, | ||
87 | ssize_t frameLeft); | ||
88 | static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount, | ||
89 | u_char frame[], ssize_t *frameUsed, | ||
90 | ssize_t frameLeft); | ||
91 | static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount, | ||
92 | u_char frame[], ssize_t *frameUsed, | ||
93 | ssize_t frameLeft); | ||
94 | static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount, | ||
95 | u_char frame[], ssize_t *frameUsed, | ||
96 | ssize_t frameLeft); | ||
97 | static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount, | ||
98 | u_char frame[], ssize_t *frameUsed, | ||
99 | ssize_t frameLeft); | ||
100 | static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount, | ||
101 | u_char frame[], ssize_t *frameUsed, | ||
102 | ssize_t frameLeft); | ||
103 | static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount, | ||
104 | u_char frame[], ssize_t *frameUsed, | ||
105 | ssize_t frameLeft); | ||
106 | static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount, | ||
107 | u_char frame[], ssize_t *frameUsed, | ||
108 | ssize_t frameLeft); | ||
109 | static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount, | ||
110 | u_char frame[], ssize_t *frameUsed, | ||
111 | ssize_t frameLeft); | ||
112 | |||
113 | |||
114 | /*** Low level stuff *********************************************************/ | ||
115 | |||
116 | |||
117 | static void *AtaAlloc(unsigned int size, int flags); | ||
118 | static void AtaFree(void *, unsigned int size); | ||
119 | static int AtaIrqInit(void); | ||
120 | #ifdef MODULE | ||
121 | static void AtaIrqCleanUp(void); | ||
122 | #endif /* MODULE */ | ||
123 | static int AtaSetBass(int bass); | ||
124 | static int AtaSetTreble(int treble); | ||
125 | static void TTSilence(void); | ||
126 | static void TTInit(void); | ||
127 | static int TTSetFormat(int format); | ||
128 | static int TTSetVolume(int volume); | ||
129 | static int TTSetGain(int gain); | ||
130 | static void FalconSilence(void); | ||
131 | static void FalconInit(void); | ||
132 | static int FalconSetFormat(int format); | ||
133 | static int FalconSetVolume(int volume); | ||
134 | static void AtaPlayNextFrame(int index); | ||
135 | static void AtaPlay(void); | ||
136 | static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp); | ||
137 | |||
138 | /*** Mid level stuff *********************************************************/ | ||
139 | |||
140 | static void TTMixerInit(void); | ||
141 | static void FalconMixerInit(void); | ||
142 | static int AtaMixerIoctl(u_int cmd, u_long arg); | ||
143 | static int TTMixerIoctl(u_int cmd, u_long arg); | ||
144 | static int FalconMixerIoctl(u_int cmd, u_long arg); | ||
145 | static int AtaWriteSqSetup(void); | ||
146 | static int AtaSqOpen(mode_t mode); | ||
147 | static int TTStateInfo(char *buffer, size_t space); | ||
148 | static int FalconStateInfo(char *buffer, size_t space); | ||
149 | |||
150 | |||
151 | /*** Translations ************************************************************/ | ||
152 | |||
153 | |||
154 | static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount, | ||
155 | u_char frame[], ssize_t *frameUsed, | ||
156 | ssize_t frameLeft) | ||
157 | { | ||
158 | char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8 | ||
159 | : dmasound_alaw2dma8; | ||
160 | ssize_t count, used; | ||
161 | u_char *p = &frame[*frameUsed]; | ||
162 | |||
163 | count = min_t(unsigned long, userCount, frameLeft); | ||
164 | if (dmasound.soft.stereo) | ||
165 | count &= ~1; | ||
166 | used = count; | ||
167 | while (count > 0) { | ||
168 | u_char data; | ||
169 | if (get_user(data, userPtr++)) | ||
170 | return -EFAULT; | ||
171 | *p++ = table[data]; | ||
172 | count--; | ||
173 | } | ||
174 | *frameUsed += used; | ||
175 | return used; | ||
176 | } | ||
177 | |||
178 | |||
179 | static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount, | ||
180 | u_char frame[], ssize_t *frameUsed, | ||
181 | ssize_t frameLeft) | ||
182 | { | ||
183 | ssize_t count, used; | ||
184 | void *p = &frame[*frameUsed]; | ||
185 | |||
186 | count = min_t(unsigned long, userCount, frameLeft); | ||
187 | if (dmasound.soft.stereo) | ||
188 | count &= ~1; | ||
189 | used = count; | ||
190 | if (copy_from_user(p, userPtr, count)) | ||
191 | return -EFAULT; | ||
192 | *frameUsed += used; | ||
193 | return used; | ||
194 | } | ||
195 | |||
196 | |||
197 | static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount, | ||
198 | u_char frame[], ssize_t *frameUsed, | ||
199 | ssize_t frameLeft) | ||
200 | { | ||
201 | ssize_t count, used; | ||
202 | |||
203 | if (!dmasound.soft.stereo) { | ||
204 | u_char *p = &frame[*frameUsed]; | ||
205 | count = min_t(unsigned long, userCount, frameLeft); | ||
206 | used = count; | ||
207 | while (count > 0) { | ||
208 | u_char data; | ||
209 | if (get_user(data, userPtr++)) | ||
210 | return -EFAULT; | ||
211 | *p++ = data ^ 0x80; | ||
212 | count--; | ||
213 | } | ||
214 | } else { | ||
215 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
216 | count = min_t(unsigned long, userCount, frameLeft)>>1; | ||
217 | used = count*2; | ||
218 | while (count > 0) { | ||
219 | u_short data; | ||
220 | if (get_user(data, ((u_short *)userPtr)++)) | ||
221 | return -EFAULT; | ||
222 | *p++ = data ^ 0x8080; | ||
223 | count--; | ||
224 | } | ||
225 | } | ||
226 | *frameUsed += used; | ||
227 | return used; | ||
228 | } | ||
229 | |||
230 | |||
231 | static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount, | ||
232 | u_char frame[], ssize_t *frameUsed, | ||
233 | ssize_t frameLeft) | ||
234 | { | ||
235 | ssize_t count, used; | ||
236 | |||
237 | if (!dmasound.soft.stereo) { | ||
238 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
239 | count = min_t(unsigned long, userCount, frameLeft)>>1; | ||
240 | used = count*2; | ||
241 | while (count > 0) { | ||
242 | u_short data; | ||
243 | if (get_user(data, ((u_short *)userPtr)++)) | ||
244 | return -EFAULT; | ||
245 | *p++ = data; | ||
246 | *p++ = data; | ||
247 | count--; | ||
248 | } | ||
249 | *frameUsed += used*2; | ||
250 | } else { | ||
251 | void *p = (u_short *)&frame[*frameUsed]; | ||
252 | count = min_t(unsigned long, userCount, frameLeft) & ~3; | ||
253 | used = count; | ||
254 | if (copy_from_user(p, userPtr, count)) | ||
255 | return -EFAULT; | ||
256 | *frameUsed += used; | ||
257 | } | ||
258 | return used; | ||
259 | } | ||
260 | |||
261 | |||
262 | static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount, | ||
263 | u_char frame[], ssize_t *frameUsed, | ||
264 | ssize_t frameLeft) | ||
265 | { | ||
266 | ssize_t count, used; | ||
267 | |||
268 | if (!dmasound.soft.stereo) { | ||
269 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
270 | count = min_t(unsigned long, userCount, frameLeft)>>1; | ||
271 | used = count*2; | ||
272 | while (count > 0) { | ||
273 | u_short data; | ||
274 | if (get_user(data, ((u_short *)userPtr)++)) | ||
275 | return -EFAULT; | ||
276 | data ^= 0x8000; | ||
277 | *p++ = data; | ||
278 | *p++ = data; | ||
279 | count--; | ||
280 | } | ||
281 | *frameUsed += used*2; | ||
282 | } else { | ||
283 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
284 | count = min_t(unsigned long, userCount, frameLeft)>>2; | ||
285 | used = count*4; | ||
286 | while (count > 0) { | ||
287 | u_long data; | ||
288 | if (get_user(data, ((u_int *)userPtr)++)) | ||
289 | return -EFAULT; | ||
290 | *p++ = data ^ 0x80008000; | ||
291 | count--; | ||
292 | } | ||
293 | *frameUsed += used; | ||
294 | } | ||
295 | return used; | ||
296 | } | ||
297 | |||
298 | |||
299 | static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount, | ||
300 | u_char frame[], ssize_t *frameUsed, | ||
301 | ssize_t frameLeft) | ||
302 | { | ||
303 | ssize_t count, used; | ||
304 | |||
305 | count = frameLeft; | ||
306 | if (!dmasound.soft.stereo) { | ||
307 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
308 | count = min_t(unsigned long, userCount, frameLeft)>>1; | ||
309 | used = count*2; | ||
310 | while (count > 0) { | ||
311 | u_short data; | ||
312 | if (get_user(data, ((u_short *)userPtr)++)) | ||
313 | return -EFAULT; | ||
314 | data = le2be16(data); | ||
315 | *p++ = data; | ||
316 | *p++ = data; | ||
317 | count--; | ||
318 | } | ||
319 | *frameUsed += used*2; | ||
320 | } else { | ||
321 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
322 | count = min_t(unsigned long, userCount, frameLeft)>>2; | ||
323 | used = count*4; | ||
324 | while (count > 0) { | ||
325 | u_long data; | ||
326 | if (get_user(data, ((u_int *)userPtr)++)) | ||
327 | return -EFAULT; | ||
328 | data = le2be16dbl(data); | ||
329 | *p++ = data; | ||
330 | count--; | ||
331 | } | ||
332 | *frameUsed += used; | ||
333 | } | ||
334 | return used; | ||
335 | } | ||
336 | |||
337 | |||
338 | static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount, | ||
339 | u_char frame[], ssize_t *frameUsed, | ||
340 | ssize_t frameLeft) | ||
341 | { | ||
342 | ssize_t count, used; | ||
343 | |||
344 | count = frameLeft; | ||
345 | if (!dmasound.soft.stereo) { | ||
346 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
347 | count = min_t(unsigned long, userCount, frameLeft)>>1; | ||
348 | used = count*2; | ||
349 | while (count > 0) { | ||
350 | u_short data; | ||
351 | if (get_user(data, ((u_short *)userPtr)++)) | ||
352 | return -EFAULT; | ||
353 | data = le2be16(data) ^ 0x8000; | ||
354 | *p++ = data; | ||
355 | *p++ = data; | ||
356 | } | ||
357 | *frameUsed += used*2; | ||
358 | } else { | ||
359 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
360 | count = min_t(unsigned long, userCount, frameLeft)>>2; | ||
361 | used = count; | ||
362 | while (count > 0) { | ||
363 | u_long data; | ||
364 | if (get_user(data, ((u_int *)userPtr)++)) | ||
365 | return -EFAULT; | ||
366 | data = le2be16dbl(data) ^ 0x80008000; | ||
367 | *p++ = data; | ||
368 | count--; | ||
369 | } | ||
370 | *frameUsed += used; | ||
371 | } | ||
372 | return used; | ||
373 | } | ||
374 | |||
375 | |||
376 | static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount, | ||
377 | u_char frame[], ssize_t *frameUsed, | ||
378 | ssize_t frameLeft) | ||
379 | { | ||
380 | char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8 | ||
381 | : dmasound_alaw2dma8; | ||
382 | /* this should help gcc to stuff everything into registers */ | ||
383 | long bal = expand_bal; | ||
384 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
385 | ssize_t used, usedf; | ||
386 | |||
387 | used = userCount; | ||
388 | usedf = frameLeft; | ||
389 | if (!dmasound.soft.stereo) { | ||
390 | u_char *p = &frame[*frameUsed]; | ||
391 | u_char data = expand_data; | ||
392 | while (frameLeft) { | ||
393 | u_char c; | ||
394 | if (bal < 0) { | ||
395 | if (!userCount) | ||
396 | break; | ||
397 | if (get_user(c, userPtr++)) | ||
398 | return -EFAULT; | ||
399 | data = table[c]; | ||
400 | userCount--; | ||
401 | bal += hSpeed; | ||
402 | } | ||
403 | *p++ = data; | ||
404 | frameLeft--; | ||
405 | bal -= sSpeed; | ||
406 | } | ||
407 | expand_data = data; | ||
408 | } else { | ||
409 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
410 | u_short data = expand_data; | ||
411 | while (frameLeft >= 2) { | ||
412 | u_char c; | ||
413 | if (bal < 0) { | ||
414 | if (userCount < 2) | ||
415 | break; | ||
416 | if (get_user(c, userPtr++)) | ||
417 | return -EFAULT; | ||
418 | data = table[c] << 8; | ||
419 | if (get_user(c, userPtr++)) | ||
420 | return -EFAULT; | ||
421 | data |= table[c]; | ||
422 | userCount -= 2; | ||
423 | bal += hSpeed; | ||
424 | } | ||
425 | *p++ = data; | ||
426 | frameLeft -= 2; | ||
427 | bal -= sSpeed; | ||
428 | } | ||
429 | expand_data = data; | ||
430 | } | ||
431 | expand_bal = bal; | ||
432 | used -= userCount; | ||
433 | *frameUsed += usedf-frameLeft; | ||
434 | return used; | ||
435 | } | ||
436 | |||
437 | |||
438 | static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount, | ||
439 | u_char frame[], ssize_t *frameUsed, | ||
440 | ssize_t frameLeft) | ||
441 | { | ||
442 | /* this should help gcc to stuff everything into registers */ | ||
443 | long bal = expand_bal; | ||
444 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
445 | ssize_t used, usedf; | ||
446 | |||
447 | used = userCount; | ||
448 | usedf = frameLeft; | ||
449 | if (!dmasound.soft.stereo) { | ||
450 | u_char *p = &frame[*frameUsed]; | ||
451 | u_char data = expand_data; | ||
452 | while (frameLeft) { | ||
453 | if (bal < 0) { | ||
454 | if (!userCount) | ||
455 | break; | ||
456 | if (get_user(data, userPtr++)) | ||
457 | return -EFAULT; | ||
458 | userCount--; | ||
459 | bal += hSpeed; | ||
460 | } | ||
461 | *p++ = data; | ||
462 | frameLeft--; | ||
463 | bal -= sSpeed; | ||
464 | } | ||
465 | expand_data = data; | ||
466 | } else { | ||
467 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
468 | u_short data = expand_data; | ||
469 | while (frameLeft >= 2) { | ||
470 | if (bal < 0) { | ||
471 | if (userCount < 2) | ||
472 | break; | ||
473 | if (get_user(data, ((u_short *)userPtr)++)) | ||
474 | return -EFAULT; | ||
475 | userCount -= 2; | ||
476 | bal += hSpeed; | ||
477 | } | ||
478 | *p++ = data; | ||
479 | frameLeft -= 2; | ||
480 | bal -= sSpeed; | ||
481 | } | ||
482 | expand_data = data; | ||
483 | } | ||
484 | expand_bal = bal; | ||
485 | used -= userCount; | ||
486 | *frameUsed += usedf-frameLeft; | ||
487 | return used; | ||
488 | } | ||
489 | |||
490 | |||
491 | static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount, | ||
492 | u_char frame[], ssize_t *frameUsed, | ||
493 | ssize_t frameLeft) | ||
494 | { | ||
495 | /* this should help gcc to stuff everything into registers */ | ||
496 | long bal = expand_bal; | ||
497 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
498 | ssize_t used, usedf; | ||
499 | |||
500 | used = userCount; | ||
501 | usedf = frameLeft; | ||
502 | if (!dmasound.soft.stereo) { | ||
503 | u_char *p = &frame[*frameUsed]; | ||
504 | u_char data = expand_data; | ||
505 | while (frameLeft) { | ||
506 | if (bal < 0) { | ||
507 | if (!userCount) | ||
508 | break; | ||
509 | if (get_user(data, userPtr++)) | ||
510 | return -EFAULT; | ||
511 | data ^= 0x80; | ||
512 | userCount--; | ||
513 | bal += hSpeed; | ||
514 | } | ||
515 | *p++ = data; | ||
516 | frameLeft--; | ||
517 | bal -= sSpeed; | ||
518 | } | ||
519 | expand_data = data; | ||
520 | } else { | ||
521 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
522 | u_short data = expand_data; | ||
523 | while (frameLeft >= 2) { | ||
524 | if (bal < 0) { | ||
525 | if (userCount < 2) | ||
526 | break; | ||
527 | if (get_user(data, ((u_short *)userPtr)++)) | ||
528 | return -EFAULT; | ||
529 | data ^= 0x8080; | ||
530 | userCount -= 2; | ||
531 | bal += hSpeed; | ||
532 | } | ||
533 | *p++ = data; | ||
534 | frameLeft -= 2; | ||
535 | bal -= sSpeed; | ||
536 | } | ||
537 | expand_data = data; | ||
538 | } | ||
539 | expand_bal = bal; | ||
540 | used -= userCount; | ||
541 | *frameUsed += usedf-frameLeft; | ||
542 | return used; | ||
543 | } | ||
544 | |||
545 | |||
546 | static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount, | ||
547 | u_char frame[], ssize_t *frameUsed, | ||
548 | ssize_t frameLeft) | ||
549 | { | ||
550 | /* this should help gcc to stuff everything into registers */ | ||
551 | long bal = expand_bal; | ||
552 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
553 | ssize_t used, usedf; | ||
554 | |||
555 | used = userCount; | ||
556 | usedf = frameLeft; | ||
557 | if (!dmasound.soft.stereo) { | ||
558 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
559 | u_short data = expand_data; | ||
560 | while (frameLeft >= 4) { | ||
561 | if (bal < 0) { | ||
562 | if (userCount < 2) | ||
563 | break; | ||
564 | if (get_user(data, ((u_short *)userPtr)++)) | ||
565 | return -EFAULT; | ||
566 | userCount -= 2; | ||
567 | bal += hSpeed; | ||
568 | } | ||
569 | *p++ = data; | ||
570 | *p++ = data; | ||
571 | frameLeft -= 4; | ||
572 | bal -= sSpeed; | ||
573 | } | ||
574 | expand_data = data; | ||
575 | } else { | ||
576 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
577 | u_long data = expand_data; | ||
578 | while (frameLeft >= 4) { | ||
579 | if (bal < 0) { | ||
580 | if (userCount < 4) | ||
581 | break; | ||
582 | if (get_user(data, ((u_int *)userPtr)++)) | ||
583 | return -EFAULT; | ||
584 | userCount -= 4; | ||
585 | bal += hSpeed; | ||
586 | } | ||
587 | *p++ = data; | ||
588 | frameLeft -= 4; | ||
589 | bal -= sSpeed; | ||
590 | } | ||
591 | expand_data = data; | ||
592 | } | ||
593 | expand_bal = bal; | ||
594 | used -= userCount; | ||
595 | *frameUsed += usedf-frameLeft; | ||
596 | return used; | ||
597 | } | ||
598 | |||
599 | |||
600 | static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount, | ||
601 | u_char frame[], ssize_t *frameUsed, | ||
602 | ssize_t frameLeft) | ||
603 | { | ||
604 | /* this should help gcc to stuff everything into registers */ | ||
605 | long bal = expand_bal; | ||
606 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
607 | ssize_t used, usedf; | ||
608 | |||
609 | used = userCount; | ||
610 | usedf = frameLeft; | ||
611 | if (!dmasound.soft.stereo) { | ||
612 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
613 | u_short data = expand_data; | ||
614 | while (frameLeft >= 4) { | ||
615 | if (bal < 0) { | ||
616 | if (userCount < 2) | ||
617 | break; | ||
618 | if (get_user(data, ((u_short *)userPtr)++)) | ||
619 | return -EFAULT; | ||
620 | data ^= 0x8000; | ||
621 | userCount -= 2; | ||
622 | bal += hSpeed; | ||
623 | } | ||
624 | *p++ = data; | ||
625 | *p++ = data; | ||
626 | frameLeft -= 4; | ||
627 | bal -= sSpeed; | ||
628 | } | ||
629 | expand_data = data; | ||
630 | } else { | ||
631 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
632 | u_long data = expand_data; | ||
633 | while (frameLeft >= 4) { | ||
634 | if (bal < 0) { | ||
635 | if (userCount < 4) | ||
636 | break; | ||
637 | if (get_user(data, ((u_int *)userPtr)++)) | ||
638 | return -EFAULT; | ||
639 | data ^= 0x80008000; | ||
640 | userCount -= 4; | ||
641 | bal += hSpeed; | ||
642 | } | ||
643 | *p++ = data; | ||
644 | frameLeft -= 4; | ||
645 | bal -= sSpeed; | ||
646 | } | ||
647 | expand_data = data; | ||
648 | } | ||
649 | expand_bal = bal; | ||
650 | used -= userCount; | ||
651 | *frameUsed += usedf-frameLeft; | ||
652 | return used; | ||
653 | } | ||
654 | |||
655 | |||
656 | static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount, | ||
657 | u_char frame[], ssize_t *frameUsed, | ||
658 | ssize_t frameLeft) | ||
659 | { | ||
660 | /* this should help gcc to stuff everything into registers */ | ||
661 | long bal = expand_bal; | ||
662 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
663 | ssize_t used, usedf; | ||
664 | |||
665 | used = userCount; | ||
666 | usedf = frameLeft; | ||
667 | if (!dmasound.soft.stereo) { | ||
668 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
669 | u_short data = expand_data; | ||
670 | while (frameLeft >= 4) { | ||
671 | if (bal < 0) { | ||
672 | if (userCount < 2) | ||
673 | break; | ||
674 | if (get_user(data, ((u_short *)userPtr)++)) | ||
675 | return -EFAULT; | ||
676 | data = le2be16(data); | ||
677 | userCount -= 2; | ||
678 | bal += hSpeed; | ||
679 | } | ||
680 | *p++ = data; | ||
681 | *p++ = data; | ||
682 | frameLeft -= 4; | ||
683 | bal -= sSpeed; | ||
684 | } | ||
685 | expand_data = data; | ||
686 | } else { | ||
687 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
688 | u_long data = expand_data; | ||
689 | while (frameLeft >= 4) { | ||
690 | if (bal < 0) { | ||
691 | if (userCount < 4) | ||
692 | break; | ||
693 | if (get_user(data, ((u_int *)userPtr)++)) | ||
694 | return -EFAULT; | ||
695 | data = le2be16dbl(data); | ||
696 | userCount -= 4; | ||
697 | bal += hSpeed; | ||
698 | } | ||
699 | *p++ = data; | ||
700 | frameLeft -= 4; | ||
701 | bal -= sSpeed; | ||
702 | } | ||
703 | expand_data = data; | ||
704 | } | ||
705 | expand_bal = bal; | ||
706 | used -= userCount; | ||
707 | *frameUsed += usedf-frameLeft; | ||
708 | return used; | ||
709 | } | ||
710 | |||
711 | |||
712 | static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount, | ||
713 | u_char frame[], ssize_t *frameUsed, | ||
714 | ssize_t frameLeft) | ||
715 | { | ||
716 | /* this should help gcc to stuff everything into registers */ | ||
717 | long bal = expand_bal; | ||
718 | long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | ||
719 | ssize_t used, usedf; | ||
720 | |||
721 | used = userCount; | ||
722 | usedf = frameLeft; | ||
723 | if (!dmasound.soft.stereo) { | ||
724 | u_short *p = (u_short *)&frame[*frameUsed]; | ||
725 | u_short data = expand_data; | ||
726 | while (frameLeft >= 4) { | ||
727 | if (bal < 0) { | ||
728 | if (userCount < 2) | ||
729 | break; | ||
730 | if (get_user(data, ((u_short *)userPtr)++)) | ||
731 | return -EFAULT; | ||
732 | data = le2be16(data) ^ 0x8000; | ||
733 | userCount -= 2; | ||
734 | bal += hSpeed; | ||
735 | } | ||
736 | *p++ = data; | ||
737 | *p++ = data; | ||
738 | frameLeft -= 4; | ||
739 | bal -= sSpeed; | ||
740 | } | ||
741 | expand_data = data; | ||
742 | } else { | ||
743 | u_long *p = (u_long *)&frame[*frameUsed]; | ||
744 | u_long data = expand_data; | ||
745 | while (frameLeft >= 4) { | ||
746 | if (bal < 0) { | ||
747 | if (userCount < 4) | ||
748 | break; | ||
749 | if (get_user(data, ((u_int *)userPtr)++)) | ||
750 | return -EFAULT; | ||
751 | data = le2be16dbl(data) ^ 0x80008000; | ||
752 | userCount -= 4; | ||
753 | bal += hSpeed; | ||
754 | } | ||
755 | *p++ = data; | ||
756 | frameLeft -= 4; | ||
757 | bal -= sSpeed; | ||
758 | } | ||
759 | expand_data = data; | ||
760 | } | ||
761 | expand_bal = bal; | ||
762 | used -= userCount; | ||
763 | *frameUsed += usedf-frameLeft; | ||
764 | return used; | ||
765 | } | ||
766 | |||
767 | |||
768 | static TRANS transTTNormal = { | ||
769 | .ct_ulaw = ata_ct_law, | ||
770 | .ct_alaw = ata_ct_law, | ||
771 | .ct_s8 = ata_ct_s8, | ||
772 | .ct_u8 = ata_ct_u8, | ||
773 | }; | ||
774 | |||
775 | static TRANS transTTExpanding = { | ||
776 | .ct_ulaw = ata_ctx_law, | ||
777 | .ct_alaw = ata_ctx_law, | ||
778 | .ct_s8 = ata_ctx_s8, | ||
779 | .ct_u8 = ata_ctx_u8, | ||
780 | }; | ||
781 | |||
782 | static TRANS transFalconNormal = { | ||
783 | .ct_ulaw = ata_ct_law, | ||
784 | .ct_alaw = ata_ct_law, | ||
785 | .ct_s8 = ata_ct_s8, | ||
786 | .ct_u8 = ata_ct_u8, | ||
787 | .ct_s16be = ata_ct_s16be, | ||
788 | .ct_u16be = ata_ct_u16be, | ||
789 | .ct_s16le = ata_ct_s16le, | ||
790 | .ct_u16le = ata_ct_u16le | ||
791 | }; | ||
792 | |||
793 | static TRANS transFalconExpanding = { | ||
794 | .ct_ulaw = ata_ctx_law, | ||
795 | .ct_alaw = ata_ctx_law, | ||
796 | .ct_s8 = ata_ctx_s8, | ||
797 | .ct_u8 = ata_ctx_u8, | ||
798 | .ct_s16be = ata_ctx_s16be, | ||
799 | .ct_u16be = ata_ctx_u16be, | ||
800 | .ct_s16le = ata_ctx_s16le, | ||
801 | .ct_u16le = ata_ctx_u16le, | ||
802 | }; | ||
803 | |||
804 | |||
805 | /*** Low level stuff *********************************************************/ | ||
806 | |||
807 | |||
808 | |||
809 | /* | ||
810 | * Atari (TT/Falcon) | ||
811 | */ | ||
812 | |||
813 | static void *AtaAlloc(unsigned int size, int flags) | ||
814 | { | ||
815 | return atari_stram_alloc(size, "dmasound"); | ||
816 | } | ||
817 | |||
818 | static void AtaFree(void *obj, unsigned int size) | ||
819 | { | ||
820 | atari_stram_free( obj ); | ||
821 | } | ||
822 | |||
823 | static int __init AtaIrqInit(void) | ||
824 | { | ||
825 | /* Set up timer A. Timer A | ||
826 | will receive a signal upon end of playing from the sound | ||
827 | hardware. Furthermore Timer A is able to count events | ||
828 | and will cause an interrupt after a programmed number | ||
829 | of events. So all we need to keep the music playing is | ||
830 | to provide the sound hardware with new data upon | ||
831 | an interrupt from timer A. */ | ||
832 | mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ | ||
833 | mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ | ||
834 | mfp.tim_ct_a = 8; /* Turn on event counting. */ | ||
835 | /* Register interrupt handler. */ | ||
836 | request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", | ||
837 | AtaInterrupt); | ||
838 | mfp.int_en_a |= 0x20; /* Turn interrupt on. */ | ||
839 | mfp.int_mk_a |= 0x20; | ||
840 | return 1; | ||
841 | } | ||
842 | |||
843 | #ifdef MODULE | ||
844 | static void AtaIrqCleanUp(void) | ||
845 | { | ||
846 | mfp.tim_ct_a = 0; /* stop timer */ | ||
847 | mfp.int_en_a &= ~0x20; /* turn interrupt off */ | ||
848 | free_irq(IRQ_MFP_TIMA, AtaInterrupt); | ||
849 | } | ||
850 | #endif /* MODULE */ | ||
851 | |||
852 | |||
853 | #define TONE_VOXWARE_TO_DB(v) \ | ||
854 | (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25) | ||
855 | #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) | ||
856 | |||
857 | |||
858 | static int AtaSetBass(int bass) | ||
859 | { | ||
860 | dmasound.bass = TONE_VOXWARE_TO_DB(bass); | ||
861 | atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass)); | ||
862 | return TONE_DB_TO_VOXWARE(dmasound.bass); | ||
863 | } | ||
864 | |||
865 | |||
866 | static int AtaSetTreble(int treble) | ||
867 | { | ||
868 | dmasound.treble = TONE_VOXWARE_TO_DB(treble); | ||
869 | atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble)); | ||
870 | return TONE_DB_TO_VOXWARE(dmasound.treble); | ||
871 | } | ||
872 | |||
873 | |||
874 | |||
875 | /* | ||
876 | * TT | ||
877 | */ | ||
878 | |||
879 | |||
880 | static void TTSilence(void) | ||
881 | { | ||
882 | tt_dmasnd.ctrl = DMASND_CTRL_OFF; | ||
883 | atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ | ||
884 | } | ||
885 | |||
886 | |||
887 | static void TTInit(void) | ||
888 | { | ||
889 | int mode, i, idx; | ||
890 | const int freq[4] = {50066, 25033, 12517, 6258}; | ||
891 | |||
892 | /* search a frequency that fits into the allowed error range */ | ||
893 | |||
894 | idx = -1; | ||
895 | for (i = 0; i < ARRAY_SIZE(freq); i++) | ||
896 | /* this isn't as much useful for a TT than for a Falcon, but | ||
897 | * then it doesn't hurt very much to implement it for a TT too. | ||
898 | */ | ||
899 | if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius) | ||
900 | idx = i; | ||
901 | if (idx > -1) { | ||
902 | dmasound.soft.speed = freq[idx]; | ||
903 | dmasound.trans_write = &transTTNormal; | ||
904 | } else | ||
905 | dmasound.trans_write = &transTTExpanding; | ||
906 | |||
907 | TTSilence(); | ||
908 | dmasound.hard = dmasound.soft; | ||
909 | |||
910 | if (dmasound.hard.speed > 50066) { | ||
911 | /* we would need to squeeze the sound, but we won't do that */ | ||
912 | dmasound.hard.speed = 50066; | ||
913 | mode = DMASND_MODE_50KHZ; | ||
914 | dmasound.trans_write = &transTTNormal; | ||
915 | } else if (dmasound.hard.speed > 25033) { | ||
916 | dmasound.hard.speed = 50066; | ||
917 | mode = DMASND_MODE_50KHZ; | ||
918 | } else if (dmasound.hard.speed > 12517) { | ||
919 | dmasound.hard.speed = 25033; | ||
920 | mode = DMASND_MODE_25KHZ; | ||
921 | } else if (dmasound.hard.speed > 6258) { | ||
922 | dmasound.hard.speed = 12517; | ||
923 | mode = DMASND_MODE_12KHZ; | ||
924 | } else { | ||
925 | dmasound.hard.speed = 6258; | ||
926 | mode = DMASND_MODE_6KHZ; | ||
927 | } | ||
928 | |||
929 | tt_dmasnd.mode = (dmasound.hard.stereo ? | ||
930 | DMASND_MODE_STEREO : DMASND_MODE_MONO) | | ||
931 | DMASND_MODE_8BIT | mode; | ||
932 | |||
933 | expand_bal = -dmasound.soft.speed; | ||
934 | } | ||
935 | |||
936 | |||
937 | static int TTSetFormat(int format) | ||
938 | { | ||
939 | /* TT sound DMA supports only 8bit modes */ | ||
940 | |||
941 | switch (format) { | ||
942 | case AFMT_QUERY: | ||
943 | return dmasound.soft.format; | ||
944 | case AFMT_MU_LAW: | ||
945 | case AFMT_A_LAW: | ||
946 | case AFMT_S8: | ||
947 | case AFMT_U8: | ||
948 | break; | ||
949 | default: | ||
950 | format = AFMT_S8; | ||
951 | } | ||
952 | |||
953 | dmasound.soft.format = format; | ||
954 | dmasound.soft.size = 8; | ||
955 | if (dmasound.minDev == SND_DEV_DSP) { | ||
956 | dmasound.dsp.format = format; | ||
957 | dmasound.dsp.size = 8; | ||
958 | } | ||
959 | TTInit(); | ||
960 | |||
961 | return format; | ||
962 | } | ||
963 | |||
964 | |||
965 | #define VOLUME_VOXWARE_TO_DB(v) \ | ||
966 | (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40) | ||
967 | #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) | ||
968 | |||
969 | |||
970 | static int TTSetVolume(int volume) | ||
971 | { | ||
972 | dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); | ||
973 | atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left)); | ||
974 | dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); | ||
975 | atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right)); | ||
976 | return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) | | ||
977 | (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8); | ||
978 | } | ||
979 | |||
980 | |||
981 | #define GAIN_VOXWARE_TO_DB(v) \ | ||
982 | (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80) | ||
983 | #define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4) | ||
984 | |||
985 | static int TTSetGain(int gain) | ||
986 | { | ||
987 | dmasound.gain = GAIN_VOXWARE_TO_DB(gain); | ||
988 | atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain)); | ||
989 | return GAIN_DB_TO_VOXWARE(dmasound.gain); | ||
990 | } | ||
991 | |||
992 | |||
993 | |||
994 | /* | ||
995 | * Falcon | ||
996 | */ | ||
997 | |||
998 | |||
999 | static void FalconSilence(void) | ||
1000 | { | ||
1001 | /* stop playback, set sample rate 50kHz for PSG sound */ | ||
1002 | tt_dmasnd.ctrl = DMASND_CTRL_OFF; | ||
1003 | tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; | ||
1004 | tt_dmasnd.int_div = 0; /* STE compatible divider */ | ||
1005 | tt_dmasnd.int_ctrl = 0x0; | ||
1006 | tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ | ||
1007 | tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ | ||
1008 | tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ | ||
1009 | tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | static void FalconInit(void) | ||
1014 | { | ||
1015 | int divider, i, idx; | ||
1016 | const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; | ||
1017 | |||
1018 | /* search a frequency that fits into the allowed error range */ | ||
1019 | |||
1020 | idx = -1; | ||
1021 | for (i = 0; i < ARRAY_SIZE(freq); i++) | ||
1022 | /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would | ||
1023 | * be playable without expanding, but that now a kernel runtime | ||
1024 | * option | ||
1025 | */ | ||
1026 | if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius) | ||
1027 | idx = i; | ||
1028 | if (idx > -1) { | ||
1029 | dmasound.soft.speed = freq[idx]; | ||
1030 | dmasound.trans_write = &transFalconNormal; | ||
1031 | } else | ||
1032 | dmasound.trans_write = &transFalconExpanding; | ||
1033 | |||
1034 | FalconSilence(); | ||
1035 | dmasound.hard = dmasound.soft; | ||
1036 | |||
1037 | if (dmasound.hard.size == 16) { | ||
1038 | /* the Falcon can play 16bit samples only in stereo */ | ||
1039 | dmasound.hard.stereo = 1; | ||
1040 | } | ||
1041 | |||
1042 | if (dmasound.hard.speed > 49170) { | ||
1043 | /* we would need to squeeze the sound, but we won't do that */ | ||
1044 | dmasound.hard.speed = 49170; | ||
1045 | divider = 1; | ||
1046 | dmasound.trans_write = &transFalconNormal; | ||
1047 | } else if (dmasound.hard.speed > 32780) { | ||
1048 | dmasound.hard.speed = 49170; | ||
1049 | divider = 1; | ||
1050 | } else if (dmasound.hard.speed > 24585) { | ||
1051 | dmasound.hard.speed = 32780; | ||
1052 | divider = 2; | ||
1053 | } else if (dmasound.hard.speed > 19668) { | ||
1054 | dmasound.hard.speed = 24585; | ||
1055 | divider = 3; | ||
1056 | } else if (dmasound.hard.speed > 16390) { | ||
1057 | dmasound.hard.speed = 19668; | ||
1058 | divider = 4; | ||
1059 | } else if (dmasound.hard.speed > 12292) { | ||
1060 | dmasound.hard.speed = 16390; | ||
1061 | divider = 5; | ||
1062 | } else if (dmasound.hard.speed > 9834) { | ||
1063 | dmasound.hard.speed = 12292; | ||
1064 | divider = 7; | ||
1065 | } else if (dmasound.hard.speed > 8195) { | ||
1066 | dmasound.hard.speed = 9834; | ||
1067 | divider = 9; | ||
1068 | } else { | ||
1069 | dmasound.hard.speed = 8195; | ||
1070 | divider = 11; | ||
1071 | } | ||
1072 | tt_dmasnd.int_div = divider; | ||
1073 | |||
1074 | /* Setup Falcon sound DMA for playback */ | ||
1075 | tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ | ||
1076 | tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ | ||
1077 | tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ | ||
1078 | tt_dmasnd.cbar_dst = 0x0000; | ||
1079 | tt_dmasnd.rec_track_select = 0; | ||
1080 | tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ | ||
1081 | tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ | ||
1082 | |||
1083 | tt_dmasnd.mode = (dmasound.hard.stereo ? | ||
1084 | DMASND_MODE_STEREO : DMASND_MODE_MONO) | | ||
1085 | ((dmasound.hard.size == 8) ? | ||
1086 | DMASND_MODE_8BIT : DMASND_MODE_16BIT) | | ||
1087 | DMASND_MODE_6KHZ; | ||
1088 | |||
1089 | expand_bal = -dmasound.soft.speed; | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | static int FalconSetFormat(int format) | ||
1094 | { | ||
1095 | int size; | ||
1096 | /* Falcon sound DMA supports 8bit and 16bit modes */ | ||
1097 | |||
1098 | switch (format) { | ||
1099 | case AFMT_QUERY: | ||
1100 | return dmasound.soft.format; | ||
1101 | case AFMT_MU_LAW: | ||
1102 | case AFMT_A_LAW: | ||
1103 | case AFMT_U8: | ||
1104 | case AFMT_S8: | ||
1105 | size = 8; | ||
1106 | break; | ||
1107 | case AFMT_S16_BE: | ||
1108 | case AFMT_U16_BE: | ||
1109 | case AFMT_S16_LE: | ||
1110 | case AFMT_U16_LE: | ||
1111 | size = 16; | ||
1112 | break; | ||
1113 | default: /* :-) */ | ||
1114 | size = 8; | ||
1115 | format = AFMT_S8; | ||
1116 | } | ||
1117 | |||
1118 | dmasound.soft.format = format; | ||
1119 | dmasound.soft.size = size; | ||
1120 | if (dmasound.minDev == SND_DEV_DSP) { | ||
1121 | dmasound.dsp.format = format; | ||
1122 | dmasound.dsp.size = dmasound.soft.size; | ||
1123 | } | ||
1124 | |||
1125 | FalconInit(); | ||
1126 | |||
1127 | return format; | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | /* This is for the Falcon output *attenuation* in 1.5dB steps, | ||
1132 | * i.e. output level from 0 to -22.5dB in -1.5dB steps. | ||
1133 | */ | ||
1134 | #define VOLUME_VOXWARE_TO_ATT(v) \ | ||
1135 | ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20) | ||
1136 | #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) | ||
1137 | |||
1138 | |||
1139 | static int FalconSetVolume(int volume) | ||
1140 | { | ||
1141 | dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); | ||
1142 | dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); | ||
1143 | tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4; | ||
1144 | return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) | | ||
1145 | VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8; | ||
1146 | } | ||
1147 | |||
1148 | |||
1149 | static void AtaPlayNextFrame(int index) | ||
1150 | { | ||
1151 | char *start, *end; | ||
1152 | |||
1153 | /* used by AtaPlay() if all doubts whether there really is something | ||
1154 | * to be played are already wiped out. | ||
1155 | */ | ||
1156 | start = write_sq.buffers[write_sq.front]; | ||
1157 | end = start+((write_sq.count == index) ? write_sq.rear_size | ||
1158 | : write_sq.block_size); | ||
1159 | /* end might not be a legal virtual address. */ | ||
1160 | DMASNDSetEnd(virt_to_phys(end - 1) + 1); | ||
1161 | DMASNDSetBase(virt_to_phys(start)); | ||
1162 | /* Since only an even number of samples per frame can | ||
1163 | be played, we might lose one byte here. (TO DO) */ | ||
1164 | write_sq.front = (write_sq.front+1) % write_sq.max_count; | ||
1165 | write_sq.active++; | ||
1166 | tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | static void AtaPlay(void) | ||
1171 | { | ||
1172 | /* ++TeSche: Note that write_sq.active is no longer just a flag but | ||
1173 | * holds the number of frames the DMA is currently programmed for | ||
1174 | * instead, may be 0, 1 (currently being played) or 2 (pre-programmed). | ||
1175 | * | ||
1176 | * Changes done to write_sq.count and write_sq.active are a bit more | ||
1177 | * subtle again so now I must admit I also prefer disabling the irq | ||
1178 | * here rather than considering all possible situations. But the point | ||
1179 | * is that disabling the irq doesn't have any bad influence on this | ||
1180 | * version of the driver as we benefit from having pre-programmed the | ||
1181 | * DMA wherever possible: There's no need to reload the DMA at the | ||
1182 | * exact time of an interrupt but only at some time while the | ||
1183 | * pre-programmed frame is playing! | ||
1184 | */ | ||
1185 | atari_disable_irq(IRQ_MFP_TIMA); | ||
1186 | |||
1187 | if (write_sq.active == 2 || /* DMA is 'full' */ | ||
1188 | write_sq.count <= 0) { /* nothing to do */ | ||
1189 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1190 | return; | ||
1191 | } | ||
1192 | |||
1193 | if (write_sq.active == 0) { | ||
1194 | /* looks like there's nothing 'in' the DMA yet, so try | ||
1195 | * to put two frames into it (at least one is available). | ||
1196 | */ | ||
1197 | if (write_sq.count == 1 && | ||
1198 | write_sq.rear_size < write_sq.block_size && | ||
1199 | !write_sq.syncing) { | ||
1200 | /* hmmm, the only existing frame is not | ||
1201 | * yet filled and we're not syncing? | ||
1202 | */ | ||
1203 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1204 | return; | ||
1205 | } | ||
1206 | AtaPlayNextFrame(1); | ||
1207 | if (write_sq.count == 1) { | ||
1208 | /* no more frames */ | ||
1209 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1210 | return; | ||
1211 | } | ||
1212 | if (write_sq.count == 2 && | ||
1213 | write_sq.rear_size < write_sq.block_size && | ||
1214 | !write_sq.syncing) { | ||
1215 | /* hmmm, there were two frames, but the second | ||
1216 | * one is not yet filled and we're not syncing? | ||
1217 | */ | ||
1218 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1219 | return; | ||
1220 | } | ||
1221 | AtaPlayNextFrame(2); | ||
1222 | } else { | ||
1223 | /* there's already a frame being played so we may only stuff | ||
1224 | * one new into the DMA, but even if this may be the last | ||
1225 | * frame existing the previous one is still on write_sq.count. | ||
1226 | */ | ||
1227 | if (write_sq.count == 2 && | ||
1228 | write_sq.rear_size < write_sq.block_size && | ||
1229 | !write_sq.syncing) { | ||
1230 | /* hmmm, the only existing frame is not | ||
1231 | * yet filled and we're not syncing? | ||
1232 | */ | ||
1233 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1234 | return; | ||
1235 | } | ||
1236 | AtaPlayNextFrame(2); | ||
1237 | } | ||
1238 | atari_enable_irq(IRQ_MFP_TIMA); | ||
1239 | } | ||
1240 | |||
1241 | |||
1242 | static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp) | ||
1243 | { | ||
1244 | #if 0 | ||
1245 | /* ++TeSche: if you should want to test this... */ | ||
1246 | static int cnt; | ||
1247 | if (write_sq.active == 2) | ||
1248 | if (++cnt == 10) { | ||
1249 | /* simulate losing an interrupt */ | ||
1250 | cnt = 0; | ||
1251 | return IRQ_HANDLED; | ||
1252 | } | ||
1253 | #endif | ||
1254 | spin_lock(&dmasound.lock); | ||
1255 | if (write_sq_ignore_int && is_falcon) { | ||
1256 | /* ++TeSche: Falcon only: ignore first irq because it comes | ||
1257 | * immediately after starting a frame. after that, irqs come | ||
1258 | * (almost) like on the TT. | ||
1259 | */ | ||
1260 | write_sq_ignore_int = 0; | ||
1261 | return IRQ_HANDLED; | ||
1262 | } | ||
1263 | |||
1264 | if (!write_sq.active) { | ||
1265 | /* playing was interrupted and sq_reset() has already cleared | ||
1266 | * the sq variables, so better don't do anything here. | ||
1267 | */ | ||
1268 | WAKE_UP(write_sq.sync_queue); | ||
1269 | return IRQ_HANDLED; | ||
1270 | } | ||
1271 | |||
1272 | /* Probably ;) one frame is finished. Well, in fact it may be that a | ||
1273 | * pre-programmed one is also finished because there has been a long | ||
1274 | * delay in interrupt delivery and we've completely lost one, but | ||
1275 | * there's no way to detect such a situation. In such a case the last | ||
1276 | * frame will be played more than once and the situation will recover | ||
1277 | * as soon as the irq gets through. | ||
1278 | */ | ||
1279 | write_sq.count--; | ||
1280 | write_sq.active--; | ||
1281 | |||
1282 | if (!write_sq.active) { | ||
1283 | tt_dmasnd.ctrl = DMASND_CTRL_OFF; | ||
1284 | write_sq_ignore_int = 1; | ||
1285 | } | ||
1286 | |||
1287 | WAKE_UP(write_sq.action_queue); | ||
1288 | /* At least one block of the queue is free now | ||
1289 | so wake up a writing process blocked because | ||
1290 | of a full queue. */ | ||
1291 | |||
1292 | if ((write_sq.active != 1) || (write_sq.count != 1)) | ||
1293 | /* We must be a bit carefully here: write_sq.count indicates the | ||
1294 | * number of buffers used and not the number of frames to be | ||
1295 | * played. If write_sq.count==1 and write_sq.active==1 that | ||
1296 | * means the only remaining frame was already programmed | ||
1297 | * earlier (and is currently running) so we mustn't call | ||
1298 | * AtaPlay() here, otherwise we'll play one frame too much. | ||
1299 | */ | ||
1300 | AtaPlay(); | ||
1301 | |||
1302 | if (!write_sq.active) WAKE_UP(write_sq.sync_queue); | ||
1303 | /* We are not playing after AtaPlay(), so there | ||
1304 | is nothing to play any more. Wake up a process | ||
1305 | waiting for audio output to drain. */ | ||
1306 | spin_unlock(&dmasound.lock); | ||
1307 | return IRQ_HANDLED; | ||
1308 | } | ||
1309 | |||
1310 | |||
1311 | /*** Mid level stuff *********************************************************/ | ||
1312 | |||
1313 | |||
1314 | /* | ||
1315 | * /dev/mixer abstraction | ||
1316 | */ | ||
1317 | |||
1318 | #define RECLEVEL_VOXWARE_TO_GAIN(v) \ | ||
1319 | ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) | ||
1320 | #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) | ||
1321 | |||
1322 | |||
1323 | static void __init TTMixerInit(void) | ||
1324 | { | ||
1325 | atari_microwire_cmd(MW_LM1992_VOLUME(0)); | ||
1326 | dmasound.volume_left = 0; | ||
1327 | atari_microwire_cmd(MW_LM1992_BALLEFT(0)); | ||
1328 | dmasound.volume_right = 0; | ||
1329 | atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); | ||
1330 | atari_microwire_cmd(MW_LM1992_TREBLE(0)); | ||
1331 | atari_microwire_cmd(MW_LM1992_BASS(0)); | ||
1332 | } | ||
1333 | |||
1334 | static void __init FalconMixerInit(void) | ||
1335 | { | ||
1336 | dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; | ||
1337 | dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; | ||
1338 | } | ||
1339 | |||
1340 | static int AtaMixerIoctl(u_int cmd, u_long arg) | ||
1341 | { | ||
1342 | int data; | ||
1343 | unsigned long flags; | ||
1344 | switch (cmd) { | ||
1345 | case SOUND_MIXER_READ_SPEAKER: | ||
1346 | if (is_falcon || MACH_IS_TT) { | ||
1347 | int porta; | ||
1348 | spin_lock_irqsave(&dmasound.lock, flags); | ||
1349 | sound_ym.rd_data_reg_sel = 14; | ||
1350 | porta = sound_ym.rd_data_reg_sel; | ||
1351 | spin_unlock_irqrestore(&dmasound.lock, flags); | ||
1352 | return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100); | ||
1353 | } | ||
1354 | break; | ||
1355 | case SOUND_MIXER_WRITE_VOLUME: | ||
1356 | IOCTL_IN(arg, data); | ||
1357 | return IOCTL_OUT(arg, dmasound_set_volume(data)); | ||
1358 | case SOUND_MIXER_WRITE_SPEAKER: | ||
1359 | if (is_falcon || MACH_IS_TT) { | ||
1360 | int porta; | ||
1361 | IOCTL_IN(arg, data); | ||
1362 | spin_lock_irqsave(&dmasound.lock, flags); | ||
1363 | sound_ym.rd_data_reg_sel = 14; | ||
1364 | porta = (sound_ym.rd_data_reg_sel & ~0x40) | | ||
1365 | (data < 50 ? 0x40 : 0); | ||
1366 | sound_ym.wd_data = porta; | ||
1367 | spin_unlock_irqrestore(&dmasound.lock, flags); | ||
1368 | return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100); | ||
1369 | } | ||
1370 | } | ||
1371 | return -EINVAL; | ||
1372 | } | ||
1373 | |||
1374 | |||
1375 | static int TTMixerIoctl(u_int cmd, u_long arg) | ||
1376 | { | ||
1377 | int data; | ||
1378 | switch (cmd) { | ||
1379 | case SOUND_MIXER_READ_RECMASK: | ||
1380 | return IOCTL_OUT(arg, 0); | ||
1381 | case SOUND_MIXER_READ_DEVMASK: | ||
1382 | return IOCTL_OUT(arg, | ||
1383 | SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | | ||
1384 | (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)); | ||
1385 | case SOUND_MIXER_READ_STEREODEVS: | ||
1386 | return IOCTL_OUT(arg, SOUND_MASK_VOLUME); | ||
1387 | case SOUND_MIXER_READ_VOLUME: | ||
1388 | return IOCTL_OUT(arg, | ||
1389 | VOLUME_DB_TO_VOXWARE(dmasound.volume_left) | | ||
1390 | (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8)); | ||
1391 | case SOUND_MIXER_READ_BASS: | ||
1392 | return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass)); | ||
1393 | case SOUND_MIXER_READ_TREBLE: | ||
1394 | return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble)); | ||
1395 | case SOUND_MIXER_READ_OGAIN: | ||
1396 | return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain)); | ||
1397 | case SOUND_MIXER_WRITE_BASS: | ||
1398 | IOCTL_IN(arg, data); | ||
1399 | return IOCTL_OUT(arg, dmasound_set_bass(data)); | ||
1400 | case SOUND_MIXER_WRITE_TREBLE: | ||
1401 | IOCTL_IN(arg, data); | ||
1402 | return IOCTL_OUT(arg, dmasound_set_treble(data)); | ||
1403 | case SOUND_MIXER_WRITE_OGAIN: | ||
1404 | IOCTL_IN(arg, data); | ||
1405 | return IOCTL_OUT(arg, dmasound_set_gain(data)); | ||
1406 | } | ||
1407 | return AtaMixerIoctl(cmd, arg); | ||
1408 | } | ||
1409 | |||
1410 | static int FalconMixerIoctl(u_int cmd, u_long arg) | ||
1411 | { | ||
1412 | int data; | ||
1413 | switch (cmd) { | ||
1414 | case SOUND_MIXER_READ_RECMASK: | ||
1415 | return IOCTL_OUT(arg, SOUND_MASK_MIC); | ||
1416 | case SOUND_MIXER_READ_DEVMASK: | ||
1417 | return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER); | ||
1418 | case SOUND_MIXER_READ_STEREODEVS: | ||
1419 | return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC); | ||
1420 | case SOUND_MIXER_READ_VOLUME: | ||
1421 | return IOCTL_OUT(arg, | ||
1422 | VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) | | ||
1423 | VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8); | ||
1424 | case SOUND_MIXER_READ_CAPS: | ||
1425 | return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT); | ||
1426 | case SOUND_MIXER_WRITE_MIC: | ||
1427 | IOCTL_IN(arg, data); | ||
1428 | tt_dmasnd.input_gain = | ||
1429 | RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | | ||
1430 | RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); | ||
1431 | /* fall thru, return set value */ | ||
1432 | case SOUND_MIXER_READ_MIC: | ||
1433 | return IOCTL_OUT(arg, | ||
1434 | RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | | ||
1435 | RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8); | ||
1436 | } | ||
1437 | return AtaMixerIoctl(cmd, arg); | ||
1438 | } | ||
1439 | |||
1440 | static int AtaWriteSqSetup(void) | ||
1441 | { | ||
1442 | write_sq_ignore_int = 0; | ||
1443 | return 0 ; | ||
1444 | } | ||
1445 | |||
1446 | static int AtaSqOpen(mode_t mode) | ||
1447 | { | ||
1448 | write_sq_ignore_int = 1; | ||
1449 | return 0 ; | ||
1450 | } | ||
1451 | |||
1452 | static int TTStateInfo(char *buffer, size_t space) | ||
1453 | { | ||
1454 | int len = 0; | ||
1455 | len += sprintf(buffer+len, "\tvol left %ddB [-40... 0]\n", | ||
1456 | dmasound.volume_left); | ||
1457 | len += sprintf(buffer+len, "\tvol right %ddB [-40... 0]\n", | ||
1458 | dmasound.volume_right); | ||
1459 | len += sprintf(buffer+len, "\tbass %ddB [-12...+12]\n", | ||
1460 | dmasound.bass); | ||
1461 | len += sprintf(buffer+len, "\ttreble %ddB [-12...+12]\n", | ||
1462 | dmasound.treble); | ||
1463 | if (len >= space) { | ||
1464 | printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; | ||
1465 | len = space ; | ||
1466 | } | ||
1467 | return len; | ||
1468 | } | ||
1469 | |||
1470 | static int FalconStateInfo(char *buffer, size_t space) | ||
1471 | { | ||
1472 | int len = 0; | ||
1473 | len += sprintf(buffer+len, "\tvol left %ddB [-22.5 ... 0]\n", | ||
1474 | dmasound.volume_left); | ||
1475 | len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n", | ||
1476 | dmasound.volume_right); | ||
1477 | if (len >= space) { | ||
1478 | printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; | ||
1479 | len = space ; | ||
1480 | } | ||
1481 | return len; | ||
1482 | } | ||
1483 | |||
1484 | |||
1485 | /*** Machine definitions *****************************************************/ | ||
1486 | |||
1487 | static SETTINGS def_hard_falcon = { | ||
1488 | .format = AFMT_S8, | ||
1489 | .stereo = 0, | ||
1490 | .size = 8, | ||
1491 | .speed = 8195 | ||
1492 | } ; | ||
1493 | |||
1494 | static SETTINGS def_hard_tt = { | ||
1495 | .format = AFMT_S8, | ||
1496 | .stereo = 0, | ||
1497 | .size = 8, | ||
1498 | .speed = 12517 | ||
1499 | } ; | ||
1500 | |||
1501 | static SETTINGS def_soft = { | ||
1502 | .format = AFMT_U8, | ||
1503 | .stereo = 0, | ||
1504 | .size = 8, | ||
1505 | .speed = 8000 | ||
1506 | } ; | ||
1507 | |||
1508 | static MACHINE machTT = { | ||
1509 | .name = "Atari", | ||
1510 | .name2 = "TT", | ||
1511 | .owner = THIS_MODULE, | ||
1512 | .dma_alloc = AtaAlloc, | ||
1513 | .dma_free = AtaFree, | ||
1514 | .irqinit = AtaIrqInit, | ||
1515 | #ifdef MODULE | ||
1516 | .irqcleanup = AtaIrqCleanUp, | ||
1517 | #endif /* MODULE */ | ||
1518 | .init = TTInit, | ||
1519 | .silence = TTSilence, | ||
1520 | .setFormat = TTSetFormat, | ||
1521 | .setVolume = TTSetVolume, | ||
1522 | .setBass = AtaSetBass, | ||
1523 | .setTreble = AtaSetTreble, | ||
1524 | .setGain = TTSetGain, | ||
1525 | .play = AtaPlay, | ||
1526 | .mixer_init = TTMixerInit, | ||
1527 | .mixer_ioctl = TTMixerIoctl, | ||
1528 | .write_sq_setup = AtaWriteSqSetup, | ||
1529 | .sq_open = AtaSqOpen, | ||
1530 | .state_info = TTStateInfo, | ||
1531 | .min_dsp_speed = 6258, | ||
1532 | .version = ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), | ||
1533 | .hardware_afmts = AFMT_S8, /* h'ware-supported formats *only* here */ | ||
1534 | .capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ | ||
1535 | }; | ||
1536 | |||
1537 | static MACHINE machFalcon = { | ||
1538 | .name = "Atari", | ||
1539 | .name2 = "FALCON", | ||
1540 | .dma_alloc = AtaAlloc, | ||
1541 | .dma_free = AtaFree, | ||
1542 | .irqinit = AtaIrqInit, | ||
1543 | #ifdef MODULE | ||
1544 | .irqcleanup = AtaIrqCleanUp, | ||
1545 | #endif /* MODULE */ | ||
1546 | .init = FalconInit, | ||
1547 | .silence = FalconSilence, | ||
1548 | .setFormat = FalconSetFormat, | ||
1549 | .setVolume = FalconSetVolume, | ||
1550 | .setBass = AtaSetBass, | ||
1551 | .setTreble = AtaSetTreble, | ||
1552 | .play = AtaPlay, | ||
1553 | .mixer_init = FalconMixerInit, | ||
1554 | .mixer_ioctl = FalconMixerIoctl, | ||
1555 | .write_sq_setup = AtaWriteSqSetup, | ||
1556 | .sq_open = AtaSqOpen, | ||
1557 | .state_info = FalconStateInfo, | ||
1558 | .min_dsp_speed = 8195, | ||
1559 | .version = ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), | ||
1560 | .hardware_afmts = (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */ | ||
1561 | .capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ | ||
1562 | }; | ||
1563 | |||
1564 | |||
1565 | /*** Config & Setup **********************************************************/ | ||
1566 | |||
1567 | |||
1568 | static int __init dmasound_atari_init(void) | ||
1569 | { | ||
1570 | if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) { | ||
1571 | if (ATARIHW_PRESENT(CODEC)) { | ||
1572 | dmasound.mach = machFalcon; | ||
1573 | dmasound.mach.default_soft = def_soft ; | ||
1574 | dmasound.mach.default_hard = def_hard_falcon ; | ||
1575 | is_falcon = 1; | ||
1576 | } else if (ATARIHW_PRESENT(MICROWIRE)) { | ||
1577 | dmasound.mach = machTT; | ||
1578 | dmasound.mach.default_soft = def_soft ; | ||
1579 | dmasound.mach.default_hard = def_hard_tt ; | ||
1580 | is_falcon = 0; | ||
1581 | } else | ||
1582 | return -ENODEV; | ||
1583 | if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) | ||
1584 | return dmasound_init(); | ||
1585 | else { | ||
1586 | printk("DMA sound driver: Timer A interrupt already in use\n"); | ||
1587 | return -EBUSY; | ||
1588 | } | ||
1589 | } | ||
1590 | return -ENODEV; | ||
1591 | } | ||
1592 | |||
1593 | static void __exit dmasound_atari_cleanup(void) | ||
1594 | { | ||
1595 | dmasound_deinit(); | ||
1596 | } | ||
1597 | |||
1598 | module_init(dmasound_atari_init); | ||
1599 | module_exit(dmasound_atari_cleanup); | ||
1600 | MODULE_LICENSE("GPL"); | ||