!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/sound/dmasound/   drwxr-xr-x
Free 318.34 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     dmasound_atari.c (40.73 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  linux/drivers/sound/dmasound/dmasound_atari.c
 *
 *  Atari TT and Falcon DMA Sound Driver
 *
 *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
 *  prior to 28/01/2001
 *
 *  28/01/2001 [0.1] Iain Sandoe
 *             - added versioning
 *             - put in and populated the hardware_afmts field.
 *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
 *  01/02/2001 [0.3] - put in default hard/soft settings.
 */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/mm.h>

#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/atariints.h>
#include <asm/atari_stram.h>

#include "dmasound.h"

#define DMASOUND_ATARI_REVISION 0
#define DMASOUND_ATARI_EDITION 3

extern void atari_microwire_cmd(int cmd);

static int is_falcon;
static int write_sq_ignore_int = 0;    /* ++TeSche: used for Falcon */

static int expand_bal;    /* Balance factor for expanding (not volume!) */
static int expand_data;    /* Data for expanding */


/*** Translations ************************************************************/


/* ++TeSche: radically changed for new expanding purposes...
 *
 * These two routines now deal with copying/expanding/translating the samples
 * from user space into our buffer at the right frequency. They take care about
 * how much data there's actually to read, how much buffer space there is and
 * to convert samples into the right frequency/encoding. They will only work on
 * complete samples so it may happen they leave some bytes in the input stream
 * if the user didn't write a multiple of the current sample size. They both
 * return the number of bytes they've used from both streams so you may detect
 * such a situation. Luckily all programs should be able to cope with that.
 *
 * I think I've optimized anything as far as one can do in plain C, all
 * variables should fit in registers and the loops are really short. There's
 * one loop for every possible situation. Writing a more generalized and thus
 * parameterized loop would only produce slower code. Feel free to optimize
 * this in assembler if you like. :)
 *
 * I think these routines belong here because they're not yet really hardware
 * independent, especially the fact that the Falcon can play 16bit samples
 * only in stereo is hardcoded in both of them!
 *
 * ++geert: split in even more functions (one per format)
 */

static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft);
static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
             u_char frame[], ssize_t *frameUsed,
             ssize_t frameLeft);
static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
             u_char frame[], ssize_t *frameUsed,
             ssize_t frameLeft);
static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft);
static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft);
static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft);
static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft);
static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
               u_char frame[], ssize_t *frameUsed,
               ssize_t frameLeft);
static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft);
static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft);
static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft);
static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft);
static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft);
static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft);


/*** Low level stuff *********************************************************/


static void AtaOpen(void);
static void AtaRelease(void);
static void *AtaAlloc(unsigned int size, int flags);
static void AtaFree(void *, unsigned int size);
static int AtaIrqInit(void);
#ifdef MODULE
static void AtaIrqCleanUp(void);
#endif /* MODULE */
static int AtaSetBass(int bass);
static int AtaSetTreble(int treble);
static void TTSilence(void);
static void TTInit(void);
static int TTSetFormat(int format);
static int TTSetVolume(int volume);
static int TTSetGain(int gain);
static void FalconSilence(void);
static void FalconInit(void);
static int FalconSetFormat(int format);
static int FalconSetVolume(int volume);
static void AtaPlayNextFrame(int index);
static void AtaPlay(void);
static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);

/*** Mid level stuff *********************************************************/

static void TTMixerInit(void);
static void FalconMixerInit(void);
static int AtaMixerIoctl(u_int cmd, u_long arg);
static int TTMixerIoctl(u_int cmd, u_long arg);
static int FalconMixerIoctl(u_int cmd, u_long arg);
static void AtaWriteSqSetup(void);
static int AtaSqOpen(mode_t mode);
static int TTStateInfo(char *buffer, size_t space);
static int FalconStateInfo(char *buffer, size_t space);


/*** Translations ************************************************************/


static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft)
{
    char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
                              : dmasound_alaw2dma8;
    ssize_t count, used;
    u_char *p = &frame[*frameUsed];

    count = min_t(unsigned long, userCount, frameLeft);
    if (dmasound.soft.stereo)
        count &= ~1;
    used = count;
    while (count > 0) {
        u_char data;
        if (get_user(data, userPtr++))
            return -EFAULT;
        *p++ = table[data];
        count--;
    }
    *frameUsed += used;
    return used;
}


