Commit 89728e0e authored by Andrew Morton's avatar Andrew Morton Committed by Greg Kroah-Hartman

[PATCH] ppc32: Update PowerMac dmasound driver

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

This patch was missing from my big merge.  It updates the PowerMac
"dmasound" driver.  Adds input support for some recent machines using the
tas3004 coded/mixer chip.  Code mostly written by Renzo Davoli.

This driver isn't (unfortunately) fully obsoleted by the Alsa one.  There
are lots of reports of the Alsa one not working properly on various
PowerMac machines, and some people are unhappy with Alsa in general, enough
to have ported the messy PowerMac dmasound to 2.6 :)
parent 29052d81
...@@ -273,4 +273,11 @@ static inline void wait_ms(unsigned int ms) ...@@ -273,4 +273,11 @@ static inline void wait_ms(unsigned int ms)
schedule_timeout(1 + ms * HZ / 1000); schedule_timeout(1 + ms * HZ / 1000);
} }
#define SW_INPUT_VOLUME_SCALE 4
#define SW_INPUT_VOLUME_DEFAULT (128 / SW_INPUT_VOLUME_SCALE)
extern int expand_bal; /* Balance factor for expanding (not volume!) */
extern int expand_read_bal; /* Balance factor for reading */
extern uint software_input_volume; /* software implemented recording volume! */
#endif /* _dmasound_h_ */ #endif /* _dmasound_h_ */
...@@ -52,6 +52,10 @@ ...@@ -52,6 +52,10 @@
* - Support for snapper & better tumbler integration by Toby Sargeant * - Support for snapper & better tumbler integration by Toby Sargeant
* - Headphone detect for scremer by Julien Blache * - Headphone detect for scremer by Julien Blache
* - More tumbler fixed by Andreas Schwab * - More tumbler fixed by Andreas Schwab
* 11/29/2003 [0.8.1] - Renzo Davoli (King Enzo)
* - Support for Snapper line in
* - snapper input resampling (for rates < 44100)
* - software line gain control
*/ */
/* GENERAL FIXME/TODO: check that the assumptions about what is written to /* GENERAL FIXME/TODO: check that the assumptions about what is written to
...@@ -76,6 +80,7 @@ ...@@ -76,6 +80,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#ifdef CONFIG_ADB_CUDA #ifdef CONFIG_ADB_CUDA
#include <linux/cuda.h> #include <linux/cuda.h>
...@@ -119,7 +124,6 @@ static volatile u32 *i2s; ...@@ -119,7 +124,6 @@ static volatile u32 *i2s;
static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
static int awacs_rate_index; static int awacs_rate_index;
static int awacs_subframe; static int awacs_subframe;
static int awacs_spkr_vol;
static struct device_node* awacs_node; static struct device_node* awacs_node;
static struct device_node* i2s_node; static struct device_node* i2s_node;
...@@ -264,6 +268,7 @@ struct pmu_sleep_notifier awacs_sleep_notifier = { ...@@ -264,6 +268,7 @@ struct pmu_sleep_notifier awacs_sleep_notifier = {
/* for (soft) sample rate translations */ /* for (soft) sample rate translations */
int expand_bal; /* Balance factor for expanding (not volume!) */ int expand_bal; /* Balance factor for expanding (not volume!) */
int expand_read_bal; /* Balance factor for expanding reads (not volume!) */
/*** Low level stuff *********************************************************/ /*** Low level stuff *********************************************************/
...@@ -285,8 +290,6 @@ static irqreturn_t pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs); ...@@ -285,8 +290,6 @@ static irqreturn_t pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
static void awacs_write(int val); static void awacs_write(int val);
static int awacs_get_volume(int reg, int lshift); static int awacs_get_volume(int reg, int lshift);
static int awacs_volume_setter(int volume, int n, int mute, int lshift); static int awacs_volume_setter(int volume, int n, int mute, int lshift);
static void awacs_mksound(unsigned int hz, unsigned int ticks);
static void awacs_nosound(unsigned long xx);
/*** Mid level stuff **********************************************************/ /*** Mid level stuff **********************************************************/
...@@ -299,6 +302,7 @@ static void PMacAbortRead(void); ...@@ -299,6 +302,7 @@ static void PMacAbortRead(void);
extern TRANS transAwacsNormal ; extern TRANS transAwacsNormal ;
extern TRANS transAwacsExpand ; extern TRANS transAwacsExpand ;
extern TRANS transAwacsNormalRead ; extern TRANS transAwacsNormalRead ;
extern TRANS transAwacsExpandRead ;
extern int daca_init(void); extern int daca_init(void);
extern void daca_cleanup(void); extern void daca_cleanup(void);
...@@ -545,11 +549,15 @@ tas_mixer_ioctl(u_int cmd, u_long arg) ...@@ -545,11 +549,15 @@ tas_mixer_ioctl(u_int cmd, u_long arg)
rc = IOCTL_OUT(arg, 0); rc = IOCTL_OUT(arg, 0);
break; break;
case SOUND_MIXER_READ_RECMASK: case SOUND_MIXER_READ_RECMASK:
data = 0; // XXX FIXME: find a way to check what is really available */
data = SOUND_MASK_LINE | SOUND_MASK_MIC;
rc = IOCTL_OUT(arg, data); rc = IOCTL_OUT(arg, data);
break; break;
case SOUND_MIXER_READ_RECSRC: case SOUND_MIXER_READ_RECSRC:
data = 0; if (awacs_reg[0] & MASK_MUX_AUDIN)
data |= SOUND_MASK_LINE;
if (awacs_reg[0] & MASK_MUX_MIC)
data |= SOUND_MASK_MIC;
rc = IOCTL_OUT(arg, data); rc = IOCTL_OUT(arg, data);
break; break;
case SOUND_MIXER_WRITE_RECSRC: case SOUND_MIXER_WRITE_RECSRC:
...@@ -799,11 +807,13 @@ static void PMacInit(void) ...@@ -799,11 +807,13 @@ static void PMacInit(void)
set_frame_rate(dmasound.soft.speed, catchRadius) ; set_frame_rate(dmasound.soft.speed, catchRadius) ;
tolerance = (catchRadius * dmasound.hard.speed) / 100; tolerance = (catchRadius * dmasound.hard.speed) / 100;
if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) {
dmasound.trans_write = &transAwacsNormal; dmasound.trans_write = &transAwacsNormal;
else
dmasound.trans_write = &transAwacsExpand;
dmasound.trans_read = &transAwacsNormalRead; dmasound.trans_read = &transAwacsNormalRead;
} else {
dmasound.trans_write = &transAwacsExpand;
dmasound.trans_read = &transAwacsExpandRead;
}
if (awacs) { if (awacs) {
if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
...@@ -813,6 +823,7 @@ static void PMacInit(void) ...@@ -813,6 +823,7 @@ static void PMacInit(void)
} }
expand_bal = -dmasound.soft.speed; expand_bal = -dmasound.soft.speed;
expand_read_bal = -dmasound.soft.speed;
} }
static int PMacSetFormat(int format) static int PMacSetFormat(int format)
...@@ -1280,15 +1291,14 @@ static void awacs_nosound(unsigned long xx) ...@@ -1280,15 +1291,14 @@ static void awacs_nosound(unsigned long xx)
spin_unlock_irqrestore(&dmasound.lock, flags); spin_unlock_irqrestore(&dmasound.lock, flags);
} }
static struct timer_list beep_timer = TIMER_INITIALIZER(awacs_nosound, 0, 0); /*
* We generate the beep with a single dbdma command that loops a buffer
#if 0 /* would need to go through the input layer in 2.6, later.. --hch */ * forever - without generating interrupts.
/* we generate the beep with a single dbdma command that loops a buffer *
forever - without generating interrupts. * So, to stop it you have to stop dma output as per awacs_nosound.
So, to stop it you have to stop dma output as per awacs_nosound. */
*/ static int awacs_beep_event(struct input_dev *dev, unsigned int type,
unsigned int code, int hz)
static void awacs_mksound(unsigned int hz, unsigned int ticks)
{ {
unsigned long flags; unsigned long flags;
int beep_speed = 0; int beep_speed = 0;
...@@ -1300,8 +1310,21 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) ...@@ -1300,8 +1310,21 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
static int beep_nsamples_cache; static int beep_nsamples_cache;
static int beep_volume_cache; static int beep_volume_cache;
if (type != EV_SND)
return -1;
switch (code) {
case SND_BELL:
if (hz)
hz = 1000;
break;
case SND_TONE:
break;
default:
return -1;
}
if (beep_buf == NULL) if (beep_buf == NULL)
return; return -1;
/* quick-hack fix for DACA, Burgundy & Tumbler */ /* quick-hack fix for DACA, Burgundy & Tumbler */
...@@ -1313,26 +1336,17 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) ...@@ -1313,26 +1336,17 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
beep_speed = i; beep_speed = i;
srate = awacs_freqs[beep_speed]; srate = awacs_freqs[beep_speed];
} }
if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
#if 1
/* this is a hack for broken X server code */
hz = 750;
ticks = 12;
#else
/* cancel beep currently playing */ /* cancel beep currently playing */
awacs_nosound(0); awacs_nosound(0);
return; return 0;
#endif
} }
spin_lock_irqsave(&dmasound.lock, flags); spin_lock_irqsave(&dmasound.lock, flags);
del_timer(&beep_timer);
if (ticks) {
beep_timer.expires = jiffies + ticks;
add_timer(&beep_timer);
}
if (beep_playing || write_sq.active || beep_buf == NULL) { if (beep_playing || write_sq.active || beep_buf == NULL) {
spin_unlock_irqrestore(&dmasound.lock, flags); spin_unlock_irqrestore(&dmasound.lock, flags);
return; /* too hard, sorry :-( */ return -1; /* too hard, sorry :-( */
} }
beep_playing = 1; beep_playing = 1;
st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
...@@ -1375,8 +1389,9 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) ...@@ -1375,8 +1389,9 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
out_le32(&awacs_txdma->control, RUN | (RUN << 16)); out_le32(&awacs_txdma->control, RUN | (RUN << 16));
} }
spin_unlock_irqrestore(&dmasound.lock, flags); spin_unlock_irqrestore(&dmasound.lock, flags);
return 0;
} }
#endif
/* used in init and for wake-up */ /* used in init and for wake-up */
...@@ -1764,7 +1779,6 @@ awacs_enable_amp(int spkr_vol) ...@@ -1764,7 +1779,6 @@ awacs_enable_amp(int spkr_vol)
#ifdef CONFIG_ADB_CUDA #ifdef CONFIG_ADB_CUDA
struct adb_request req; struct adb_request req;
awacs_spkr_vol = spkr_vol;
if (sys_ctrler != SYS_CTRLER_CUDA) if (sys_ctrler != SYS_CTRLER_CUDA)
return; return;
...@@ -2797,6 +2811,17 @@ __init setup_beep(void) ...@@ -2797,6 +2811,17 @@ __init setup_beep(void)
return 0 ; return 0 ;
} }
static struct input_dev awacs_beep_dev = {
.evbit = { BIT(EV_SND) },
.sndbit = { BIT(SND_BELL) | BIT(SND_TONE) },
.event = awacs_beep_event,
.name = "dmasound beeper",
.phys = "macio/input0", /* what the heck is this?? */
.id = {
.bustype = BUS_HOST,
},
};
int __init dmasound_awacs_init(void) int __init dmasound_awacs_init(void)
{ {
struct device_node *io = NULL, *info = NULL; struct device_node *io = NULL, *info = NULL;
...@@ -3086,13 +3111,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); ...@@ -3086,13 +3111,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
/* shut out chips that do output only. /* shut out chips that do output only.
* may need to extend this to machines which have no inputs - even tho' * may need to extend this to machines which have no inputs - even tho'
* they use screamer - IIRC one of the powerbooks is like this. * they use screamer - IIRC one of the powerbooks is like this.
*
* FIXME: Actually, some TUMBLER and SNAPPER do have inputs...
*/ */
if (awacs_revision != AWACS_TUMBLER && if (awacs_revision != AWACS_DACA) {
awacs_revision != AWACS_SNAPPER &&
awacs_revision != AWACS_DACA) {
dmasound.mach.capabilities = DSP_CAP_DUPLEX ; dmasound.mach.capabilities = DSP_CAP_DUPLEX ;
dmasound.mach.record = PMacRecord ; dmasound.mach.record = PMacRecord ;
} }
...@@ -3122,11 +3143,19 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); ...@@ -3122,11 +3143,19 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
break ; break ;
} }
/*
* XXX: we should handle errors here, but that would mean
* rewriting the whole init code. later..
*/
input_register_device(&awacs_beep_dev);
return dmasound_init(); return dmasound_init();
} }
static void __exit dmasound_awacs_cleanup(void) static void __exit dmasound_awacs_cleanup(void)
{ {
input_unregister_device(&awacs_beep_dev);
switch (awacs_revision) { switch (awacs_revision) {
case AWACS_TUMBLER: case AWACS_TUMBLER:
case AWACS_SNAPPER: case AWACS_SNAPPER:
...@@ -3138,6 +3167,7 @@ static void __exit dmasound_awacs_cleanup(void) ...@@ -3138,6 +3167,7 @@ static void __exit dmasound_awacs_cleanup(void)
break; break;
} }
dmasound_deinit(); dmasound_deinit();
} }
MODULE_DESCRIPTION("PowerMac built-in audio driver."); MODULE_DESCRIPTION("PowerMac built-in audio driver.");
......
...@@ -218,6 +218,10 @@ static int state_unit = -1; ...@@ -218,6 +218,10 @@ static int state_unit = -1;
static int irq_installed; static int irq_installed;
#endif /* MODULE */ #endif /* MODULE */
/* software implemented recording volume! */
uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT;
EXPORT_SYMBOL(software_input_volume);
/* control over who can modify resources shared between play/record */ /* control over who can modify resources shared between play/record */
static mode_t shared_resource_owner; static mode_t shared_resource_owner;
static int shared_resources_initialised; static int shared_resources_initialised;
...@@ -238,6 +242,7 @@ static inline int sound_set_format(int format) ...@@ -238,6 +242,7 @@ static inline int sound_set_format(int format)
return dmasound.mach.setFormat(format); return dmasound.mach.setFormat(format);
} }
static int sound_set_speed(int speed) static int sound_set_speed(int speed)
{ {
if (speed < 0) if (speed < 0)
...@@ -1264,15 +1269,13 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, ...@@ -1264,15 +1269,13 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
result = IOCTL_OUT(arg, format); result = IOCTL_OUT(arg, format);
if (result < 0) if (result < 0)
return result; return result;
if (format != data) if (format != data && data != AFMT_QUERY)
return -EINVAL; return -EINVAL;
return 0; return 0;
} else } else
return -EINVAL ; return -EINVAL ;
break ;
case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SUBDIVIDE:
return -EINVAL ; return -EINVAL ;
break;
case SNDCTL_DSP_SETFRAGMENT: case SNDCTL_DSP_SETFRAGMENT:
/* we can do this independently for the two queues - with the /* we can do this independently for the two queues - with the
proviso that for fds opened O_RDWR we cannot separate the proviso that for fds opened O_RDWR we cannot separate the
......
...@@ -5,11 +5,7 @@ ...@@ -5,11 +5,7 @@
* Tobias Sargeant <tobias.sargeant@bigpond.com> * Tobias Sargeant <tobias.sargeant@bigpond.com>
* Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>: * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>:
* *
* TODO: * Input support by Renzo Davoli <renzo@cs.unibo.it>
* -----
* * Enable control over input line 2 (is this connected?)
* * Implement sleep support (at least mute everything and
* * set gains to minimum during sleep)
* *
*/ */
...@@ -293,7 +289,8 @@ tas3004_write_register( struct tas3004_data_t *self, ...@@ -293,7 +289,8 @@ tas3004_write_register( struct tas3004_data_t *self,
{ {
if (reg_num==TAS3004_REG_MCR || if (reg_num==TAS3004_REG_MCR ||
reg_num==TAS3004_REG_BASS || reg_num==TAS3004_REG_BASS ||
reg_num==TAS3004_REG_TREBLE) { reg_num==TAS3004_REG_TREBLE ||
reg_num==TAS3004_REG_ANALOG_CTRL) {
return tas_write_byte_register(&self->super, return tas_write_byte_register(&self->super,
(uint)reg_num, (uint)reg_num,
*data, *data,
...@@ -313,7 +310,8 @@ tas3004_sync_register( struct tas3004_data_t *self, ...@@ -313,7 +310,8 @@ tas3004_sync_register( struct tas3004_data_t *self,
{ {
if (reg_num==TAS3004_REG_MCR || if (reg_num==TAS3004_REG_MCR ||
reg_num==TAS3004_REG_BASS || reg_num==TAS3004_REG_BASS ||
reg_num==TAS3004_REG_TREBLE) { reg_num==TAS3004_REG_TREBLE ||
reg_num==TAS3004_REG_ANALOG_CTRL) {
return tas_sync_byte_register(&self->super, return tas_sync_byte_register(&self->super,
(uint)reg_num, (uint)reg_num,
register_width(reg_num)); register_width(reg_num));
...@@ -354,7 +352,9 @@ tas3004_supported_mixers(struct tas3004_data_t *self) ...@@ -354,7 +352,9 @@ tas3004_supported_mixers(struct tas3004_data_t *self)
SOUND_MASK_ALTPCM | SOUND_MASK_ALTPCM |
SOUND_MASK_IMIX | SOUND_MASK_IMIX |
SOUND_MASK_TREBLE | SOUND_MASK_TREBLE |
SOUND_MASK_BASS; SOUND_MASK_BASS |
SOUND_MASK_MIC |
SOUND_MASK_LINE;
} }
static int static int
...@@ -447,6 +447,28 @@ tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) ...@@ -447,6 +447,28 @@ tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level)
shadow[TAS3004_REG_BASS][0]=temp&0xff; shadow[TAS3004_REG_BASS][0]=temp&0xff;
rc = tas3004_sync_register(self,TAS3004_REG_BASS); rc = tas3004_sync_register(self,TAS3004_REG_BASS);
break; break;
case SOUND_MIXER_MIC:
if ((level&0xff)>0) {
software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
if (self->super.mixer[mixer] == 0) {
self->super.mixer[SOUND_MIXER_LINE] = 0;
shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2;
rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
} else rc=0;
} else {
self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT;
software_input_volume = SW_INPUT_VOLUME_SCALE *
(self->super.mixer[SOUND_MIXER_LINE]&0xff);
shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00;
rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
}
break;
case SOUND_MIXER_LINE:
if (self->super.mixer[SOUND_MIXER_MIC] == 0) {
software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
rc=0;
}
break;
default: default:
rc = -1; rc = -1;
break; break;
...@@ -496,6 +518,7 @@ tas3004_leave_sleep(struct tas3004_data_t *self) ...@@ -496,6 +518,7 @@ tas3004_leave_sleep(struct tas3004_data_t *self)
(void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER);
(void)tas3004_sync_register(self,TAS3004_REG_TREBLE); (void)tas3004_sync_register(self,TAS3004_REG_TREBLE);
(void)tas3004_sync_register(self,TAS3004_REG_BASS); (void)tas3004_sync_register(self,TAS3004_REG_BASS);
(void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
return 0; return 0;
} }
...@@ -1050,6 +1073,8 @@ tas3004_init_mixer(struct tas3004_data_t *self) ...@@ -1050,6 +1073,8 @@ tas3004_init_mixer(struct tas3004_data_t *self)
tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);
tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);
tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT);
return 0; return 0;
} }
...@@ -1064,6 +1089,8 @@ tas3004_uninit_mixer(struct tas3004_data_t *self) ...@@ -1064,6 +1089,8 @@ tas3004_uninit_mixer(struct tas3004_data_t *self)
tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0);
tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);
tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0);
return 0; return 0;
} }
......
...@@ -195,6 +195,9 @@ tas_init(int driver_id, const char *driver_name) ...@@ -195,6 +195,9 @@ tas_init(int driver_id, const char *driver_name)
printk(KERN_INFO "tas driver [%s])\n", driver_name); printk(KERN_INFO "tas driver [%s])\n", driver_name);
#ifndef CONFIG_I2C_KEYWEST
request_module("i2c-keywest");
#endif
tas_node = find_devices("deq"); tas_node = find_devices("deq");
if (tas_node == NULL) if (tas_node == NULL)
return -ENODEV; return -ENODEV;
......
...@@ -87,7 +87,7 @@ struct tas_gain_t ...@@ -87,7 +87,7 @@ struct tas_gain_t
unsigned int *mixer; unsigned int *mixer;
}; };
typedef char tas_shadow_t[16]; typedef char tas_shadow_t[0x45];
struct tas_data_t struct tas_data_t
{ {
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
* *
* 08/02/2001 Iain Sandoe * 08/02/2001 Iain Sandoe
* split from dmasound_awacs.c * split from dmasound_awacs.c
* 11/29/2003 Renzo Davoli (King Enzo)
* - input resampling (for soft rate < hard rate)
* - software line in gain control
*/ */
#include <linux/soundcard.h> #include <linux/soundcard.h>
...@@ -58,7 +61,6 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, ...@@ -58,7 +61,6 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
/*** Translations ************************************************************/ /*** Translations ************************************************************/
extern int expand_bal; /* Balance factor for expanding (not volume!) */
static int expand_data; /* Data for expanding */ static int expand_data; /* Data for expanding */
static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
...@@ -461,11 +463,13 @@ static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount, ...@@ -461,11 +463,13 @@ static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
u_char data; u_char data;
val = *p++; val = *p++;
val = (val * software_input_volume) >> 7;
data = val >> 8; data = val >> 8;
if (put_user(data, (u_char *)userPtr++)) if (put_user(data, (u_char *)userPtr++))
return -EFAULT; return -EFAULT;
if (stereo) { if (stereo) {
val = *p; val = *p;
val = (val * software_input_volume) >> 7;
data = val >> 8; data = val >> 8;
if (put_user(data, (u_char *)userPtr++)) if (put_user(data, (u_char *)userPtr++))
return -EFAULT; return -EFAULT;
...@@ -494,11 +498,13 @@ static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount, ...@@ -494,11 +498,13 @@ static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
u_char data; u_char data;
val = *p++; val = *p++;
val = (val * software_input_volume) >> 7;
data = (val >> 8) ^ 0x80; data = (val >> 8) ^ 0x80;
if (put_user(data, (u_char *)userPtr++)) if (put_user(data, (u_char *)userPtr++))
return -EFAULT; return -EFAULT;
if (stereo) { if (stereo) {
val = *p; val = *p;
val = (val * software_input_volume) >> 7;
data = (val >> 8) ^ 0x80; data = (val >> 8) ^ 0x80;
if (put_user(data, (u_char *)userPtr++)) if (put_user(data, (u_char *)userPtr++))
return -EFAULT; return -EFAULT;
...@@ -517,23 +523,26 @@ static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, ...@@ -517,23 +523,26 @@ static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
ssize_t count, used; ssize_t count, used;
int stereo = dmasound.soft.stereo; int stereo = dmasound.soft.stereo;
short *fp = (short *) &frame[*frameUsed]; short *fp = (short *) &frame[*frameUsed];
short *up = (short *) userPtr;
frameLeft >>= 2; frameLeft >>= 2;
userCount >>= (stereo? 2: 1); userCount >>= (stereo? 2: 1);
used = count = min_t(unsigned long, userCount, frameLeft); used = count = min_t(unsigned long, userCount, frameLeft);
if (!stereo) {
short *up = (short *) userPtr;
while (count > 0) { while (count > 0) {
short data; short data;
data = *fp++;
data = (data * software_input_volume) >> 7;
if (put_user(data, up++))
return -EFAULT;
if (stereo) {
data = *fp; data = *fp;
data = (data * software_input_volume) >> 7;
if (put_user(data, up++)) if (put_user(data, up++))
return -EFAULT; return -EFAULT;
fp+=2;
count--;
} }
} else { fp++;
if (copy_to_user((u_char *)userPtr, fp, count * 4)) count--;
return -EFAULT;
} }
*frameUsed += used * 4; *frameUsed += used * 4;
return stereo? used * 4: used * 2; return stereo? used * 4: used * 2;
...@@ -556,11 +565,13 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, ...@@ -556,11 +565,13 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
int data; int data;
data = *fp++; data = *fp++;
data = (data * software_input_volume) >> 7;
data ^= mask; data ^= mask;
if (put_user(data, up++)) if (put_user(data, up++))
return -EFAULT; return -EFAULT;
if (stereo) { if (stereo) {
data = *fp; data = *fp;
data = (data * software_input_volume) >> 7;
data ^= mask; data ^= mask;
if (put_user(data, up++)) if (put_user(data, up++))
return -EFAULT; return -EFAULT;
...@@ -572,6 +583,204 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, ...@@ -572,6 +583,204 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
return stereo? used * 4: used * 2; return stereo? used * 4: used * 2;
} }
/* data in routines (reducing speed)... */
static ssize_t pmac_ctx_s8_read(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft)
{
short *p = (short *) &frame[*frameUsed];
int bal = expand_read_bal;
int vall,valr, stereo = dmasound.soft.stereo;
int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
int utotal, ftotal;
frameLeft >>= 2;
if (stereo)
userCount >>= 1;
ftotal = frameLeft;
utotal = userCount;
while (frameLeft) {
u_char data;
if (bal<0 && userCount == 0)
break;
vall = *p++;
vall = (vall * software_input_volume) >> 7;
if (stereo) {
valr = *p;
valr = (valr * software_input_volume) >> 7;
}
p++;
if (bal < 0) {
data = vall >> 8;
if (put_user(data, (u_char *)userPtr++))
return -EFAULT;
if (stereo) {
data = valr >> 8;
if (put_user(data, (u_char *)userPtr++))
return -EFAULT;
}
userCount--;
bal += hSpeed;
}
frameLeft--;
bal -= sSpeed;
}
expand_read_bal=bal;
*frameUsed += (ftotal - frameLeft) * 4;
utotal -= userCount;
return stereo? utotal * 2: utotal;
}
static ssize_t pmac_ctx_u8_read(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft)
{
short *p = (short *) &frame[*frameUsed];
int bal = expand_read_bal;
int vall,valr, stereo = dmasound.soft.stereo;
int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
int utotal, ftotal;
frameLeft >>= 2;
if (stereo)
userCount >>= 1;
ftotal = frameLeft;
utotal = userCount;
while (frameLeft) {
u_char data;
if (bal<0 && userCount == 0)
break;
vall = *p++;
vall = (vall * software_input_volume) >> 7;
if (stereo) {
valr = *p;
valr = (valr * software_input_volume) >> 7;
}
p++;
if (bal < 0) {
data = (vall >> 8) ^ 0x80;
if (put_user(data, (u_char *)userPtr++))
return -EFAULT;
if (stereo) {
data = (valr >> 8) ^ 0x80;
if (put_user(data, (u_char *)userPtr++))
return -EFAULT;
}
userCount--;
bal += hSpeed;
}
frameLeft--;
bal -= sSpeed;
}
expand_read_bal=bal;
*frameUsed += (ftotal - frameLeft) * 4;
utotal -= userCount;
return stereo? utotal * 2: utotal;
}
static ssize_t pmac_ctx_s16_read(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft)
{
int bal = expand_read_bal;
short *fp = (short *) &frame[*frameUsed];
short *up = (short *) userPtr;
int stereo = dmasound.soft.stereo;
int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
int utotal, ftotal;
frameLeft >>= 2;
userCount >>= (stereo? 2: 1);
ftotal = frameLeft;
utotal = userCount;
while (frameLeft) {
int datal,datar;
if (bal<0 && userCount == 0)
break;
datal = *fp++;
datal = (datal * software_input_volume) >> 7;
if (stereo) {
datar = *fp;
datar = (datar * software_input_volume) >> 7;
}
fp++;
if (bal < 0) {
if (put_user(datal, up++))
return -EFAULT;
if (stereo) {
if (put_user(datar, up++))
return -EFAULT;
}
userCount--;
bal += hSpeed;
}
frameLeft--;
bal -= sSpeed;
}
expand_read_bal=bal;
*frameUsed += (ftotal - frameLeft) * 4;
utotal -= userCount;
return stereo? utotal * 4: utotal * 2;
}
static ssize_t pmac_ctx_u16_read(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft)
{
int bal = expand_read_bal;
int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
short *fp = (short *) &frame[*frameUsed];
short *up = (short *) userPtr;
int stereo = dmasound.soft.stereo;
int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
int utotal, ftotal;
frameLeft >>= 2;
userCount >>= (stereo? 2: 1);
ftotal = frameLeft;
utotal = userCount;
while (frameLeft) {
int datal,datar;
if (bal<0 && userCount == 0)
break;
datal = *fp++;
datal = (datal * software_input_volume) >> 7;
datal ^= mask;
if (stereo) {
datar = *fp;
datar = (datar * software_input_volume) >> 7;
datar ^= mask;
}
fp++;
if (bal < 0) {
if (put_user(datal, up++))
return -EFAULT;
if (stereo) {
if (put_user(datar, up++))
return -EFAULT;
}
userCount--;
bal += hSpeed;
}
frameLeft--;
bal -= sSpeed;
}
expand_read_bal=bal;
*frameUsed += (ftotal - frameLeft) * 4;
utotal -= userCount;
return stereo? utotal * 4: utotal * 2;
}
TRANS transAwacsNormal = { TRANS transAwacsNormal = {
.ct_ulaw= pmac_ct_law, .ct_ulaw= pmac_ct_law,
.ct_alaw= pmac_ct_law, .ct_alaw= pmac_ct_law,
...@@ -603,6 +812,15 @@ TRANS transAwacsNormalRead = { ...@@ -603,6 +812,15 @@ TRANS transAwacsNormalRead = {
.ct_u16le= pmac_ct_u16_read, .ct_u16le= pmac_ct_u16_read,
}; };
TRANS transAwacsExpandRead = {
.ct_s8= pmac_ctx_s8_read,
.ct_u8= pmac_ctx_u8_read,
.ct_s16be= pmac_ctx_s16_read,
.ct_u16be= pmac_ctx_u16_read,
.ct_s16le= pmac_ctx_s16_read,
.ct_u16le= pmac_ctx_u16_read,
};
/* translation tables */ /* translation tables */
/* 16 bit mu-law */ /* 16 bit mu-law */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment