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