static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
             u_char frame[], ssize_t *frameUsed,
             ssize_t frameLeft)
{
    ssize_t count, used;
    void *p = &frame[*frameUsed];

    count = min_t(unsigned long, userCount, frameLeft);
    if (dmasound.soft.stereo)
        count &= ~1;
    used = count;
    if (copy_from_user(p, userPtr, count))
        return -EFAULT;
    *frameUsed += used;
    return used;
}


static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
             u_char frame[], ssize_t *frameUsed,
             ssize_t frameLeft)
{
    ssize_t count, used;

    if (!dmasound.soft.stereo) {
        u_char *p = &frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft);
        used = count;
        while (count > 0) {
            u_char data;
            if (get_user(data, userPtr++))
                return -EFAULT;
            *p++ = data ^ 0x80;
            count--;
        }
    } else {
        u_short *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>1;
        used = count*2;
        while (count > 0) {
            u_short data;
            if (get_user(data, ((u_short *)userPtr)++))
                return -EFAULT;
            *p++ = data ^ 0x8080;
            count--;
        }
    }
    *frameUsed += used;
    return used;
}


static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft)
{
    ssize_t count, used;

    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>1;
        used = count*2;
        while (count > 0) {
            u_short data;
            if (get_user(data, ((u_short *)userPtr)++))
                return -EFAULT;
            *p++ = data;
            *p++ = data;
            count--;
        }
        *frameUsed += used*2;
    } else {
        void *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft) & ~3;
        used = count;
        if (copy_from_user(p, userPtr, count))
            return -EFAULT;
        *frameUsed += used;
    }
    return used;
}


static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft)
{
    ssize_t count, used;

    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>1;
        used = count*2;
        while (count > 0) {
            u_short data;
            if (get_user(data, ((u_short *)userPtr)++))
                return -EFAULT;
            data ^= 0x8000;
            *p++ = data;
            *p++ = data;
            count--;
        }
        *frameUsed += used*2;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>2;
        used = count*4;
        while (count > 0) {
            u_long data;
            if (get_user(data, ((u_int *)userPtr)++))
                return -EFAULT;
            *p++ = data ^ 0x80008000;
            count--;
        }
        *frameUsed += used;
    }
    return used;
}


static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft)
{
    ssize_t count, used;

    count = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>1;
        used = count*2;
        while (count > 0) {
            u_short data;
            if (get_user(data, ((u_short *)userPtr)++))
                return -EFAULT;
            data = le2be16(data);
            *p++ = data;
            *p++ = data;
            count--;
        }
        *frameUsed += used*2;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>2;
        used = count*4;
        while (count > 0) {
            u_long data;
            if (get_user(data, ((u_int *)userPtr)++))
                return -EFAULT;
            data = le2be16dbl(data);
            *p++ = data;
            count--;
        }
        *frameUsed += used;
    }
    return used;
}


static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
                u_char frame[], ssize_t *frameUsed,
                ssize_t frameLeft)
{
    ssize_t count, used;

    count = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>1;
        used = count*2;
        while (count > 0) {
            u_short data;
            if (get_user(data, ((u_short *)userPtr)++))
                return -EFAULT;
            data = le2be16(data) ^ 0x8000;
            *p++ = data;
            *p++ = data;
        }
        *frameUsed += used*2;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        count = min_t(unsigned long, userCount, frameLeft)>>2;
        used = count;
        while (count > 0) {
            u_long data;
            if (get_user(data, ((u_int *)userPtr)++))
                return -EFAULT;
            data = le2be16dbl(data) ^ 0x80008000;
            *p++ = data;
            count--;
        }
        *frameUsed += used;
    }
    return used;
}


