Path: blob/master/sound/oss/dmasound/dmasound_atari.c
10817 views
/*1* linux/sound/oss/dmasound/dmasound_atari.c2*3* Atari TT and Falcon DMA Sound Driver4*5* See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits6* prior to 28/01/20017*8* 28/01/2001 [0.1] Iain Sandoe9* - added versioning10* - put in and populated the hardware_afmts field.11* [0.2] - put in SNDCTL_DSP_GETCAPS value.12* 01/02/2001 [0.3] - put in default hard/soft settings.13*/141516#include <linux/module.h>17#include <linux/kernel.h>18#include <linux/init.h>19#include <linux/soundcard.h>20#include <linux/mm.h>21#include <linux/spinlock.h>22#include <linux/interrupt.h>2324#include <asm/uaccess.h>25#include <asm/atariints.h>26#include <asm/atari_stram.h>2728#include "dmasound.h"2930#define DMASOUND_ATARI_REVISION 031#define DMASOUND_ATARI_EDITION 33233extern void atari_microwire_cmd(int cmd);3435static int is_falcon;36static int write_sq_ignore_int; /* ++TeSche: used for Falcon */3738static int expand_bal; /* Balance factor for expanding (not volume!) */39static int expand_data; /* Data for expanding */404142/*** Translations ************************************************************/434445/* ++TeSche: radically changed for new expanding purposes...46*47* These two routines now deal with copying/expanding/translating the samples48* from user space into our buffer at the right frequency. They take care about49* how much data there's actually to read, how much buffer space there is and50* to convert samples into the right frequency/encoding. They will only work on51* complete samples so it may happen they leave some bytes in the input stream52* if the user didn't write a multiple of the current sample size. They both53* return the number of bytes they've used from both streams so you may detect54* such a situation. Luckily all programs should be able to cope with that.55*56* I think I've optimized anything as far as one can do in plain C, all57* variables should fit in registers and the loops are really short. There's58* one loop for every possible situation. Writing a more generalized and thus59* parameterized loop would only produce slower code. Feel free to optimize60* this in assembler if you like. :)61*62* I think these routines belong here because they're not yet really hardware63* independent, especially the fact that the Falcon can play 16bit samples64* only in stereo is hardcoded in both of them!65*66* ++geert: split in even more functions (one per format)67*/6869static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount,70u_char frame[], ssize_t *frameUsed,71ssize_t frameLeft);72static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount,73u_char frame[], ssize_t *frameUsed,74ssize_t frameLeft);75static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount,76u_char frame[], ssize_t *frameUsed,77ssize_t frameLeft);78static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount,79u_char frame[], ssize_t *frameUsed,80ssize_t frameLeft);81static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount,82u_char frame[], ssize_t *frameUsed,83ssize_t frameLeft);84static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount,85u_char frame[], ssize_t *frameUsed,86ssize_t frameLeft);87static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount,88u_char frame[], ssize_t *frameUsed,89ssize_t frameLeft);90static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount,91u_char frame[], ssize_t *frameUsed,92ssize_t frameLeft);93static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount,94u_char frame[], ssize_t *frameUsed,95ssize_t frameLeft);96static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount,97u_char frame[], ssize_t *frameUsed,98ssize_t frameLeft);99static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount,100u_char frame[], ssize_t *frameUsed,101ssize_t frameLeft);102static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount,103u_char frame[], ssize_t *frameUsed,104ssize_t frameLeft);105static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount,106u_char frame[], ssize_t *frameUsed,107ssize_t frameLeft);108static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount,109u_char frame[], ssize_t *frameUsed,110ssize_t frameLeft);111112113/*** Low level stuff *********************************************************/114115116static void *AtaAlloc(unsigned int size, gfp_t flags);117static void AtaFree(void *, unsigned int size);118static int AtaIrqInit(void);119#ifdef MODULE120static void AtaIrqCleanUp(void);121#endif /* MODULE */122static int AtaSetBass(int bass);123static int AtaSetTreble(int treble);124static void TTSilence(void);125static void TTInit(void);126static int TTSetFormat(int format);127static int TTSetVolume(int volume);128static int TTSetGain(int gain);129static void FalconSilence(void);130static void FalconInit(void);131static int FalconSetFormat(int format);132static int FalconSetVolume(int volume);133static void AtaPlayNextFrame(int index);134static void AtaPlay(void);135static irqreturn_t AtaInterrupt(int irq, void *dummy);136137/*** Mid level stuff *********************************************************/138139static void TTMixerInit(void);140static void FalconMixerInit(void);141static int AtaMixerIoctl(u_int cmd, u_long arg);142static int TTMixerIoctl(u_int cmd, u_long arg);143static int FalconMixerIoctl(u_int cmd, u_long arg);144static int AtaWriteSqSetup(void);145static int AtaSqOpen(fmode_t mode);146static int TTStateInfo(char *buffer, size_t space);147static int FalconStateInfo(char *buffer, size_t space);148149150/*** Translations ************************************************************/151152153static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount,154u_char frame[], ssize_t *frameUsed,155ssize_t frameLeft)156{157char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8158: dmasound_alaw2dma8;159ssize_t count, used;160u_char *p = &frame[*frameUsed];161162count = min_t(unsigned long, userCount, frameLeft);163if (dmasound.soft.stereo)164count &= ~1;165used = count;166while (count > 0) {167u_char data;168if (get_user(data, userPtr++))169return -EFAULT;170*p++ = table[data];171count--;172}173*frameUsed += used;174return used;175}176177178static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount,179u_char frame[], ssize_t *frameUsed,180ssize_t frameLeft)181{182ssize_t count, used;183void *p = &frame[*frameUsed];184185count = min_t(unsigned long, userCount, frameLeft);186if (dmasound.soft.stereo)187count &= ~1;188used = count;189if (copy_from_user(p, userPtr, count))190return -EFAULT;191*frameUsed += used;192return used;193}194195196static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount,197u_char frame[], ssize_t *frameUsed,198ssize_t frameLeft)199{200ssize_t count, used;201202if (!dmasound.soft.stereo) {203u_char *p = &frame[*frameUsed];204count = min_t(unsigned long, userCount, frameLeft);205used = count;206while (count > 0) {207u_char data;208if (get_user(data, userPtr++))209return -EFAULT;210*p++ = data ^ 0x80;211count--;212}213} else {214u_short *p = (u_short *)&frame[*frameUsed];215count = min_t(unsigned long, userCount, frameLeft)>>1;216used = count*2;217while (count > 0) {218u_short data;219if (get_user(data, (u_short __user *)userPtr))220return -EFAULT;221userPtr += 2;222*p++ = data ^ 0x8080;223count--;224}225}226*frameUsed += used;227return used;228}229230231static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount,232u_char frame[], ssize_t *frameUsed,233ssize_t frameLeft)234{235ssize_t count, used;236237if (!dmasound.soft.stereo) {238u_short *p = (u_short *)&frame[*frameUsed];239count = min_t(unsigned long, userCount, frameLeft)>>1;240used = count*2;241while (count > 0) {242u_short data;243if (get_user(data, (u_short __user *)userPtr))244return -EFAULT;245userPtr += 2;246*p++ = data;247*p++ = data;248count--;249}250*frameUsed += used*2;251} else {252void *p = (u_short *)&frame[*frameUsed];253count = min_t(unsigned long, userCount, frameLeft) & ~3;254used = count;255if (copy_from_user(p, userPtr, count))256return -EFAULT;257*frameUsed += used;258}259return used;260}261262263static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount,264u_char frame[], ssize_t *frameUsed,265ssize_t frameLeft)266{267ssize_t count, used;268269if (!dmasound.soft.stereo) {270u_short *p = (u_short *)&frame[*frameUsed];271count = min_t(unsigned long, userCount, frameLeft)>>1;272used = count*2;273while (count > 0) {274u_short data;275if (get_user(data, (u_short __user *)userPtr))276return -EFAULT;277userPtr += 2;278data ^= 0x8000;279*p++ = data;280*p++ = data;281count--;282}283*frameUsed += used*2;284} else {285u_long *p = (u_long *)&frame[*frameUsed];286count = min_t(unsigned long, userCount, frameLeft)>>2;287used = count*4;288while (count > 0) {289u_int data;290if (get_user(data, (u_int __user *)userPtr))291return -EFAULT;292userPtr += 4;293*p++ = data ^ 0x80008000;294count--;295}296*frameUsed += used;297}298return used;299}300301302static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount,303u_char frame[], ssize_t *frameUsed,304ssize_t frameLeft)305{306ssize_t count, used;307308count = frameLeft;309if (!dmasound.soft.stereo) {310u_short *p = (u_short *)&frame[*frameUsed];311count = min_t(unsigned long, userCount, frameLeft)>>1;312used = count*2;313while (count > 0) {314u_short data;315if (get_user(data, (u_short __user *)userPtr))316return -EFAULT;317userPtr += 2;318data = le2be16(data);319*p++ = data;320*p++ = data;321count--;322}323*frameUsed += used*2;324} else {325u_long *p = (u_long *)&frame[*frameUsed];326count = min_t(unsigned long, userCount, frameLeft)>>2;327used = count*4;328while (count > 0) {329u_long data;330if (get_user(data, (u_int __user *)userPtr))331return -EFAULT;332userPtr += 4;333data = le2be16dbl(data);334*p++ = data;335count--;336}337*frameUsed += used;338}339return used;340}341342343static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount,344u_char frame[], ssize_t *frameUsed,345ssize_t frameLeft)346{347ssize_t count, used;348349count = frameLeft;350if (!dmasound.soft.stereo) {351u_short *p = (u_short *)&frame[*frameUsed];352count = min_t(unsigned long, userCount, frameLeft)>>1;353used = count*2;354while (count > 0) {355u_short data;356if (get_user(data, (u_short __user *)userPtr))357return -EFAULT;358userPtr += 2;359data = le2be16(data) ^ 0x8000;360*p++ = data;361*p++ = data;362}363*frameUsed += used*2;364} else {365u_long *p = (u_long *)&frame[*frameUsed];366count = min_t(unsigned long, userCount, frameLeft)>>2;367used = count;368while (count > 0) {369u_long data;370if (get_user(data, (u_int __user *)userPtr))371return -EFAULT;372userPtr += 4;373data = le2be16dbl(data) ^ 0x80008000;374*p++ = data;375count--;376}377*frameUsed += used;378}379return used;380}381382383static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount,384u_char frame[], ssize_t *frameUsed,385ssize_t frameLeft)386{387char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8388: dmasound_alaw2dma8;389/* this should help gcc to stuff everything into registers */390long bal = expand_bal;391long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;392ssize_t used, usedf;393394used = userCount;395usedf = frameLeft;396if (!dmasound.soft.stereo) {397u_char *p = &frame[*frameUsed];398u_char data = expand_data;399while (frameLeft) {400u_char c;401if (bal < 0) {402if (!userCount)403break;404if (get_user(c, userPtr++))405return -EFAULT;406data = table[c];407userCount--;408bal += hSpeed;409}410*p++ = data;411frameLeft--;412bal -= sSpeed;413}414expand_data = data;415} else {416u_short *p = (u_short *)&frame[*frameUsed];417u_short data = expand_data;418while (frameLeft >= 2) {419u_char c;420if (bal < 0) {421if (userCount < 2)422break;423if (get_user(c, userPtr++))424return -EFAULT;425data = table[c] << 8;426if (get_user(c, userPtr++))427return -EFAULT;428data |= table[c];429userCount -= 2;430bal += hSpeed;431}432*p++ = data;433frameLeft -= 2;434bal -= sSpeed;435}436expand_data = data;437}438expand_bal = bal;439used -= userCount;440*frameUsed += usedf-frameLeft;441return used;442}443444445static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount,446u_char frame[], ssize_t *frameUsed,447ssize_t frameLeft)448{449/* this should help gcc to stuff everything into registers */450long bal = expand_bal;451long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;452ssize_t used, usedf;453454used = userCount;455usedf = frameLeft;456if (!dmasound.soft.stereo) {457u_char *p = &frame[*frameUsed];458u_char data = expand_data;459while (frameLeft) {460if (bal < 0) {461if (!userCount)462break;463if (get_user(data, userPtr++))464return -EFAULT;465userCount--;466bal += hSpeed;467}468*p++ = data;469frameLeft--;470bal -= sSpeed;471}472expand_data = data;473} else {474u_short *p = (u_short *)&frame[*frameUsed];475u_short data = expand_data;476while (frameLeft >= 2) {477if (bal < 0) {478if (userCount < 2)479break;480if (get_user(data, (u_short __user *)userPtr))481return -EFAULT;482userPtr += 2;483userCount -= 2;484bal += hSpeed;485}486*p++ = data;487frameLeft -= 2;488bal -= sSpeed;489}490expand_data = data;491}492expand_bal = bal;493used -= userCount;494*frameUsed += usedf-frameLeft;495return used;496}497498499static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount,500u_char frame[], ssize_t *frameUsed,501ssize_t frameLeft)502{503/* this should help gcc to stuff everything into registers */504long bal = expand_bal;505long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;506ssize_t used, usedf;507508used = userCount;509usedf = frameLeft;510if (!dmasound.soft.stereo) {511u_char *p = &frame[*frameUsed];512u_char data = expand_data;513while (frameLeft) {514if (bal < 0) {515if (!userCount)516break;517if (get_user(data, userPtr++))518return -EFAULT;519data ^= 0x80;520userCount--;521bal += hSpeed;522}523*p++ = data;524frameLeft--;525bal -= sSpeed;526}527expand_data = data;528} else {529u_short *p = (u_short *)&frame[*frameUsed];530u_short data = expand_data;531while (frameLeft >= 2) {532if (bal < 0) {533if (userCount < 2)534break;535if (get_user(data, (u_short __user *)userPtr))536return -EFAULT;537userPtr += 2;538data ^= 0x8080;539userCount -= 2;540bal += hSpeed;541}542*p++ = data;543frameLeft -= 2;544bal -= sSpeed;545}546expand_data = data;547}548expand_bal = bal;549used -= userCount;550*frameUsed += usedf-frameLeft;551return used;552}553554555static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount,556u_char frame[], ssize_t *frameUsed,557ssize_t frameLeft)558{559/* this should help gcc to stuff everything into registers */560long bal = expand_bal;561long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;562ssize_t used, usedf;563564used = userCount;565usedf = frameLeft;566if (!dmasound.soft.stereo) {567u_short *p = (u_short *)&frame[*frameUsed];568u_short data = expand_data;569while (frameLeft >= 4) {570if (bal < 0) {571if (userCount < 2)572break;573if (get_user(data, (u_short __user *)userPtr))574return -EFAULT;575userPtr += 2;576userCount -= 2;577bal += hSpeed;578}579*p++ = data;580*p++ = data;581frameLeft -= 4;582bal -= sSpeed;583}584expand_data = data;585} else {586u_long *p = (u_long *)&frame[*frameUsed];587u_long data = expand_data;588while (frameLeft >= 4) {589if (bal < 0) {590if (userCount < 4)591break;592if (get_user(data, (u_int __user *)userPtr))593return -EFAULT;594userPtr += 4;595userCount -= 4;596bal += hSpeed;597}598*p++ = data;599frameLeft -= 4;600bal -= sSpeed;601}602expand_data = data;603}604expand_bal = bal;605used -= userCount;606*frameUsed += usedf-frameLeft;607return used;608}609610611static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount,612u_char frame[], ssize_t *frameUsed,613ssize_t frameLeft)614{615/* this should help gcc to stuff everything into registers */616long bal = expand_bal;617long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;618ssize_t used, usedf;619620used = userCount;621usedf = frameLeft;622if (!dmasound.soft.stereo) {623u_short *p = (u_short *)&frame[*frameUsed];624u_short data = expand_data;625while (frameLeft >= 4) {626if (bal < 0) {627if (userCount < 2)628break;629if (get_user(data, (u_short __user *)userPtr))630return -EFAULT;631userPtr += 2;632data ^= 0x8000;633userCount -= 2;634bal += hSpeed;635}636*p++ = data;637*p++ = data;638frameLeft -= 4;639bal -= sSpeed;640}641expand_data = data;642} else {643u_long *p = (u_long *)&frame[*frameUsed];644u_long data = expand_data;645while (frameLeft >= 4) {646if (bal < 0) {647if (userCount < 4)648break;649if (get_user(data, (u_int __user *)userPtr))650return -EFAULT;651userPtr += 4;652data ^= 0x80008000;653userCount -= 4;654bal += hSpeed;655}656*p++ = data;657frameLeft -= 4;658bal -= sSpeed;659}660expand_data = data;661}662expand_bal = bal;663used -= userCount;664*frameUsed += usedf-frameLeft;665return used;666}667668669static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount,670u_char frame[], ssize_t *frameUsed,671ssize_t frameLeft)672{673/* this should help gcc to stuff everything into registers */674long bal = expand_bal;675long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;676ssize_t used, usedf;677678used = userCount;679usedf = frameLeft;680if (!dmasound.soft.stereo) {681u_short *p = (u_short *)&frame[*frameUsed];682u_short data = expand_data;683while (frameLeft >= 4) {684if (bal < 0) {685if (userCount < 2)686break;687if (get_user(data, (u_short __user *)userPtr))688return -EFAULT;689userPtr += 2;690data = le2be16(data);691userCount -= 2;692bal += hSpeed;693}694*p++ = data;695*p++ = data;696frameLeft -= 4;697bal -= sSpeed;698}699expand_data = data;700} else {701u_long *p = (u_long *)&frame[*frameUsed];702u_long data = expand_data;703while (frameLeft >= 4) {704if (bal < 0) {705if (userCount < 4)706break;707if (get_user(data, (u_int __user *)userPtr))708return -EFAULT;709userPtr += 4;710data = le2be16dbl(data);711userCount -= 4;712bal += hSpeed;713}714*p++ = data;715frameLeft -= 4;716bal -= sSpeed;717}718expand_data = data;719}720expand_bal = bal;721used -= userCount;722*frameUsed += usedf-frameLeft;723return used;724}725726727static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount,728u_char frame[], ssize_t *frameUsed,729ssize_t frameLeft)730{731/* this should help gcc to stuff everything into registers */732long bal = expand_bal;733long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;734ssize_t used, usedf;735736used = userCount;737usedf = frameLeft;738if (!dmasound.soft.stereo) {739u_short *p = (u_short *)&frame[*frameUsed];740u_short data = expand_data;741while (frameLeft >= 4) {742if (bal < 0) {743if (userCount < 2)744break;745if (get_user(data, (u_short __user *)userPtr))746return -EFAULT;747userPtr += 2;748data = le2be16(data) ^ 0x8000;749userCount -= 2;750bal += hSpeed;751}752*p++ = data;753*p++ = data;754frameLeft -= 4;755bal -= sSpeed;756}757expand_data = data;758} else {759u_long *p = (u_long *)&frame[*frameUsed];760u_long data = expand_data;761while (frameLeft >= 4) {762if (bal < 0) {763if (userCount < 4)764break;765if (get_user(data, (u_int __user *)userPtr))766return -EFAULT;767userPtr += 4;768data = le2be16dbl(data) ^ 0x80008000;769userCount -= 4;770bal += hSpeed;771}772*p++ = data;773frameLeft -= 4;774bal -= sSpeed;775}776expand_data = data;777}778expand_bal = bal;779used -= userCount;780*frameUsed += usedf-frameLeft;781return used;782}783784785static TRANS transTTNormal = {786.ct_ulaw = ata_ct_law,787.ct_alaw = ata_ct_law,788.ct_s8 = ata_ct_s8,789.ct_u8 = ata_ct_u8,790};791792static TRANS transTTExpanding = {793.ct_ulaw = ata_ctx_law,794.ct_alaw = ata_ctx_law,795.ct_s8 = ata_ctx_s8,796.ct_u8 = ata_ctx_u8,797};798799static TRANS transFalconNormal = {800.ct_ulaw = ata_ct_law,801.ct_alaw = ata_ct_law,802.ct_s8 = ata_ct_s8,803.ct_u8 = ata_ct_u8,804.ct_s16be = ata_ct_s16be,805.ct_u16be = ata_ct_u16be,806.ct_s16le = ata_ct_s16le,807.ct_u16le = ata_ct_u16le808};809810static TRANS transFalconExpanding = {811.ct_ulaw = ata_ctx_law,812.ct_alaw = ata_ctx_law,813.ct_s8 = ata_ctx_s8,814.ct_u8 = ata_ctx_u8,815.ct_s16be = ata_ctx_s16be,816.ct_u16be = ata_ctx_u16be,817.ct_s16le = ata_ctx_s16le,818.ct_u16le = ata_ctx_u16le,819};820821822/*** Low level stuff *********************************************************/823824825826/*827* Atari (TT/Falcon)828*/829830static void *AtaAlloc(unsigned int size, gfp_t flags)831{832return atari_stram_alloc(size, "dmasound");833}834835static void AtaFree(void *obj, unsigned int size)836{837atari_stram_free( obj );838}839840static int __init AtaIrqInit(void)841{842/* Set up timer A. Timer A843will receive a signal upon end of playing from the sound844hardware. Furthermore Timer A is able to count events845and will cause an interrupt after a programmed number846of events. So all we need to keep the music playing is847to provide the sound hardware with new data upon848an interrupt from timer A. */849st_mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */850st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */851st_mfp.tim_ct_a = 8; /* Turn on event counting. */852/* Register interrupt handler. */853if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",854AtaInterrupt))855return 0;856st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */857st_mfp.int_mk_a |= 0x20;858return 1;859}860861#ifdef MODULE862static void AtaIrqCleanUp(void)863{864st_mfp.tim_ct_a = 0; /* stop timer */865st_mfp.int_en_a &= ~0x20; /* turn interrupt off */866free_irq(IRQ_MFP_TIMA, AtaInterrupt);867}868#endif /* MODULE */869870871#define TONE_VOXWARE_TO_DB(v) \872(((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)873#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)874875876static int AtaSetBass(int bass)877{878dmasound.bass = TONE_VOXWARE_TO_DB(bass);879atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass));880return TONE_DB_TO_VOXWARE(dmasound.bass);881}882883884static int AtaSetTreble(int treble)885{886dmasound.treble = TONE_VOXWARE_TO_DB(treble);887atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble));888return TONE_DB_TO_VOXWARE(dmasound.treble);889}890891892893/*894* TT895*/896897898static void TTSilence(void)899{900tt_dmasnd.ctrl = DMASND_CTRL_OFF;901atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */902}903904905static void TTInit(void)906{907int mode, i, idx;908const int freq[4] = {50066, 25033, 12517, 6258};909910/* search a frequency that fits into the allowed error range */911912idx = -1;913for (i = 0; i < ARRAY_SIZE(freq); i++)914/* this isn't as much useful for a TT than for a Falcon, but915* then it doesn't hurt very much to implement it for a TT too.916*/917if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)918idx = i;919if (idx > -1) {920dmasound.soft.speed = freq[idx];921dmasound.trans_write = &transTTNormal;922} else923dmasound.trans_write = &transTTExpanding;924925TTSilence();926dmasound.hard = dmasound.soft;927928if (dmasound.hard.speed > 50066) {929/* we would need to squeeze the sound, but we won't do that */930dmasound.hard.speed = 50066;931mode = DMASND_MODE_50KHZ;932dmasound.trans_write = &transTTNormal;933} else if (dmasound.hard.speed > 25033) {934dmasound.hard.speed = 50066;935mode = DMASND_MODE_50KHZ;936} else if (dmasound.hard.speed > 12517) {937dmasound.hard.speed = 25033;938mode = DMASND_MODE_25KHZ;939} else if (dmasound.hard.speed > 6258) {940dmasound.hard.speed = 12517;941mode = DMASND_MODE_12KHZ;942} else {943dmasound.hard.speed = 6258;944mode = DMASND_MODE_6KHZ;945}946947tt_dmasnd.mode = (dmasound.hard.stereo ?948DMASND_MODE_STEREO : DMASND_MODE_MONO) |949DMASND_MODE_8BIT | mode;950951expand_bal = -dmasound.soft.speed;952}953954955static int TTSetFormat(int format)956{957/* TT sound DMA supports only 8bit modes */958959switch (format) {960case AFMT_QUERY:961return dmasound.soft.format;962case AFMT_MU_LAW:963case AFMT_A_LAW:964case AFMT_S8:965case AFMT_U8:966break;967default:968format = AFMT_S8;969}970971dmasound.soft.format = format;972dmasound.soft.size = 8;973if (dmasound.minDev == SND_DEV_DSP) {974dmasound.dsp.format = format;975dmasound.dsp.size = 8;976}977TTInit();978979return format;980}981982983#define VOLUME_VOXWARE_TO_DB(v) \984(((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)985#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)986987988static int TTSetVolume(int volume)989{990dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);991atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left));992dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);993atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right));994return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |995(VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8);996}997998999#define GAIN_VOXWARE_TO_DB(v) \1000(((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)1001#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)10021003static int TTSetGain(int gain)1004{1005dmasound.gain = GAIN_VOXWARE_TO_DB(gain);1006atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain));1007return GAIN_DB_TO_VOXWARE(dmasound.gain);1008}1009101010111012/*1013* Falcon1014*/101510161017static void FalconSilence(void)1018{1019/* stop playback, set sample rate 50kHz for PSG sound */1020tt_dmasnd.ctrl = DMASND_CTRL_OFF;1021tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;1022tt_dmasnd.int_div = 0; /* STE compatible divider */1023tt_dmasnd.int_ctrl = 0x0;1024tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */1025tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */1026tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */1027tt_dmasnd.adc_src = 3; /* ADC Input = PSG */1028}102910301031static void FalconInit(void)1032{1033int divider, i, idx;1034const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};10351036/* search a frequency that fits into the allowed error range */10371038idx = -1;1039for (i = 0; i < ARRAY_SIZE(freq); i++)1040/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would1041* be playable without expanding, but that now a kernel runtime1042* option1043*/1044if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)1045idx = i;1046if (idx > -1) {1047dmasound.soft.speed = freq[idx];1048dmasound.trans_write = &transFalconNormal;1049} else1050dmasound.trans_write = &transFalconExpanding;10511052FalconSilence();1053dmasound.hard = dmasound.soft;10541055if (dmasound.hard.size == 16) {1056/* the Falcon can play 16bit samples only in stereo */1057dmasound.hard.stereo = 1;1058}10591060if (dmasound.hard.speed > 49170) {1061/* we would need to squeeze the sound, but we won't do that */1062dmasound.hard.speed = 49170;1063divider = 1;1064dmasound.trans_write = &transFalconNormal;1065} else if (dmasound.hard.speed > 32780) {1066dmasound.hard.speed = 49170;1067divider = 1;1068} else if (dmasound.hard.speed > 24585) {1069dmasound.hard.speed = 32780;1070divider = 2;1071} else if (dmasound.hard.speed > 19668) {1072dmasound.hard.speed = 24585;1073divider = 3;1074} else if (dmasound.hard.speed > 16390) {1075dmasound.hard.speed = 19668;1076divider = 4;1077} else if (dmasound.hard.speed > 12292) {1078dmasound.hard.speed = 16390;1079divider = 5;1080} else if (dmasound.hard.speed > 9834) {1081dmasound.hard.speed = 12292;1082divider = 7;1083} else if (dmasound.hard.speed > 8195) {1084dmasound.hard.speed = 9834;1085divider = 9;1086} else {1087dmasound.hard.speed = 8195;1088divider = 11;1089}1090tt_dmasnd.int_div = divider;10911092/* Setup Falcon sound DMA for playback */1093tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */1094tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */1095tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */1096tt_dmasnd.cbar_dst = 0x0000;1097tt_dmasnd.rec_track_select = 0;1098tt_dmasnd.dac_src = 2; /* connect matrix to DAC */1099tt_dmasnd.adc_src = 0; /* ADC Input = Mic */11001101tt_dmasnd.mode = (dmasound.hard.stereo ?1102DMASND_MODE_STEREO : DMASND_MODE_MONO) |1103((dmasound.hard.size == 8) ?1104DMASND_MODE_8BIT : DMASND_MODE_16BIT) |1105DMASND_MODE_6KHZ;11061107expand_bal = -dmasound.soft.speed;1108}110911101111static int FalconSetFormat(int format)1112{1113int size;1114/* Falcon sound DMA supports 8bit and 16bit modes */11151116switch (format) {1117case AFMT_QUERY:1118return dmasound.soft.format;1119case AFMT_MU_LAW:1120case AFMT_A_LAW:1121case AFMT_U8:1122case AFMT_S8:1123size = 8;1124break;1125case AFMT_S16_BE:1126case AFMT_U16_BE:1127case AFMT_S16_LE:1128case AFMT_U16_LE:1129size = 16;1130break;1131default: /* :-) */1132size = 8;1133format = AFMT_S8;1134}11351136dmasound.soft.format = format;1137dmasound.soft.size = size;1138if (dmasound.minDev == SND_DEV_DSP) {1139dmasound.dsp.format = format;1140dmasound.dsp.size = dmasound.soft.size;1141}11421143FalconInit();11441145return format;1146}114711481149/* This is for the Falcon output *attenuation* in 1.5dB steps,1150* i.e. output level from 0 to -22.5dB in -1.5dB steps.1151*/1152#define VOLUME_VOXWARE_TO_ATT(v) \1153((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)1154#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)115511561157static int FalconSetVolume(int volume)1158{1159dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);1160dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);1161tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;1162return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |1163VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;1164}116511661167static void AtaPlayNextFrame(int index)1168{1169char *start, *end;11701171/* used by AtaPlay() if all doubts whether there really is something1172* to be played are already wiped out.1173*/1174start = write_sq.buffers[write_sq.front];1175end = start+((write_sq.count == index) ? write_sq.rear_size1176: write_sq.block_size);1177/* end might not be a legal virtual address. */1178DMASNDSetEnd(virt_to_phys(end - 1) + 1);1179DMASNDSetBase(virt_to_phys(start));1180/* Since only an even number of samples per frame can1181be played, we might lose one byte here. (TO DO) */1182write_sq.front = (write_sq.front+1) % write_sq.max_count;1183write_sq.active++;1184tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;1185}118611871188static void AtaPlay(void)1189{1190/* ++TeSche: Note that write_sq.active is no longer just a flag but1191* holds the number of frames the DMA is currently programmed for1192* instead, may be 0, 1 (currently being played) or 2 (pre-programmed).1193*1194* Changes done to write_sq.count and write_sq.active are a bit more1195* subtle again so now I must admit I also prefer disabling the irq1196* here rather than considering all possible situations. But the point1197* is that disabling the irq doesn't have any bad influence on this1198* version of the driver as we benefit from having pre-programmed the1199* DMA wherever possible: There's no need to reload the DMA at the1200* exact time of an interrupt but only at some time while the1201* pre-programmed frame is playing!1202*/1203atari_disable_irq(IRQ_MFP_TIMA);12041205if (write_sq.active == 2 || /* DMA is 'full' */1206write_sq.count <= 0) { /* nothing to do */1207atari_enable_irq(IRQ_MFP_TIMA);1208return;1209}12101211if (write_sq.active == 0) {1212/* looks like there's nothing 'in' the DMA yet, so try1213* to put two frames into it (at least one is available).1214*/1215if (write_sq.count == 1 &&1216write_sq.rear_size < write_sq.block_size &&1217!write_sq.syncing) {1218/* hmmm, the only existing frame is not1219* yet filled and we're not syncing?1220*/1221atari_enable_irq(IRQ_MFP_TIMA);1222return;1223}1224AtaPlayNextFrame(1);1225if (write_sq.count == 1) {1226/* no more frames */1227atari_enable_irq(IRQ_MFP_TIMA);1228return;1229}1230if (write_sq.count == 2 &&1231write_sq.rear_size < write_sq.block_size &&1232!write_sq.syncing) {1233/* hmmm, there were two frames, but the second1234* one is not yet filled and we're not syncing?1235*/1236atari_enable_irq(IRQ_MFP_TIMA);1237return;1238}1239AtaPlayNextFrame(2);1240} else {1241/* there's already a frame being played so we may only stuff1242* one new into the DMA, but even if this may be the last1243* frame existing the previous one is still on write_sq.count.1244*/1245if (write_sq.count == 2 &&1246write_sq.rear_size < write_sq.block_size &&1247!write_sq.syncing) {1248/* hmmm, the only existing frame is not1249* yet filled and we're not syncing?1250*/1251atari_enable_irq(IRQ_MFP_TIMA);1252return;1253}1254AtaPlayNextFrame(2);1255}1256atari_enable_irq(IRQ_MFP_TIMA);1257}125812591260static irqreturn_t AtaInterrupt(int irq, void *dummy)1261{1262#if 01263/* ++TeSche: if you should want to test this... */1264static int cnt;1265if (write_sq.active == 2)1266if (++cnt == 10) {1267/* simulate losing an interrupt */1268cnt = 0;1269return IRQ_HANDLED;1270}1271#endif1272spin_lock(&dmasound.lock);1273if (write_sq_ignore_int && is_falcon) {1274/* ++TeSche: Falcon only: ignore first irq because it comes1275* immediately after starting a frame. after that, irqs come1276* (almost) like on the TT.1277*/1278write_sq_ignore_int = 0;1279goto out;1280}12811282if (!write_sq.active) {1283/* playing was interrupted and sq_reset() has already cleared1284* the sq variables, so better don't do anything here.1285*/1286WAKE_UP(write_sq.sync_queue);1287goto out;1288}12891290/* Probably ;) one frame is finished. Well, in fact it may be that a1291* pre-programmed one is also finished because there has been a long1292* delay in interrupt delivery and we've completely lost one, but1293* there's no way to detect such a situation. In such a case the last1294* frame will be played more than once and the situation will recover1295* as soon as the irq gets through.1296*/1297write_sq.count--;1298write_sq.active--;12991300if (!write_sq.active) {1301tt_dmasnd.ctrl = DMASND_CTRL_OFF;1302write_sq_ignore_int = 1;1303}13041305WAKE_UP(write_sq.action_queue);1306/* At least one block of the queue is free now1307so wake up a writing process blocked because1308of a full queue. */13091310if ((write_sq.active != 1) || (write_sq.count != 1))1311/* We must be a bit carefully here: write_sq.count indicates the1312* number of buffers used and not the number of frames to be1313* played. If write_sq.count==1 and write_sq.active==1 that1314* means the only remaining frame was already programmed1315* earlier (and is currently running) so we mustn't call1316* AtaPlay() here, otherwise we'll play one frame too much.1317*/1318AtaPlay();13191320if (!write_sq.active) WAKE_UP(write_sq.sync_queue);1321/* We are not playing after AtaPlay(), so there1322is nothing to play any more. Wake up a process1323waiting for audio output to drain. */1324out:1325spin_unlock(&dmasound.lock);1326return IRQ_HANDLED;1327}132813291330/*** Mid level stuff *********************************************************/133113321333/*1334* /dev/mixer abstraction1335*/13361337#define RECLEVEL_VOXWARE_TO_GAIN(v) \1338((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)1339#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)134013411342static void __init TTMixerInit(void)1343{1344atari_microwire_cmd(MW_LM1992_VOLUME(0));1345dmasound.volume_left = 0;1346atari_microwire_cmd(MW_LM1992_BALLEFT(0));1347dmasound.volume_right = 0;1348atari_microwire_cmd(MW_LM1992_BALRIGHT(0));1349atari_microwire_cmd(MW_LM1992_TREBLE(0));1350atari_microwire_cmd(MW_LM1992_BASS(0));1351}13521353static void __init FalconMixerInit(void)1354{1355dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;1356dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;1357}13581359static int AtaMixerIoctl(u_int cmd, u_long arg)1360{1361int data;1362unsigned long flags;1363switch (cmd) {1364case SOUND_MIXER_READ_SPEAKER:1365if (is_falcon || MACH_IS_TT) {1366int porta;1367spin_lock_irqsave(&dmasound.lock, flags);1368sound_ym.rd_data_reg_sel = 14;1369porta = sound_ym.rd_data_reg_sel;1370spin_unlock_irqrestore(&dmasound.lock, flags);1371return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);1372}1373break;1374case SOUND_MIXER_WRITE_VOLUME:1375IOCTL_IN(arg, data);1376return IOCTL_OUT(arg, dmasound_set_volume(data));1377case SOUND_MIXER_WRITE_SPEAKER:1378if (is_falcon || MACH_IS_TT) {1379int porta;1380IOCTL_IN(arg, data);1381spin_lock_irqsave(&dmasound.lock, flags);1382sound_ym.rd_data_reg_sel = 14;1383porta = (sound_ym.rd_data_reg_sel & ~0x40) |1384(data < 50 ? 0x40 : 0);1385sound_ym.wd_data = porta;1386spin_unlock_irqrestore(&dmasound.lock, flags);1387return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);1388}1389}1390return -EINVAL;1391}139213931394static int TTMixerIoctl(u_int cmd, u_long arg)1395{1396int data;1397switch (cmd) {1398case SOUND_MIXER_READ_RECMASK:1399return IOCTL_OUT(arg, 0);1400case SOUND_MIXER_READ_DEVMASK:1401return IOCTL_OUT(arg,1402SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |1403(MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));1404case SOUND_MIXER_READ_STEREODEVS:1405return IOCTL_OUT(arg, SOUND_MASK_VOLUME);1406case SOUND_MIXER_READ_VOLUME:1407return IOCTL_OUT(arg,1408VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |1409(VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));1410case SOUND_MIXER_READ_BASS:1411return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));1412case SOUND_MIXER_READ_TREBLE:1413return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));1414case SOUND_MIXER_READ_OGAIN:1415return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));1416case SOUND_MIXER_WRITE_BASS:1417IOCTL_IN(arg, data);1418return IOCTL_OUT(arg, dmasound_set_bass(data));1419case SOUND_MIXER_WRITE_TREBLE:1420IOCTL_IN(arg, data);1421return IOCTL_OUT(arg, dmasound_set_treble(data));1422case SOUND_MIXER_WRITE_OGAIN:1423IOCTL_IN(arg, data);1424return IOCTL_OUT(arg, dmasound_set_gain(data));1425}1426return AtaMixerIoctl(cmd, arg);1427}14281429static int FalconMixerIoctl(u_int cmd, u_long arg)1430{1431int data;1432switch (cmd) {1433case SOUND_MIXER_READ_RECMASK:1434return IOCTL_OUT(arg, SOUND_MASK_MIC);1435case SOUND_MIXER_READ_DEVMASK:1436return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);1437case SOUND_MIXER_READ_STEREODEVS:1438return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);1439case SOUND_MIXER_READ_VOLUME:1440return IOCTL_OUT(arg,1441VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |1442VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);1443case SOUND_MIXER_READ_CAPS:1444return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);1445case SOUND_MIXER_WRITE_MIC:1446IOCTL_IN(arg, data);1447tt_dmasnd.input_gain =1448RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |1449RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);1450/* fall thru, return set value */1451case SOUND_MIXER_READ_MIC:1452return IOCTL_OUT(arg,1453RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |1454RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);1455}1456return AtaMixerIoctl(cmd, arg);1457}14581459static int AtaWriteSqSetup(void)1460{1461write_sq_ignore_int = 0;1462return 0 ;1463}14641465static int AtaSqOpen(fmode_t mode)1466{1467write_sq_ignore_int = 1;1468return 0 ;1469}14701471static int TTStateInfo(char *buffer, size_t space)1472{1473int len = 0;1474len += sprintf(buffer+len, "\tvol left %ddB [-40... 0]\n",1475dmasound.volume_left);1476len += sprintf(buffer+len, "\tvol right %ddB [-40... 0]\n",1477dmasound.volume_right);1478len += sprintf(buffer+len, "\tbass %ddB [-12...+12]\n",1479dmasound.bass);1480len += sprintf(buffer+len, "\ttreble %ddB [-12...+12]\n",1481dmasound.treble);1482if (len >= space) {1483printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;1484len = space ;1485}1486return len;1487}14881489static int FalconStateInfo(char *buffer, size_t space)1490{1491int len = 0;1492len += sprintf(buffer+len, "\tvol left %ddB [-22.5 ... 0]\n",1493dmasound.volume_left);1494len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n",1495dmasound.volume_right);1496if (len >= space) {1497printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;1498len = space ;1499}1500return len;1501}150215031504/*** Machine definitions *****************************************************/15051506static SETTINGS def_hard_falcon = {1507.format = AFMT_S8,1508.stereo = 0,1509.size = 8,1510.speed = 81951511} ;15121513static SETTINGS def_hard_tt = {1514.format = AFMT_S8,1515.stereo = 0,1516.size = 8,1517.speed = 125171518} ;15191520static SETTINGS def_soft = {1521.format = AFMT_U8,1522.stereo = 0,1523.size = 8,1524.speed = 80001525} ;15261527static __initdata MACHINE machTT = {1528.name = "Atari",1529.name2 = "TT",1530.owner = THIS_MODULE,1531.dma_alloc = AtaAlloc,1532.dma_free = AtaFree,1533.irqinit = AtaIrqInit,1534#ifdef MODULE1535.irqcleanup = AtaIrqCleanUp,1536#endif /* MODULE */1537.init = TTInit,1538.silence = TTSilence,1539.setFormat = TTSetFormat,1540.setVolume = TTSetVolume,1541.setBass = AtaSetBass,1542.setTreble = AtaSetTreble,1543.setGain = TTSetGain,1544.play = AtaPlay,1545.mixer_init = TTMixerInit,1546.mixer_ioctl = TTMixerIoctl,1547.write_sq_setup = AtaWriteSqSetup,1548.sq_open = AtaSqOpen,1549.state_info = TTStateInfo,1550.min_dsp_speed = 6258,1551.version = ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),1552.hardware_afmts = AFMT_S8, /* h'ware-supported formats *only* here */1553.capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */1554};15551556static __initdata MACHINE machFalcon = {1557.name = "Atari",1558.name2 = "FALCON",1559.dma_alloc = AtaAlloc,1560.dma_free = AtaFree,1561.irqinit = AtaIrqInit,1562#ifdef MODULE1563.irqcleanup = AtaIrqCleanUp,1564#endif /* MODULE */1565.init = FalconInit,1566.silence = FalconSilence,1567.setFormat = FalconSetFormat,1568.setVolume = FalconSetVolume,1569.setBass = AtaSetBass,1570.setTreble = AtaSetTreble,1571.play = AtaPlay,1572.mixer_init = FalconMixerInit,1573.mixer_ioctl = FalconMixerIoctl,1574.write_sq_setup = AtaWriteSqSetup,1575.sq_open = AtaSqOpen,1576.state_info = FalconStateInfo,1577.min_dsp_speed = 8195,1578.version = ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),1579.hardware_afmts = (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */1580.capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */1581};158215831584/*** Config & Setup **********************************************************/158515861587static int __init dmasound_atari_init(void)1588{1589if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {1590if (ATARIHW_PRESENT(CODEC)) {1591dmasound.mach = machFalcon;1592dmasound.mach.default_soft = def_soft ;1593dmasound.mach.default_hard = def_hard_falcon ;1594is_falcon = 1;1595} else if (ATARIHW_PRESENT(MICROWIRE)) {1596dmasound.mach = machTT;1597dmasound.mach.default_soft = def_soft ;1598dmasound.mach.default_hard = def_hard_tt ;1599is_falcon = 0;1600} else1601return -ENODEV;1602if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0)1603return dmasound_init();1604else {1605printk("DMA sound driver: Timer A interrupt already in use\n");1606return -EBUSY;1607}1608}1609return -ENODEV;1610}16111612static void __exit dmasound_atari_cleanup(void)1613{1614dmasound_deinit();1615}16161617module_init(dmasound_atari_init);1618module_exit(dmasound_atari_cleanup);1619MODULE_LICENSE("GPL");162016211622