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