static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
               u_char frame[], ssize_t *frameUsed,
               ssize_t frameLeft)
{
    char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
                              : dmasound_alaw2dma8;
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_char *p = &frame[*frameUsed];
        u_char data = expand_data;
        while (frameLeft) {
            u_char c;
            if (bal < 0) {
                if (!userCount)
                    break;
                if (get_user(c, userPtr++))
                    return -EFAULT;
                data = table[c];
                userCount--;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft--;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 2) {
            u_char c;
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(c, userPtr++))
                    return -EFAULT;
                data = table[c] << 8;
                if (get_user(c, userPtr++))
                    return -EFAULT;
                data |= table[c];
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 2;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_char *p = &frame[*frameUsed];
        u_char data = expand_data;
        while (frameLeft) {
            if (bal < 0) {
                if (!userCount)
                    break;
                if (get_user(data, userPtr++))
                    return -EFAULT;
                userCount--;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft--;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 2) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 2;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
              u_char frame[], ssize_t *frameUsed,
              ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_char *p = &frame[*frameUsed];
        u_char data = expand_data;
        while (frameLeft) {
            if (bal < 0) {
                if (!userCount)
                    break;
                if (get_user(data, userPtr++))
                    return -EFAULT;
                data ^= 0x80;
                userCount--;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft--;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 2) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                data ^= 0x8080;
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 2;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        u_long data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 4)
                    break;
                if (get_user(data, ((u_int *)userPtr)++))
                    return -EFAULT;
                userCount -= 4;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                data ^= 0x8000;
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        u_long data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 4)
                    break;
                if (get_user(data, ((u_int *)userPtr)++))
                    return -EFAULT;
                data ^= 0x80008000;
                userCount -= 4;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                data = le2be16(data);
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        u_long data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 4)
                    break;
                if (get_user(data, ((u_int *)userPtr)++))
                    return -EFAULT;
                data = le2be16dbl(data);
                userCount -= 4;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
                 u_char frame[], ssize_t *frameUsed,
                 ssize_t frameLeft)
{
    /* this should help gcc to stuff everything into registers */
    long bal = expand_bal;
    long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
    ssize_t used, usedf;

    used = userCount;
    usedf = frameLeft;
    if (!dmasound.soft.stereo) {
        u_short *p = (u_short *)&frame[*frameUsed];
        u_short data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 2)
                    break;
                if (get_user(data, ((u_short *)userPtr)++))
                    return -EFAULT;
                data = le2be16(data) ^ 0x8000;
                userCount -= 2;
                bal += hSpeed;
            }
            *p++ = data;
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    } else {
        u_long *p = (u_long *)&frame[*frameUsed];
        u_long data = expand_data;
        while (frameLeft >= 4) {
            if (bal < 0) {
                if (userCount < 4)
                    break;
                if (get_user(data, ((u_int *)userPtr)++))
                    return -EFAULT;
                data = le2be16dbl(data) ^ 0x80008000;
                userCount -= 4;
                bal += hSpeed;
            }
            *p++ = data;
            frameLeft -= 4;
            bal -= sSpeed;
        }
        expand_data = data;
    }
    expand_bal = bal;
    used -= userCount;
    *frameUsed += usedf-frameLeft;
    return used;
}


static TRANS transTTNormal = {
    ct_ulaw:    ata_ct_law,
    ct_alaw:    ata_ct_law,
    ct_s8:        ata_ct_s8,
    ct_u8:        ata_ct_u8,
};

static TRANS transTTExpanding = {
    ct_ulaw:    ata_ctx_law,
    ct_alaw:    ata_ctx_law,
    ct_s8:        ata_ctx_s8,
    ct_u8:        ata_ctx_u8,
};

static TRANS transFalconNormal = {
    ct_ulaw:    ata_ct_law,
    ct_alaw:    ata_ct_law,
    ct_s8:        ata_ct_s8,
    ct_u8:        ata_ct_u8,
    ct_s16be:    ata_ct_s16be,
    ct_u16be:    ata_ct_u16be,
    ct_s16le:    ata_ct_s16le,
    ct_u16le:    ata_ct_u16le
};

static TRANS transFalconExpanding = {
    ct_ulaw:    ata_ctx_law,
    ct_alaw:    ata_ctx_law,
    ct_s8:        ata_ctx_s8,
    ct_u8:        ata_ctx_u8,
    ct_s16be:    ata_ctx_s16be,
    ct_u16be:    ata_ctx_u16be,
    ct_s16le:    ata_ctx_s16le,
    ct_u16le:    ata_ctx_u16le,
};


/*** Low level stuff *********************************************************/



/*
 * Atari (TT/Falcon)
 */

static void AtaOpen(void)
{
    MOD_INC_USE_COUNT;
}

static void AtaRelease(void)
{
    MOD_DEC_USE_COUNT;
}

static void *AtaAlloc(unsigned int size, int flags)
{
    return atari_stram_alloc(size, "dmasound");
}

static void AtaFree(void *obj, unsigned int size)
{
    atari_stram_free( obj );
}

