📄 dmasound_atari.c
字号:
/* * linux/sound/oss/dmasound/dmasound_atari.c * * Atari TT and Falcon DMA Sound Driver * * See linux/sound/oss/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 <linux/spinlock.h>#include <linux/interrupt.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 3extern void atari_microwire_cmd(int cmd);static int is_falcon;static int write_sq_ignore_int; /* ++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 *AtaAlloc(unsigned int size, int flags);static void AtaFree(void *, unsigned int size);static int AtaIrqInit(void);#ifdef MODULEstatic 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 irqreturn_t 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 int 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -