From 89728e0ec4fc101c477f561248332119da6d30ed Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Feb 2004 16:49:10 -0800 Subject: [PATCH] [PATCH] ppc32: Update PowerMac dmasound driver From: Benjamin Herrenschmidt 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 :) --- sound/oss/dmasound/dmasound.h | 7 + sound/oss/dmasound/dmasound_awacs.c | 106 +++++++----- sound/oss/dmasound/dmasound_core.c | 9 +- sound/oss/dmasound/tas3004.c | 43 ++++- sound/oss/dmasound/tas_common.c | 3 + sound/oss/dmasound/tas_common.h | 2 +- sound/oss/dmasound/trans_16.c | 240 ++++++++++++++++++++++++++-- 7 files changed, 349 insertions(+), 61 deletions(-) diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index 9d6ba627ec4d8..371530fa56754 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -273,4 +273,11 @@ static inline void wait_ms(unsigned int ms) 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_ */ diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 4bb7535a6919e..7b5049166afe7 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -52,6 +52,10 @@ * - Support for snapper & better tumbler integration by Toby Sargeant * - Headphone detect for scremer by Julien Blache * - 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 @@ -76,6 +80,7 @@ #include #include #include +#include #include #ifdef CONFIG_ADB_CUDA #include @@ -119,7 +124,6 @@ static volatile u32 *i2s; static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; -static int awacs_spkr_vol; static struct device_node* awacs_node; static struct device_node* i2s_node; @@ -264,6 +268,7 @@ struct pmu_sleep_notifier awacs_sleep_notifier = { /* for (soft) sample rate translations */ int expand_bal; /* Balance factor for expanding (not volume!) */ +int expand_read_bal; /* Balance factor for expanding reads (not volume!) */ /*** Low level stuff *********************************************************/ @@ -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 int awacs_get_volume(int reg, 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 **********************************************************/ @@ -299,6 +302,7 @@ static void PMacAbortRead(void); extern TRANS transAwacsNormal ; extern TRANS transAwacsExpand ; extern TRANS transAwacsNormalRead ; +extern TRANS transAwacsExpandRead ; extern int daca_init(void); extern void daca_cleanup(void); @@ -545,11 +549,15 @@ tas_mixer_ioctl(u_int cmd, u_long arg) rc = IOCTL_OUT(arg, 0); break; 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); break; 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); break; case SOUND_MIXER_WRITE_RECSRC: @@ -799,11 +807,13 @@ static void PMacInit(void) set_frame_rate(dmasound.soft.speed, catchRadius) ; 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; - else + dmasound.trans_read = &transAwacsNormalRead; + } else { dmasound.trans_write = &transAwacsExpand; - dmasound.trans_read = &transAwacsNormalRead; + dmasound.trans_read = &transAwacsExpandRead; + } if (awacs) { if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) @@ -813,6 +823,7 @@ static void PMacInit(void) } expand_bal = -dmasound.soft.speed; + expand_read_bal = -dmasound.soft.speed; } static int PMacSetFormat(int format) @@ -1280,15 +1291,14 @@ static void awacs_nosound(unsigned long xx) spin_unlock_irqrestore(&dmasound.lock, flags); } -static struct timer_list beep_timer = TIMER_INITIALIZER(awacs_nosound, 0, 0); - -#if 0 /* would need to go through the input layer in 2.6, later.. --hch */ -/* 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. -*/ - -static void awacs_mksound(unsigned int hz, unsigned int ticks) +/* + * 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. + */ +static int awacs_beep_event(struct input_dev *dev, unsigned int type, + unsigned int code, int hz) { unsigned long flags; int beep_speed = 0; @@ -1300,8 +1310,21 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) static int beep_nsamples_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) - return; + return -1; /* quick-hack fix for DACA, Burgundy & Tumbler */ @@ -1313,26 +1336,17 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) beep_speed = i; srate = awacs_freqs[beep_speed]; } + 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 */ awacs_nosound(0); - return; -#endif + return 0; } + 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) { spin_unlock_irqrestore(&dmasound.lock, flags); - return; /* too hard, sorry :-( */ + return -1; /* too hard, sorry :-( */ } beep_playing = 1; st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); @@ -1375,8 +1389,9 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) out_le32(&awacs_txdma->control, RUN | (RUN << 16)); } spin_unlock_irqrestore(&dmasound.lock, flags); + + return 0; } -#endif /* used in init and for wake-up */ @@ -1764,7 +1779,6 @@ awacs_enable_amp(int spkr_vol) #ifdef CONFIG_ADB_CUDA struct adb_request req; - awacs_spkr_vol = spkr_vol; if (sys_ctrler != SYS_CTRLER_CUDA) return; @@ -2797,6 +2811,17 @@ __init setup_beep(void) 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) { struct device_node *io = NULL, *info = NULL; @@ -3086,13 +3111,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); /* shut out chips that do output only. * may need to extend this to machines which have no inputs - even tho' * 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 && - awacs_revision != AWACS_SNAPPER && - awacs_revision != AWACS_DACA) { + if (awacs_revision != AWACS_DACA) { dmasound.mach.capabilities = DSP_CAP_DUPLEX ; dmasound.mach.record = PMacRecord ; } @@ -3122,11 +3143,19 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); 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(); } static void __exit dmasound_awacs_cleanup(void) { + input_unregister_device(&awacs_beep_dev); + switch (awacs_revision) { case AWACS_TUMBLER: case AWACS_SNAPPER: @@ -3138,6 +3167,7 @@ static void __exit dmasound_awacs_cleanup(void) break; } dmasound_deinit(); + } MODULE_DESCRIPTION("PowerMac built-in audio driver."); diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 2dfed71283eb0..add1724bf38e5 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -218,6 +218,10 @@ static int state_unit = -1; static int irq_installed; #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 */ static mode_t shared_resource_owner; static int shared_resources_initialised; @@ -238,6 +242,7 @@ static inline int sound_set_format(int format) return dmasound.mach.setFormat(format); } + static int sound_set_speed(int speed) { if (speed < 0) @@ -1264,15 +1269,13 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, result = IOCTL_OUT(arg, format); if (result < 0) return result; - if (format != data) + if (format != data && data != AFMT_QUERY) return -EINVAL; return 0; } else return -EINVAL ; - break ; case SNDCTL_DSP_SUBDIVIDE: return -EINVAL ; - break; case SNDCTL_DSP_SETFRAGMENT: /* we can do this independently for the two queues - with the proviso that for fds opened O_RDWR we cannot separate the diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c index 62dd0c17ab2e2..933b46006695d 100644 --- a/sound/oss/dmasound/tas3004.c +++ b/sound/oss/dmasound/tas3004.c @@ -5,11 +5,7 @@ * Tobias Sargeant * Based upon tas3001c.c by Christopher C. Chimelis : * - * TODO: - * ----- - * * Enable control over input line 2 (is this connected?) - * * Implement sleep support (at least mute everything and - * * set gains to minimum during sleep) + * Input support by Renzo Davoli * */ @@ -293,7 +289,8 @@ tas3004_write_register( struct tas3004_data_t *self, { if (reg_num==TAS3004_REG_MCR || 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, (uint)reg_num, *data, @@ -313,7 +310,8 @@ tas3004_sync_register( struct tas3004_data_t *self, { if (reg_num==TAS3004_REG_MCR || 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, (uint)reg_num, register_width(reg_num)); @@ -354,7 +352,9 @@ tas3004_supported_mixers(struct tas3004_data_t *self) SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | SOUND_MASK_TREBLE | - SOUND_MASK_BASS; + SOUND_MASK_BASS | + SOUND_MASK_MIC | + SOUND_MASK_LINE; } static int @@ -447,6 +447,28 @@ tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) shadow[TAS3004_REG_BASS][0]=temp&0xff; rc = tas3004_sync_register(self,TAS3004_REG_BASS); 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: rc = -1; break; @@ -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_TREBLE); (void)tas3004_sync_register(self,TAS3004_REG_BASS); + (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); return 0; } @@ -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_TREBLE, TREBLE_DEFAULT); + tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT); + return 0; } @@ -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_TREBLE, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0); + return 0; } diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c index 9b877bb2fc262..d36a1fe2fcf34 100644 --- a/sound/oss/dmasound/tas_common.c +++ b/sound/oss/dmasound/tas_common.c @@ -195,6 +195,9 @@ tas_init(int driver_id, const char *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"); if (tas_node == NULL) return -ENODEV; diff --git a/sound/oss/dmasound/tas_common.h b/sound/oss/dmasound/tas_common.h index e62d6bfc1b363..3a6d48666db0c 100644 --- a/sound/oss/dmasound/tas_common.h +++ b/sound/oss/dmasound/tas_common.h @@ -87,7 +87,7 @@ struct tas_gain_t unsigned int *mixer; }; -typedef char tas_shadow_t[16]; +typedef char tas_shadow_t[0x45]; struct tas_data_t { diff --git a/sound/oss/dmasound/trans_16.c b/sound/oss/dmasound/trans_16.c index 4ba6f6589b3e2..4559dec461e4c 100644 --- a/sound/oss/dmasound/trans_16.c +++ b/sound/oss/dmasound/trans_16.c @@ -8,6 +8,9 @@ * * 08/02/2001 Iain Sandoe * 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 @@ -58,7 +61,6 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, /*** Translations ************************************************************/ -extern int expand_bal; /* Balance factor for expanding (not volume!) */ static int expand_data; /* Data for expanding */ 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, u_char data; val = *p++; + val = (val * software_input_volume) >> 7; data = val >> 8; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; if (stereo) { val = *p; + val = (val * software_input_volume) >> 7; data = val >> 8; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; @@ -494,11 +498,13 @@ static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount, u_char data; val = *p++; + val = (val * software_input_volume) >> 7; data = (val >> 8) ^ 0x80; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; if (stereo) { val = *p; + val = (val * software_input_volume) >> 7; data = (val >> 8) ^ 0x80; if (put_user(data, (u_char *)userPtr++)) return -EFAULT; @@ -517,24 +523,27 @@ static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, ssize_t count, used; int stereo = dmasound.soft.stereo; short *fp = (short *) &frame[*frameUsed]; + short *up = (short *) userPtr; frameLeft >>= 2; userCount >>= (stereo? 2: 1); used = count = min_t(unsigned long, userCount, frameLeft); - if (!stereo) { - short *up = (short *) userPtr; - while (count > 0) { - short data; + while (count > 0) { + short data; + + data = *fp++; + data = (data * software_input_volume) >> 7; + if (put_user(data, up++)) + return -EFAULT; + if (stereo) { data = *fp; + data = (data * software_input_volume) >> 7; if (put_user(data, up++)) return -EFAULT; - fp+=2; - count--; } - } else { - if (copy_to_user((u_char *)userPtr, fp, count * 4)) - return -EFAULT; - } + fp++; + count--; + } *frameUsed += used * 4; return stereo? used * 4: used * 2; } @@ -556,11 +565,13 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, int data; data = *fp++; + data = (data * software_input_volume) >> 7; data ^= mask; if (put_user(data, up++)) return -EFAULT; if (stereo) { data = *fp; + data = (data * software_input_volume) >> 7; data ^= mask; if (put_user(data, up++)) return -EFAULT; @@ -572,6 +583,204 @@ static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, 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 = { .ct_ulaw= pmac_ct_law, .ct_alaw= pmac_ct_law, @@ -603,6 +812,15 @@ TRANS transAwacsNormalRead = { .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 */ /* 16 bit mu-law */ -- 2.53.0