static int __init AtaIrqInit(void)
{
    /* Set up timer A. Timer A
       will receive a signal upon end of playing from the sound
       hardware. Furthermore Timer A is able to count events
       and will cause an interrupt after a programmed number
       of events. So all we need to keep the music playing is
       to provide the sound hardware with new data upon
       an interrupt from timer A. */
    mfp.tim_ct_a = 0;    /* ++roman: Stop timer before programming! */
    mfp.tim_dt_a = 1;    /* Cause interrupt after first event. */
    mfp.tim_ct_a = 8;    /* Turn on event counting. */
    /* Register interrupt handler. */
    request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
            AtaInterrupt);
    mfp.int_en_a |= 0x20;    /* Turn interrupt on. */
    mfp.int_mk_a |= 0x20;
    return 1;
}

#ifdef MODULE
static void AtaIrqCleanUp(void)
{
    mfp.tim_ct_a = 0;    /* stop timer */
    mfp.int_en_a &= ~0x20;    /* turn interrupt off */
    free_irq(IRQ_MFP_TIMA, AtaInterrupt);
}
#endif /* MODULE */


#define TONE_VOXWARE_TO_DB(v) \
    (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)


static int AtaSetBass(int bass)
{
    dmasound.bass = TONE_VOXWARE_TO_DB(bass);
    atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass));
    return TONE_DB_TO_VOXWARE(dmasound.bass);
}


static int AtaSetTreble(int treble)
{
    dmasound.treble = TONE_VOXWARE_TO_DB(treble);
    atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble));
    return TONE_DB_TO_VOXWARE(dmasound.treble);
}



/*
 * TT
 */


static void TTSilence(void)
{
    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
    atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
}


static void TTInit(void)
{
    int mode, i, idx;
    const int freq[4] = {50066, 25033, 12517, 6258};

    /* search a frequency that fits into the allowed error range */

    idx = -1;
    for (i = 0; i < ARRAY_SIZE(freq); i++)
        /* this isn't as much useful for a TT than for a Falcon, but
         * then it doesn't hurt very much to implement it for a TT too.
         */
        if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
            idx = i;
    if (idx > -1) {
        dmasound.soft.speed = freq[idx];
        dmasound.trans_write = &transTTNormal;
    } else
        dmasound.trans_write = &transTTExpanding;

    TTSilence();
    dmasound.hard = dmasound.soft;

    if (dmasound.hard.speed > 50066) {
        /* we would need to squeeze the sound, but we won't do that */
        dmasound.hard.speed = 50066;
        mode = DMASND_MODE_50KHZ;
        dmasound.trans_write = &transTTNormal;
    } else if (dmasound.hard.speed > 25033) {
        dmasound.hard.speed = 50066;
        mode = DMASND_MODE_50KHZ;
    } else if (dmasound.hard.speed > 12517) {
        dmasound.hard.speed = 25033;
        mode = DMASND_MODE_25KHZ;
    } else if (dmasound.hard.speed > 6258) {
        dmasound.hard.speed = 12517;
        mode = DMASND_MODE_12KHZ;
    } else {
        dmasound.hard.speed = 6258;
        mode = DMASND_MODE_6KHZ;
    }

    tt_dmasnd.mode = (dmasound.hard.stereo ?
              DMASND_MODE_STEREO : DMASND_MODE_MONO) |
        DMASND_MODE_8BIT | mode;

    expand_bal = -dmasound.soft.speed;
}


static int TTSetFormat(int format)
{
    /* TT sound DMA supports only 8bit modes */

    switch (format) {
    case AFMT_QUERY:
        return dmasound.soft.format;
    case AFMT_MU_LAW:
    case AFMT_A_LAW:
    case AFMT_S8:
    case AFMT_U8:
        break;
    default:
        format = AFMT_S8;
    }

    dmasound.soft.format = format;
    dmasound.soft.size = 8;
    if (dmasound.minDev == SND_DEV_DSP) {
        dmasound.dsp.format = format;
        dmasound.dsp.size = 8;
    }
    TTInit();

    return format;
}


#define VOLUME_VOXWARE_TO_DB(v) \
    (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)


static int TTSetVolume(int volume)
{
    dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
    atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left));
    dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
    atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right));
    return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
           (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8);
}


#define GAIN_VOXWARE_TO_DB(v) \
    (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)

static int TTSetGain(int gain)
{
    dmasound.gain = GAIN_VOXWARE_TO_DB(gain);
    atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain));
    return GAIN_DB_TO_VOXWARE(dmasound.gain);
}



/*
 * Falcon
 */


static void FalconSilence(void)
{
    /* stop playback, set sample rate 50kHz for PSG sound */
    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
    tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
    tt_dmasnd.int_div = 0; /* STE compatible divider */
    tt_dmasnd.int_ctrl = 0x0;
    tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
    tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
    tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
    tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
}


