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