1624 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/sound/oss/dmasound/dmasound_atari.c4 *5 * Atari TT and Falcon DMA Sound Driver6 *7 * See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits8 * prior to 28/01/20019 *10 * 28/01/2001 [0.1] Iain Sandoe11 * - added versioning12 * - 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 26#include <linux/uaccess.h>27#include <asm/atariints.h>28#include <asm/atari_stram.h>29 30#include "dmasound.h"31 32#define DMASOUND_ATARI_REVISION 033#define DMASOUND_ATARI_EDITION 334 35extern void atari_microwire_cmd(int cmd);36 37static int is_falcon;38static int write_sq_ignore_int; /* ++TeSche: used for Falcon */39 40static int expand_bal; /* Balance factor for expanding (not volume!) */41static 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 samples50 * from user space into our buffer at the right frequency. They take care about51 * how much data there's actually to read, how much buffer space there is and52 * to convert samples into the right frequency/encoding. They will only work on53 * complete samples so it may happen they leave some bytes in the input stream54 * if the user didn't write a multiple of the current sample size. They both55 * return the number of bytes they've used from both streams so you may detect56 * 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, all59 * variables should fit in registers and the loops are really short. There's60 * one loop for every possible situation. Writing a more generalized and thus61 * parameterized loop would only produce slower code. Feel free to optimize62 * this in assembler if you like. :)63 *64 * I think these routines belong here because they're not yet really hardware65 * independent, especially the fact that the Falcon can play 16bit samples66 * only in stereo is hardcoded in both of them!67 *68 * ++geert: split in even more functions (one per format)69 */70 71static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount,72 u_char frame[], ssize_t *frameUsed,73 ssize_t frameLeft);74static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount,75 u_char frame[], ssize_t *frameUsed,76 ssize_t frameLeft);77static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount,78 u_char frame[], ssize_t *frameUsed,79 ssize_t frameLeft);80static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount,81 u_char frame[], ssize_t *frameUsed,82 ssize_t frameLeft);83static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount,84 u_char frame[], ssize_t *frameUsed,85 ssize_t frameLeft);86static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount,87 u_char frame[], ssize_t *frameUsed,88 ssize_t frameLeft);89static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount,90 u_char frame[], ssize_t *frameUsed,91 ssize_t frameLeft);92static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount,93 u_char frame[], ssize_t *frameUsed,94 ssize_t frameLeft);95static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount,96 u_char frame[], ssize_t *frameUsed,97 ssize_t frameLeft);98static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount,99 u_char frame[], ssize_t *frameUsed,100 ssize_t frameLeft);101static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount,102 u_char frame[], ssize_t *frameUsed,103 ssize_t frameLeft);104static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount,105 u_char frame[], ssize_t *frameUsed,106 ssize_t frameLeft);107static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount,108 u_char frame[], ssize_t *frameUsed,109 ssize_t frameLeft);110static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount,111 u_char frame[], ssize_t *frameUsed,112 ssize_t frameLeft);113 114 115/*** Low level stuff *********************************************************/116 117 118static void *AtaAlloc(unsigned int size, gfp_t flags);119static void AtaFree(void *, unsigned int size);120static int AtaIrqInit(void);121#ifdef MODULE122static void AtaIrqCleanUp(void);123#endif /* MODULE */124static int AtaSetBass(int bass);125static int AtaSetTreble(int treble);126static void TTSilence(void);127static void TTInit(void);128static int TTSetFormat(int format);129static int TTSetVolume(int volume);130static int TTSetGain(int gain);131static void FalconSilence(void);132static void FalconInit(void);133static int FalconSetFormat(int format);134static int FalconSetVolume(int volume);135static void AtaPlayNextFrame(int index);136static void AtaPlay(void);137static irqreturn_t AtaInterrupt(int irq, void *dummy);138 139/*** Mid level stuff *********************************************************/140 141static void TTMixerInit(void);142static void FalconMixerInit(void);143static int AtaMixerIoctl(u_int cmd, u_long arg);144static int TTMixerIoctl(u_int cmd, u_long arg);145static int FalconMixerIoctl(u_int cmd, u_long arg);146static int AtaWriteSqSetup(void);147static int AtaSqOpen(fmode_t mode);148static int TTStateInfo(char *buffer, size_t space);149static int FalconStateInfo(char *buffer, size_t space);150 151 152/*** Translations ************************************************************/153 154 155static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount,156 u_char frame[], ssize_t *frameUsed,157 ssize_t frameLeft)158{159 char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8160 : 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 180static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount,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 198static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount,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;221 if (get_user(data, (u_short __user *)userPtr))222 return -EFAULT;223 userPtr += 2;224 *p++ = data ^ 0x8080;225 count--;226 }227 }228 *frameUsed += used;229 return used;230}231 232 233static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount,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;245 if (get_user(data, (u_short __user *)userPtr))246 return -EFAULT;247 userPtr += 2;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 265static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount,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;277 if (get_user(data, (u_short __user *)userPtr))278 return -EFAULT;279 userPtr += 2;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) {291 u_int data;292 if (get_user(data, (u_int __user *)userPtr))293 return -EFAULT;294 userPtr += 4;295 *p++ = data ^ 0x80008000;296 count--;297 }298 *frameUsed += used;299 }300 return used;301}302 303 304static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount,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;317 if (get_user(data, (u_short __user *)userPtr))318 return -EFAULT;319 userPtr += 2;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;332 if (get_user(data, (u_int __user *)userPtr))333 return -EFAULT;334 userPtr += 4;335 data = le2be16dbl(data);336 *p++ = data;337 count--;338 }339 *frameUsed += used;340 }341 return used;342}343 344 345static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount,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;358 if (get_user(data, (u_short __user *)userPtr))359 return -EFAULT;360 userPtr += 2;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;372 if (get_user(data, (u_int __user *)userPtr))373 return -EFAULT;374 userPtr += 4;375 data = le2be16dbl(data) ^ 0x80008000;376 *p++ = data;377 count--;378 }379 *frameUsed += used;380 }381 return used;382}383 384 385static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount,386 u_char frame[], ssize_t *frameUsed,387 ssize_t frameLeft)388{389 char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8390 : 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 447static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount,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;482 if (get_user(data, (u_short __user *)userPtr))483 return -EFAULT;484 userPtr += 2;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 501static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount,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;537 if (get_user(data, (u_short __user *)userPtr))538 return -EFAULT;539 userPtr += 2;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 557static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount,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;575 if (get_user(data, (u_short __user *)userPtr))576 return -EFAULT;577 userPtr += 2;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;594 if (get_user(data, (u_int __user *)userPtr))595 return -EFAULT;596 userPtr += 4;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 613static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount,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;631 if (get_user(data, (u_short __user *)userPtr))632 return -EFAULT;633 userPtr += 2;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;651 if (get_user(data, (u_int __user *)userPtr))652 return -EFAULT;653 userPtr += 4;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 671static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount,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;689 if (get_user(data, (u_short __user *)userPtr))690 return -EFAULT;691 userPtr += 2;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;709 if (get_user(data, (u_int __user *)userPtr))710 return -EFAULT;711 userPtr += 4;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 729static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount,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;747 if (get_user(data, (u_short __user *)userPtr))748 return -EFAULT;749 userPtr += 2;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;767 if (get_user(data, (u_int __user *)userPtr))768 return -EFAULT;769 userPtr += 4;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 787static 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 794static 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 801static 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_u16le810};811 812static 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 832static void *AtaAlloc(unsigned int size, gfp_t flags)833{834 return atari_stram_alloc(size, "dmasound");835}836 837static void AtaFree(void *obj, unsigned int size)838{839 atari_stram_free( obj );840}841 842static int __init AtaIrqInit(void)843{844 /* Set up timer A. Timer A845 will receive a signal upon end of playing from the sound846 hardware. Furthermore Timer A is able to count events847 and will cause an interrupt after a programmed number848 of events. So all we need to keep the music playing is849 to provide the sound hardware with new data upon850 an interrupt from timer A. */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. */854 /* Register interrupt handler. */855 if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, 0, "DMA sound",856 AtaInterrupt))857 return 0;858 st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */859 st_mfp.int_mk_a |= 0x20;860 return 1;861}862 863#ifdef MODULE864static void AtaIrqCleanUp(void)865{866 st_mfp.tim_ct_a = 0; /* stop timer */867 st_mfp.int_en_a &= ~0x20; /* turn interrupt off */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 878static 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 886static 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 * TT897 */898 899 900static 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 907static 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, but917 * 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 } else925 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 957static 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 990static 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 1005static 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 * Falcon1016 */1017 1018 1019static 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 1033static 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%) would1043 * be playable without expanding, but that now a kernel runtime1044 * option1045 */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 } else1052 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 1113static 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 1159static 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 1169static void AtaPlayNextFrame(int index)1170{1171 char *start, *end;1172 1173 /* used by AtaPlay() if all doubts whether there really is something1174 * 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_size1178 : 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 can1183 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 1190static void AtaPlay(void)1191{1192 /* ++TeSche: Note that write_sq.active is no longer just a flag but1193 * holds the number of frames the DMA is currently programmed for1194 * 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 more1197 * subtle again so now I must admit I also prefer disabling the irq1198 * here rather than considering all possible situations. But the point1199 * is that disabling the irq doesn't have any bad influence on this1200 * version of the driver as we benefit from having pre-programmed the1201 * DMA wherever possible: There's no need to reload the DMA at the1202 * exact time of an interrupt but only at some time while the1203 * 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 try1215 * 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 not1221 * 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 second1236 * 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 stuff1244 * one new into the DMA, but even if this may be the last1245 * 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 not1251 * 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 1262static irqreturn_t AtaInterrupt(int irq, void *dummy)1263{1264#if 01265 /* ++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#endif1274 spin_lock(&dmasound.lock);1275 if (write_sq_ignore_int && is_falcon) {1276 /* ++TeSche: Falcon only: ignore first irq because it comes1277 * immediately after starting a frame. after that, irqs come1278 * (almost) like on the TT.1279 */1280 write_sq_ignore_int = 0;1281 goto out;1282 }1283 1284 if (!write_sq.active) {1285 /* playing was interrupted and sq_reset() has already cleared1286 * the sq variables, so better don't do anything here.1287 */1288 WAKE_UP(write_sq.sync_queue);1289 goto out;1290 }1291 1292 /* Probably ;) one frame is finished. Well, in fact it may be that a1293 * pre-programmed one is also finished because there has been a long1294 * delay in interrupt delivery and we've completely lost one, but1295 * there's no way to detect such a situation. In such a case the last1296 * frame will be played more than once and the situation will recover1297 * 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 now1309 so wake up a writing process blocked because1310 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 the1314 * number of buffers used and not the number of frames to be1315 * played. If write_sq.count==1 and write_sq.active==1 that1316 * means the only remaining frame was already programmed1317 * earlier (and is currently running) so we mustn't call1318 * 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 there1324 is nothing to play any more. Wake up a process1325 waiting for audio output to drain. */1326out:1327 spin_unlock(&dmasound.lock);1328 return IRQ_HANDLED;1329}1330 1331 1332/*** Mid level stuff *********************************************************/1333 1334 1335/*1336 * /dev/mixer abstraction1337 */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 1344static 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 1355static 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 1361static 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 1396static 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 1431static int FalconMixerIoctl(u_int cmd, u_long arg)1432{1433 int data;1434 switch (cmd) {1435 case SOUND_MIXER_READ_RECMASK:1436 return IOCTL_OUT(arg, SOUND_MASK_MIC);1437 case SOUND_MIXER_READ_DEVMASK:1438 return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);1439 case SOUND_MIXER_READ_STEREODEVS:1440 return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);1441 case SOUND_MIXER_READ_VOLUME:1442 return IOCTL_OUT(arg,1443 VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |1444 VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);1445 case SOUND_MIXER_READ_CAPS:1446 return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);1447 case SOUND_MIXER_WRITE_MIC: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);1452 fallthrough; /* return set value */1453 case SOUND_MIXER_READ_MIC: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 1461static int AtaWriteSqSetup(void)1462{1463 write_sq_ignore_int = 0;1464 return 0 ;1465}1466 1467static int AtaSqOpen(fmode_t mode)1468{1469 write_sq_ignore_int = 1;1470 return 0 ;1471}1472 1473static 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 1491static 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 1508static SETTINGS def_hard_falcon = {1509 .format = AFMT_S8,1510 .stereo = 0,1511 .size = 8,1512 .speed = 81951513} ;1514 1515static SETTINGS def_hard_tt = {1516 .format = AFMT_S8,1517 .stereo = 0,1518 .size = 8,1519 .speed = 125171520} ;1521 1522static SETTINGS def_soft = {1523 .format = AFMT_U8,1524 .stereo = 0,1525 .size = 8,1526 .speed = 80001527} ;1528 1529static __initdata MACHINE machTT = {1530 .name = "Atari",1531 .name2 = "TT",1532 .owner = THIS_MODULE,1533 .dma_alloc = AtaAlloc,1534 .dma_free = AtaFree,1535 .irqinit = AtaIrqInit,1536#ifdef MODULE1537 .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 1558static __initdata MACHINE machFalcon = {1559 .name = "Atari",1560 .name2 = "FALCON",1561 .dma_alloc = AtaAlloc,1562 .dma_free = AtaFree,1563 .irqinit = AtaIrqInit,1564#ifdef MODULE1565 .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 1589static 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 } else1603 return -ENODEV;1604 if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0)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 1614static void __exit dmasound_atari_cleanup(void)1615{1616 dmasound_deinit();1617}1618 1619module_init(dmasound_atari_init);1620module_exit(dmasound_atari_cleanup);1621 1622MODULE_DESCRIPTION("Atari TT and Falcon DMA Sound Driver");1623MODULE_LICENSE("GPL");1624