static void FalconInit(void)
{
    int divider, i, idx;
    const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};

    /* search a frequency that fits into the allowed error range */

    idx = -1;
    for (i = 0; i < ARRAY_SIZE(freq); i++)
        /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
         * be playable without expanding, but that now a kernel runtime
         * option
         */
        if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
            idx = i;
    if (idx > -1) {
        dmasound.soft.speed = freq[idx];
        dmasound.trans_write = &transFalconNormal;
    } else
        dmasound.trans_write = &transFalconExpanding;

    FalconSilence();
    dmasound.hard = dmasound.soft;

    if (dmasound.hard.size == 16) {
        /* the Falcon can play 16bit samples only in stereo */
        dmasound.hard.stereo = 1;
    }

    if (dmasound.hard.speed > 49170) {
        /* we would need to squeeze the sound, but we won't do that */
        dmasound.hard.speed = 49170;
        divider = 1;
        dmasound.trans_write = &transFalconNormal;
    } else if (dmasound.hard.speed > 32780) {
        dmasound.hard.speed = 49170;
        divider = 1;
    } else if (dmasound.hard.speed > 24585) {
        dmasound.hard.speed = 32780;
        divider = 2;
    } else if (dmasound.hard.speed > 19668) {
        dmasound.hard.speed = 24585;
        divider = 3;
    } else if (dmasound.hard.speed > 16390) {
        dmasound.hard.speed = 19668;
        divider = 4;
    } else if (dmasound.hard.speed > 12292) {
        dmasound.hard.speed = 16390;
        divider = 5;
    } else if (dmasound.hard.speed > 9834) {
        dmasound.hard.speed = 12292;
        divider = 7;
    } else if (dmasound.hard.speed > 8195) {
        dmasound.hard.speed = 9834;
        divider = 9;
    } else {
        dmasound.hard.speed = 8195;
        divider = 11;
    }
    tt_dmasnd.int_div = divider;

    /* Setup Falcon sound DMA for playback */
    tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
    tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
    tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
    tt_dmasnd.cbar_dst = 0x0000;
    tt_dmasnd.rec_track_select = 0;
    tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
    tt_dmasnd.adc_src = 0; /* ADC Input = Mic */

    tt_dmasnd.mode = (dmasound.hard.stereo ?
              DMASND_MODE_STEREO : DMASND_MODE_MONO) |
        ((dmasound.hard.size == 8) ?
         DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
        DMASND_MODE_6KHZ;

    expand_bal = -dmasound.soft.speed;
}


static int FalconSetFormat(int format)
{
    int size;
    /* Falcon sound DMA supports 8bit and 16bit modes */

    switch (format) {
    case AFMT_QUERY:
        return dmasound.soft.format;
    case AFMT_MU_LAW:
    case AFMT_A_LAW:
    case AFMT_U8:
    case AFMT_S8:
        size = 8;
        break;
    case AFMT_S16_BE:
    case AFMT_U16_BE:
    case AFMT_S16_LE:
    case AFMT_U16_LE:
        size = 16;
        break;
    default: /* :-) */
        size = 8;
        format = AFMT_S8;
    }

    dmasound.soft.format = format;
    dmasound.soft.size = size;
    if (dmasound.minDev == SND_DEV_DSP) {
        dmasound.dsp.format = format;
        dmasound.dsp.size = dmasound.soft.size;
    }

    FalconInit();

    return format;
}


/* This is for the Falcon output *attenuation* in 1.5dB steps,
 * i.e. output level from 0 to -22.5dB in -1.5dB steps.
 */
#define VOLUME_VOXWARE_TO_ATT(v) \
    ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)


static int FalconSetVolume(int volume)
{
    dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
    dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
    tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;
    return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
           VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;
}


static void AtaPlayNextFrame(int index)
{
    char *start, *end;

    /* used by AtaPlay() if all doubts whether there really is something
     * to be played are already wiped out.
     */
    start = write_sq.buffers[write_sq.front];
    end = start+((write_sq.count == index) ? write_sq.rear_size
                           : write_sq.block_size);
    /* end might not be a legal virtual address. */
    DMASNDSetEnd(virt_to_phys(end - 1) + 1);
    DMASNDSetBase(virt_to_phys(start));
    /* Since only an even number of samples per frame can
       be played, we might lose one byte here. (TO DO) */
    write_sq.front = (write_sq.front+1) % write_sq.max_count;
    write_sq.active++;
    tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
}


