Commit | Line | Data |
---|---|---|
1da177e4 LT |
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"); |