static void AtaPlay(void)
{
    /* ++TeSche: Note that write_sq.active is no longer just a flag but
     * holds the number of frames the DMA is currently programmed for
     * instead, may be 0, 1 (currently being played) or 2 (pre-programmed).
     *
     * Changes done to write_sq.count and write_sq.active are a bit more
     * subtle again so now I must admit I also prefer disabling the irq
     * here rather than considering all possible situations. But the point
     * is that disabling the irq doesn't have any bad influence on this
     * version of the driver as we benefit from having pre-programmed the
     * DMA wherever possible: There's no need to reload the DMA at the
     * exact time of an interrupt but only at some time while the
     * pre-programmed frame is playing!
     */
    atari_disable_irq(IRQ_MFP_TIMA);

    if (write_sq.active == 2 ||    /* DMA is 'full' */
        write_sq.count <= 0) {    /* nothing to do */
        atari_enable_irq(IRQ_MFP_TIMA);
        return;
    }

    if (write_sq.active == 0) {
        /* looks like there's nothing 'in' the DMA yet, so try
         * to put two frames into it (at least one is available).
         */
        if (write_sq.count == 1 &&
            write_sq.rear_size < write_sq.block_size &&
            !write_sq.syncing) {
            /* hmmm, the only existing frame is not
             * yet filled and we're not syncing?
             */
            atari_enable_irq(IRQ_MFP_TIMA);
            return;
        }
        AtaPlayNextFrame(1);
        if (write_sq.count == 1) {
            /* no more frames */
            atari_enable_irq(IRQ_MFP_TIMA);
            return;
        }
        if (write_sq.count == 2 &&
            write_sq.rear_size < write_sq.block_size &&
            !write_sq.syncing) {
            /* hmmm, there were two frames, but the second
             * one is not yet filled and we're not syncing?
             */
            atari_enable_irq(IRQ_MFP_TIMA);
            return;
        }
        AtaPlayNextFrame(2);
    } else {
        /* there's already a frame being played so we may only stuff
         * one new into the DMA, but even if this may be the last
         * frame existing the previous one is still on write_sq.count.
         */
        if (write_sq.count == 2 &&
            write_sq.rear_size < write_sq.block_size &&
            !write_sq.syncing) {
            /* hmmm, the only existing frame is not
             * yet filled and we're not syncing?
             */
            atari_enable_irq(IRQ_MFP_TIMA);
            return;
        }
        AtaPlayNextFrame(2);
    }
    atari_enable_irq(IRQ_MFP_TIMA);
}


static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
{
#if 0
    /* ++TeSche: if you should want to test this... */
    static int cnt = 0;
    if (write_sq.active == 2)
        if (++cnt == 10) {
            /* simulate losing an interrupt */
            cnt = 0;
            return;
        }
#endif

    if (write_sq_ignore_int && is_falcon) {
        /* ++TeSche: Falcon only: ignore first irq because it comes
         * immediately after starting a frame. after that, irqs come
         * (almost) like on the TT.
         */
        write_sq_ignore_int = 0;
        return;
    }

    if (!write_sq.active) {
        /* playing was interrupted and sq_reset() has already cleared
         * the sq variables, so better don't do anything here.
         */
        WAKE_UP(write_sq.sync_queue);
        return;
    }

    /* Probably ;) one frame is finished. Well, in fact it may be that a
     * pre-programmed one is also finished because there has been a long
     * delay in interrupt delivery and we've completely lost one, but
     * there's no way to detect such a situation. In such a case the last
     * frame will be played more than once and the situation will recover
     * as soon as the irq gets through.
     */
    write_sq.count--;
    write_sq.active--;

    if (!write_sq.active) {
        tt_dmasnd.ctrl = DMASND_CTRL_OFF;
        write_sq_ignore_int = 1;
    }

    WAKE_UP(write_sq.action_queue);
    /* At least one block of the queue is free now
       so wake up a writing process blocked because
       of a full queue. */

    if ((write_sq.active != 1) || (write_sq.count != 1))
        /* We must be a bit carefully here: write_sq.count indicates the
         * number of buffers used and not the number of frames to be
         * played. If write_sq.count==1 and write_sq.active==1 that
         * means the only remaining frame was already programmed
         * earlier (and is currently running) so we mustn't call
         * AtaPlay() here, otherwise we'll play one frame too much.
         */
        AtaPlay();

    if (!write_sq.active) WAKE_UP(write_sq.sync_queue);
    /* We are not playing after AtaPlay(), so there
       is nothing to play any more. Wake up a process
       waiting for audio output to drain. */
}


/*** Mid level stuff *********************************************************/


/*
 * /dev/mixer abstraction
 */

#define RECLEVEL_VOXWARE_TO_GAIN(v)    \
    ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
#define RECLEVEL_GAIN_TO_VOXWARE(v)    (((v) * 20 + 2) / 3)


static void __init TTMixerInit(void)
{
    atari_microwire_cmd(MW_LM1992_VOLUME(0));
    dmasound.volume_left = 0;
    atari_microwire_cmd(MW_LM1992_BALLEFT(0));
    dmasound.volume_right = 0;
    atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
    atari_microwire_cmd(MW_LM1992_TREBLE(0));
    atari_microwire_cmd(MW_LM1992_BASS(0));
}

static void __init FalconMixerInit(void)
{
    dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
    dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
}

static int AtaMixerIoctl(u_int cmd, u_long arg)
{
    int data;
    switch (cmd) {
        case SOUND_MIXER_READ_SPEAKER:
            if (is_falcon || MACH_IS_TT) {
                int porta;
                cli();
                sound_ym.rd_data_reg_sel = 14;
                porta = sound_ym.rd_data_reg_sel;
                sti();
                return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
            }
            break;
        case SOUND_MIXER_WRITE_VOLUME:
            IOCTL_IN(arg, data);
            return IOCTL_OUT(arg, dmasound_set_volume(data));
        case SOUND_MIXER_WRITE_SPEAKER:
            if (is_falcon || MACH_IS_TT) {
                int porta;
                IOCTL_IN(arg, data);
                cli();
                sound_ym.rd_data_reg_sel = 14;
                porta = (sound_ym.rd_data_reg_sel & ~0x40) |
                    (data < 50 ? 0x40 : 0);
                sound_ym.wd_data = porta;
                sti();
                return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
            }
    }
    return -EINVAL;
}


static int TTMixerIoctl(u_int cmd, u_long arg)
{
    int data;
    switch (cmd) {
        case SOUND_MIXER_READ_RECMASK:
        return IOCTL_OUT(arg, 0);
        case SOUND_MIXER_READ_DEVMASK:
        return IOCTL_OUT(arg,
                 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
                 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
        case SOUND_MIXER_READ_STEREODEVS:
        return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
        case SOUND_MIXER_READ_VOLUME:
        return IOCTL_OUT(arg,
                 VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
                 (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));
        case SOUND_MIXER_READ_BASS:
        return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));
        case SOUND_MIXER_READ_TREBLE:
        return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));
        case SOUND_MIXER_READ_OGAIN:
        return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));
        case SOUND_MIXER_WRITE_BASS:
        IOCTL_IN(arg, data);
        return IOCTL_OUT(arg, dmasound_set_bass(data));
        case SOUND_MIXER_WRITE_TREBLE:
        IOCTL_IN(arg, data);
        return IOCTL_OUT(arg, dmasound_set_treble(data));
        case SOUND_MIXER_WRITE_OGAIN:
        IOCTL_IN(arg, data);
        return IOCTL_OUT(arg, dmasound_set_gain(data));
    }
    return AtaMixerIoctl(cmd, arg);
}

static int FalconMixerIoctl(u_int cmd, u_long arg)
{
    int data;
    switch (cmd) {
        case SOUND_MIXER_READ_RECMASK:
        return IOCTL_OUT(arg, SOUND_MASK_MIC);
        case SOUND_MIXER_READ_DEVMASK:
        return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
        case SOUND_MIXER_READ_STEREODEVS:
        return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
        case SOUND_MIXER_READ_VOLUME:
        return IOCTL_OUT(arg,
            VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
            VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);
        case SOUND_MIXER_READ_CAPS:
        return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
        case SOUND_MIXER_WRITE_MIC:
        IOCTL_IN(arg, data);
        tt_dmasnd.input_gain =
            RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
            RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
        /* fall thru, return set value */
        case SOUND_MIXER_READ_MIC:
        return IOCTL_OUT(arg,
            RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
            RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
    }
    return AtaMixerIoctl(cmd, arg);
}

static int AtaWriteSqSetup(void)
{
    write_sq_ignore_int = 0;
    return 0 ;
}

static int AtaSqOpen(mode_t mode)
{
    write_sq_ignore_int = 1;
    return 0 ;
}

static int TTStateInfo(char *buffer, size_t space)
{
    int len = 0;
    len += sprintf(buffer+len, "\tvol left  %ddB [-40...  0]\n",
               dmasound.volume_left);
    len += sprintf(buffer+len, "\tvol right %ddB [-40...  0]\n",
               dmasound.volume_right);
    len += sprintf(buffer+len, "\tbass      %ddB [-12...+12]\n",
               dmasound.bass);
    len += sprintf(buffer+len, "\ttreble    %ddB [-12...+12]\n",
               dmasound.treble);
    if (len >= space) {
        printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;
        len = space ;
    }
    return len;
}

static int FalconStateInfo(char *buffer, size_t space)
{
    int len = 0;
    len += sprintf(buffer+len, "\tvol left  %ddB [-22.5 ... 0]\n",
               dmasound.volume_left);
    len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n",
               dmasound.volume_right);
    if (len >= space) {
        printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ;
        len = space ;
    }
    return len;
}


/*** Machine definitions *****************************************************/

static SETTINGS def_hard_falcon = {
    format: AFMT_S8,
    stereo: 0,
    size: 8,
    speed: 8195
} ;

static SETTINGS def_hard_tt = {
    format: AFMT_S8,
    stereo: 0,
    size: 8,
    speed: 12517
} ;

static SETTINGS def_soft = {
    format: AFMT_U8,
    stereo: 0,
    size: 8,
    speed: 8000
} ;

static MACHINE machTT = {
    name:        "Atari",
    name2:        "TT",
    open:        AtaOpen,
    release:    AtaRelease,
    dma_alloc:    AtaAlloc,
    dma_free:    AtaFree,
    irqinit:    AtaIrqInit,
#ifdef MODULE
    irqcleanup:    AtaIrqCleanUp,
#endif /* MODULE */
    init:        TTInit,
    silence:    TTSilence,
    setFormat:    TTSetFormat,
    setVolume:    TTSetVolume,
    setBass:    AtaSetBass,
    setTreble:    AtaSetTreble,
    setGain:    TTSetGain,
    play:        AtaPlay,
    mixer_init:    TTMixerInit,
    mixer_ioctl:    TTMixerIoctl,
    write_sq_setup:    AtaWriteSqSetup,
    sq_open:    AtaSqOpen,
    state_info:    TTStateInfo,
    min_dsp_speed:    6258,
    version:    ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),
    hardware_afmts:    AFMT_S8,  /* h'ware-supported formats *only* here */
    capabilities:     DSP_CAP_BATCH    /* As per SNDCTL_DSP_GETCAPS */
};

static MACHINE machFalcon = {
    name:        "Atari",
    name2:        "FALCON",
    dma_alloc:    AtaAlloc,
    dma_free:    AtaFree,
    irqinit:    AtaIrqInit,
#ifdef MODULE
    irqcleanup:    AtaIrqCleanUp,
#endif /* MODULE */
    init:        FalconInit,
    silence:    FalconSilence,
    setFormat:    FalconSetFormat,
    setVolume:    FalconSetVolume,
    setBass:    AtaSetBass,
    setTreble:    AtaSetTreble,
    play:        AtaPlay,
    mixer_init:    FalconMixerInit,
    mixer_ioctl:    FalconMixerIoctl,
    write_sq_setup:    AtaWriteSqSetup,
    sq_open:    AtaSqOpen,
    state_info:    FalconStateInfo,
    min_dsp_speed:    8195,
    version:    ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION),
    hardware_afmts:    (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */
    capabilities:     DSP_CAP_BATCH    /* As per SNDCTL_DSP_GETCAPS */
};


/*** Config & Setup **********************************************************/


static int __init dmasound_atari_init(void)
{
    if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {
        if (ATARIHW_PRESENT(CODEC)) {
        dmasound.mach = machFalcon;
        dmasound.mach.default_soft = def_soft ;
        dmasound.mach.default_hard = def_hard_falcon ;
        is_falcon = 1;
        } else if (ATARIHW_PRESENT(MICROWIRE)) {
        dmasound.mach = machTT;
        dmasound.mach.default_soft = def_soft ;
        dmasound.mach.default_hard = def_hard_tt ;
        is_falcon = 0;
        } else
        return -ENODEV;
        if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
        return dmasound_init();
        else {
        printk("DMA sound driver: Timer A interrupt already in use\n");
        return -EBUSY;
        }
    }
    return -ENODEV;
}

static void __exit dmasound_atari_cleanup(void)
{
    dmasound_deinit();
}

module_init(dmasound_atari_init);
module_exit(dmasound_atari_cleanup);
MODULE_LICENSE("GPL");

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0271 ]--