From 597603d615d2b19a9e451d8cfac24372856a522d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 9 Aug 2010 14:21:11 +0200 Subject: ALSA: introduce the snd-aloop module for the PCM loopback The snd-aloop module allows redirecting of the PCM playback in the kernel back to the user space using the standard ALSA PCM capture API. The module also allows time synchronization with another timing source and notifications of playback stream parameter changes. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 84714a6..b6ae762 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -74,6 +74,25 @@ config SND_DUMMY To compile this driver as a module, choose M here: the module will be called snd-dummy. +config SND_ALOOP + tristate "Generic loopback driver (PCM)" + select SND_PCM + help + Say 'Y' or 'M' to include support for the PCM loopback device. + This module returns played samples back to the user space using + the standard ALSA PCM device. The devices are routed 0->1 and + 1->0, where first number is the playback PCM device and second + number is the capture device. Module creates two PCM devices and + configured number of substreams (see the pcm_substreams module + parameter). + + The looback device allow time sychronization with an external + timing source using the time shift universal control (+-20% + of system time). + + To compile this driver as a module, choose M here: the module + will be called snd-aloop. + config SND_VIRMIDI tristate "Virtual MIDI soundcard" depends on SND_SEQUENCER diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index d4a07f9..1a8440c 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -4,6 +4,7 @@ # snd-dummy-objs := dummy.o +snd-aloop-objs := aloop.o snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o snd-portman2x4-objs := portman2x4.o @@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o # Toplevel Module Dependency obj-$(CONFIG_SND_DUMMY) += snd-dummy.o +obj-$(CONFIG_SND_ALOOP) += snd-aloop.o obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c new file mode 100644 index 0000000..3123a15 --- /dev/null +++ b/sound/drivers/aloop.c @@ -0,0 +1,1055 @@ +/* + * Loopback soundcard + * + * Original code: + * Copyright (c) by Jaroslav Kysela + * + * More accurate positioning and full-duplex support: + * Copyright (c) Ahmet İnan + * + * Major (almost complete) rewrite: + * Copyright (c) by Takashi Iwai + * + * A next major update in 2010 (separate timers for playback and capture): + * Copyright (c) Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("A loopback soundcard"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); + +#define MAX_PCM_SUBSTREAMS 8 + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; +static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; +static int pcm_notify[SNDRV_CARDS]; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for loopback soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for loopback soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); +module_param_array(pcm_substreams, int, NULL, 0444); +MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); +module_param_array(pcm_notify, int, NULL, 0444); +MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); + +#define NO_PITCH 100000 + +struct loopback_pcm; + +struct loopback_cable { + spinlock_t lock; + struct loopback_pcm *streams[2]; + struct snd_pcm_hardware hw; + /* flags */ + unsigned int valid; + unsigned int running; +}; + +struct loopback_setup { + unsigned int notify: 1; + unsigned int rate_shift; + unsigned int format; + unsigned int rate; + unsigned int channels; + struct snd_ctl_elem_id active_id; + struct snd_ctl_elem_id format_id; + struct snd_ctl_elem_id rate_id; + struct snd_ctl_elem_id channels_id; +}; + +struct loopback { + struct snd_card *card; + struct mutex cable_lock; + struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; + struct snd_pcm *pcm[2]; + struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; +}; + +struct loopback_pcm { + struct loopback *loopback; + struct snd_pcm_substream *substream; + struct loopback_cable *cable; + unsigned int pcm_buffer_size; + unsigned int buf_pos; /* position in buffer */ + unsigned int silent_size; + /* PCM parameters */ + unsigned int pcm_period_size; + unsigned int pcm_bps; /* bytes per second */ + unsigned int pcm_salign; /* bytes per sample * channels */ + unsigned int pcm_rate_shift; /* rate shift value */ + /* flags */ + unsigned int period_update_pending :1; + /* timer stuff */ + unsigned int irq_pos; /* fractional IRQ position */ + unsigned int period_size_frac; + unsigned long last_jiffies; + struct timer_list timer; +}; + +static struct platform_device *devices[SNDRV_CARDS]; + +static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) +{ + if (dpcm->pcm_rate_shift == NO_PITCH) { + x /= HZ; + } else { + x = div_u64(NO_PITCH * (unsigned long long)x, + HZ * (unsigned long long)dpcm->pcm_rate_shift); + } + return x - (x % dpcm->pcm_salign); +} + +static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) +{ + if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ + return x * HZ; + } else { + x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, + NO_PITCH); + } + return x; +} + +static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) +{ + int device = dpcm->substream->pstr->pcm->device; + + if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + device ^= 1; + return &dpcm->loopback->setup[dpcm->substream->number][device]; +} + +static inline unsigned int get_notify(struct loopback_pcm *dpcm) +{ + return get_setup(dpcm)->notify; +} + +static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) +{ + return get_setup(dpcm)->rate_shift; +} + +static void loopback_timer_start(struct loopback_pcm *dpcm) +{ + unsigned long tick; + unsigned int rate_shift = get_rate_shift(dpcm); + + if (rate_shift != dpcm->pcm_rate_shift) { + dpcm->pcm_rate_shift = rate_shift; + dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); + } + tick = dpcm->period_size_frac - dpcm->irq_pos; + tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; + dpcm->timer.expires = jiffies + tick; + add_timer(&dpcm->timer); +} + +static inline void loopback_timer_stop(struct loopback_pcm *dpcm) +{ + del_timer(&dpcm->timer); +} + +#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) +#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) +#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) + +static int loopback_check_format(struct loopback_cable *cable, int stream) +{ + struct snd_pcm_runtime *runtime; + struct loopback_setup *setup; + struct snd_card *card; + int check; + + if (cable->valid != CABLE_VALID_BOTH) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + goto __notify; + return 0; + } + runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> + substream->runtime; + check = cable->hw.formats != (1ULL << runtime->format) || + cable->hw.rate_min != runtime->rate || + cable->hw.rate_max != runtime->rate || + cable->hw.channels_min != runtime->channels || + cable->hw.channels_max != runtime->channels; + if (!check) + return 0; + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + return -EIO; + } else { + snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> + substream, SNDRV_PCM_STATE_DRAINING); + __notify: + runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> + substream->runtime; + setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); + card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; + if (setup->format != runtime->format) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->format_id); + setup->format = runtime->format; + } + if (setup->rate != runtime->rate) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->rate_id); + setup->rate = runtime->rate; + } + if (setup->channels != runtime->channels) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->channels_id); + setup->channels = runtime->channels; + } + } + return 0; +} + +static void loopback_active_notify(struct loopback_pcm *dpcm) +{ + snd_ctl_notify(dpcm->loopback->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &get_setup(dpcm)->active_id); +} + +static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + int err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = loopback_check_format(cable, substream->stream); + if (err < 0) + return err; + dpcm->last_jiffies = jiffies; + dpcm->pcm_rate_shift = 0; + loopback_timer_start(dpcm); + cable->running |= (1 << substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); + break; + case SNDRV_PCM_TRIGGER_STOP: + cable->running &= ~(1 << substream->stream); + loopback_timer_stop(dpcm); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); + break; + default: + return -EINVAL; + } + return 0; +} + +static int loopback_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + unsigned int bps, salign; + + salign = (snd_pcm_format_width(runtime->format) * + runtime->channels) / 8; + bps = salign * runtime->rate; + if (bps <= 0 || salign <= 0) + return -EINVAL; + + dpcm->buf_pos = 0; + dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + /* clear capture buffer */ + dpcm->silent_size = dpcm->pcm_buffer_size; + snd_pcm_format_set_silence(runtime->format, runtime->dma_area, + runtime->buffer_size * runtime->channels); + } + + dpcm->irq_pos = 0; + dpcm->period_update_pending = 0; + dpcm->pcm_bps = bps; + dpcm->pcm_salign = salign; + dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); + + mutex_lock(&dpcm->loopback->cable_lock); + if (!(cable->valid & ~(1 << substream->stream))) { + cable->hw.formats = (1ULL << runtime->format); + cable->hw.rate_min = runtime->rate; + cable->hw.rate_max = runtime->rate; + cable->hw.channels_min = runtime->channels; + cable->hw.channels_max = runtime->channels; + } + cable->valid |= 1 << substream->stream; + mutex_unlock(&dpcm->loopback->cable_lock); + + return 0; +} + +static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = dpcm->substream->runtime; + char *dst = runtime->dma_area; + unsigned int dst_off = dpcm->buf_pos; + + if (dpcm->silent_size >= dpcm->pcm_buffer_size) + return; + if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) + bytes = dpcm->pcm_buffer_size - dpcm->silent_size; + + for (;;) { + unsigned int size = bytes; + if (dst_off + size > dpcm->pcm_buffer_size) + size = dpcm->pcm_buffer_size - dst_off; + snd_pcm_format_set_silence(runtime->format, dst + dst_off, + bytes_to_frames(runtime, size) * + runtime->channels); + dpcm->silent_size += size; + bytes -= size; + if (!bytes) + break; + dst_off = 0; + } +} + +static void copy_play_buf(struct loopback_pcm *play, + struct loopback_pcm *capt, + unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = play->substream->runtime; + char *src = play->substream->runtime->dma_area; + char *dst = capt->substream->runtime->dma_area; + unsigned int src_off = play->buf_pos; + unsigned int dst_off = capt->buf_pos; + unsigned int clear_bytes = 0; + + /* check if playback is draining, trim the capture copy size + * when our pointer is at the end of playback ring buffer */ + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { + snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; + appl_ptr = appl_ptr1 = runtime->control->appl_ptr; + appl_ptr1 -= appl_ptr1 % runtime->buffer_size; + appl_ptr1 += play->buf_pos / play->pcm_salign; + if (appl_ptr < appl_ptr1) + appl_ptr1 -= runtime->buffer_size; + diff = (appl_ptr - appl_ptr1) * play->pcm_salign; + if (diff < bytes) { + clear_bytes = bytes - diff; + bytes = diff; + } + } + + for (;;) { + unsigned int size = bytes; + if (src_off + size > play->pcm_buffer_size) + size = play->pcm_buffer_size - src_off; + if (dst_off + size > capt->pcm_buffer_size) + size = capt->pcm_buffer_size - dst_off; + memcpy(dst + dst_off, src + src_off, size); + capt->silent_size = 0; + bytes -= size; + if (!bytes) + break; + src_off = (src_off + size) % play->pcm_buffer_size; + dst_off = (dst_off + size) % capt->pcm_buffer_size; + } + + if (clear_bytes > 0) + clear_capture_buf(capt, clear_bytes); +} + +#define BYTEPOS_UPDATE_POSONLY 0 +#define BYTEPOS_UPDATE_CLEAR 1 +#define BYTEPOS_UPDATE_COPY 2 + +static void loopback_bytepos_update(struct loopback_pcm *dpcm, + unsigned int delta, + unsigned int cmd) +{ + unsigned int count; + unsigned long last_pos; + + last_pos = byte_pos(dpcm, dpcm->irq_pos); + dpcm->irq_pos += delta * dpcm->pcm_bps; + count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; + if (!count) + return; + if (cmd == BYTEPOS_UPDATE_CLEAR) + clear_capture_buf(dpcm, count); + else if (cmd == BYTEPOS_UPDATE_COPY) + copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], + dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], + count); + dpcm->buf_pos += count; + dpcm->buf_pos %= dpcm->pcm_buffer_size; + if (dpcm->irq_pos >= dpcm->period_size_frac) { + dpcm->irq_pos %= dpcm->period_size_frac; + dpcm->period_update_pending = 1; + } +} + +static void loopback_pos_update(struct loopback_cable *cable) +{ + struct loopback_pcm *dpcm_play = + cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + struct loopback_pcm *dpcm_capt = + cable->streams[SNDRV_PCM_STREAM_CAPTURE]; + unsigned long delta_play = 0, delta_capt = 0; + + spin_lock(&cable->lock); + if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + delta_play = jiffies - dpcm_play->last_jiffies; + dpcm_play->last_jiffies += delta_play; + } + + if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + delta_capt = jiffies - dpcm_capt->last_jiffies; + dpcm_capt->last_jiffies += delta_capt; + } + + if (delta_play == 0 && delta_capt == 0) { + spin_unlock(&cable->lock); + return; + } + + if (delta_play > delta_capt) { + loopback_bytepos_update(dpcm_play, delta_play - delta_capt, + BYTEPOS_UPDATE_POSONLY); + delta_play = delta_capt; + } else if (delta_play < delta_capt) { + loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, + BYTEPOS_UPDATE_CLEAR); + delta_capt = delta_play; + } + + if (delta_play == 0 && delta_capt == 0) { + spin_unlock(&cable->lock); + return; + } + /* note delta_capt == delta_play at this moment */ + loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); + loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); + spin_unlock(&cable->lock); +} + +static void loopback_timer_function(unsigned long data) +{ + struct loopback_pcm *dpcm = (struct loopback_pcm *)data; + int stream; + + loopback_pos_update(dpcm->cable); + stream = dpcm->substream->stream; + if (dpcm->cable->running & (1 << stream)) + loopback_timer_start(dpcm); + if (dpcm->period_update_pending) { + dpcm->period_update_pending = 0; + if (dpcm->cable->running & (1 << stream)) + snd_pcm_period_elapsed(dpcm->substream); + } +} + +static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + + loopback_pos_update(dpcm->cable); + return bytes_to_frames(runtime, dpcm->buf_pos); +} + +static struct snd_pcm_hardware loopback_pcm_hardware = +{ + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | + SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 32, + .buffer_bytes_max = 2 * 1024 * 1024, + .period_bytes_min = 64, + .period_bytes_max = 2 * 1024 * 1024, + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static void loopback_runtime_free(struct snd_pcm_runtime *runtime) +{ + struct loopback_pcm *dpcm = runtime->private_data; + kfree(dpcm); +} + +static int loopback_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); +} + +static int loopback_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + + mutex_lock(&dpcm->loopback->cable_lock); + cable->valid &= ~(1 << substream->stream); + mutex_unlock(&dpcm->loopback->cable_lock); + return snd_pcm_lib_free_pages(substream); +} + +static unsigned int get_cable_index(struct snd_pcm_substream *substream) +{ + if (!substream->pcm->device) + return substream->stream; + else + return !substream->stream; +} + +static int loopback_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback *loopback = substream->private_data; + struct loopback_pcm *dpcm; + struct loopback_cable *cable; + int err = 0; + int dev = get_cable_index(substream); + + mutex_lock(&loopback->cable_lock); + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); + if (!dpcm) { + err = -ENOMEM; + goto unlock; + } + dpcm->loopback = loopback; + dpcm->substream = substream; + setup_timer(&dpcm->timer, loopback_timer_function, + (unsigned long)dpcm); + + cable = loopback->cables[substream->number][dev]; + if (!cable) { + cable = kzalloc(sizeof(*cable), GFP_KERNEL); + if (!cable) { + kfree(dpcm); + err = -ENOMEM; + goto unlock; + } + spin_lock_init(&cable->lock); + cable->hw = loopback_pcm_hardware; + loopback->cables[substream->number][dev] = cable; + } + dpcm->cable = cable; + cable->streams[substream->stream] = dpcm; + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + runtime->private_data = dpcm; + runtime->private_free = loopback_runtime_free; + if (get_notify(dpcm) && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw = loopback_pcm_hardware; + } else { + runtime->hw = cable->hw; + } + unlock: + mutex_unlock(&loopback->cable_lock); + return err; +} + +static int loopback_close(struct snd_pcm_substream *substream) +{ + struct loopback *loopback = substream->private_data; + struct loopback_pcm *dpcm = substream->runtime->private_data; + struct loopback_cable *cable; + int dev = get_cable_index(substream); + + loopback_timer_stop(dpcm); + mutex_lock(&loopback->cable_lock); + cable = loopback->cables[substream->number][dev]; + if (cable->streams[!substream->stream]) { + /* other stream is still alive */ + cable->streams[substream->stream] = NULL; + } else { + /* free the cable */ + loopback->cables[substream->number][dev] = NULL; + kfree(cable); + } + mutex_unlock(&loopback->cable_lock); + return 0; +} + +static struct snd_pcm_ops loopback_playback_ops = { + .open = loopback_open, + .close = loopback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = loopback_hw_params, + .hw_free = loopback_hw_free, + .prepare = loopback_prepare, + .trigger = loopback_trigger, + .pointer = loopback_pointer, +}; + +static struct snd_pcm_ops loopback_capture_ops = { + .open = loopback_open, + .close = loopback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = loopback_hw_params, + .hw_free = loopback_hw_free, + .prepare = loopback_prepare, + .trigger = loopback_trigger, + .pointer = loopback_pointer, +}; + +static int __devinit loopback_pcm_new(struct loopback *loopback, + int device, int substreams) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(loopback->card, "Loopback PCM", device, + substreams, substreams, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); + + pcm->private_data = loopback; + pcm->info_flags = 0; + strcpy(pcm->name, "Loopback PCM"); + + loopback->pcm[device] = pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, 2 * 1024 * 1024); + return 0; +} + +static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 80000; + uinfo->value.integer.max = 120000; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift; + return 0; +} + +static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.integer.value[0]; + if (val < 80000) + val = 80000; + if (val > 120000) + val = 120000; + mutex_lock(&loopback->cable_lock); + if (val != loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift) { + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift = val; + change = 1; + } + mutex_unlock(&loopback->cable_lock); + return change; +} + +static int loopback_notify_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify; + return 0; +} + +static int loopback_notify_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.integer.value[0] ? 1 : 0; + if (val != loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify) { + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify = val; + change = 1; + } + return change; +} + +static int loopback_active_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + struct loopback_cable *cable = loopback->cables + [kcontrol->id.subdevice][kcontrol->id.device]; + unsigned int val = 0; + + if (cable != NULL) + val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + 1 : 0; + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int loopback_format_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].format; + return 0; +} + +static int loopback_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 192000; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate; + return 0; +} + +static int loopback_channels_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 1; + uinfo->value.integer.max = 1024; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_channels_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate; + return 0; +} + +static struct snd_kcontrol_new loopback_controls[] __devinitdata = { +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Rate Shift 100000", + .info = loopback_rate_shift_info, + .get = loopback_rate_shift_get, + .put = loopback_rate_shift_put, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Notify", + .info = snd_ctl_boolean_mono_info, + .get = loopback_notify_get, + .put = loopback_notify_put, +}, +#define ACTIVE_IDX 2 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Active", + .info = snd_ctl_boolean_mono_info, + .get = loopback_active_get, +}, +#define FORMAT_IDX 3 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Format", + .info = loopback_format_info, + .get = loopback_format_get +}, +#define RATE_IDX 4 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Rate", + .info = loopback_rate_info, + .get = loopback_rate_get +}, +#define CHANNELS_IDX 5 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Channels", + .info = loopback_channels_info, + .get = loopback_channels_get +} +}; + +static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) +{ + struct snd_card *card = loopback->card; + struct snd_pcm *pcm; + struct snd_kcontrol *kctl; + struct loopback_setup *setup; + int err, dev, substr, substr_count, idx; + + strcpy(card->mixername, "Loopback Mixer"); + for (dev = 0; dev < 2; dev++) { + pcm = loopback->pcm[dev]; + substr_count = + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; + for (substr = 0; substr < substr_count; substr++) { + setup = &loopback->setup[substr][dev]; + setup->notify = notify; + setup->rate_shift = NO_PITCH; + setup->format = SNDRV_PCM_FORMAT_S16_LE; + setup->rate = 48000; + setup->channels = 2; + for (idx = 0; idx < ARRAY_SIZE(loopback_controls); + idx++) { + kctl = snd_ctl_new1(&loopback_controls[idx], + loopback); + if (!kctl) + return -ENOMEM; + kctl->id.device = dev; + kctl->id.subdevice = substr; + switch (idx) { + case ACTIVE_IDX: + setup->active_id = kctl->id; + break; + case FORMAT_IDX: + setup->format_id = kctl->id; + break; + case RATE_IDX: + setup->rate_id = kctl->id; + break; + case CHANNELS_IDX: + setup->channels_id = kctl->id; + break; + default: + break; + } + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + } + } + } + return 0; +} + +static int __devinit loopback_probe(struct platform_device *devptr) +{ + struct snd_card *card; + struct loopback *loopback; + int dev = devptr->id; + int err; + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct loopback), &card); + if (err < 0) + return err; + loopback = card->private_data; + + if (pcm_substreams[dev] < 1) + pcm_substreams[dev] = 1; + if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) + pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; + + loopback->card = card; + mutex_init(&loopback->cable_lock); + + err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); + if (err < 0) + goto __nodev; + err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); + if (err < 0) + goto __nodev; + err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); + if (err < 0) + goto __nodev; + strcpy(card->driver, "Loopback"); + strcpy(card->shortname, "Loopback"); + sprintf(card->longname, "Loopback %i", dev + 1); + err = snd_card_register(card); + if (!err) { + platform_set_drvdata(devptr, card); + return 0; + } + __nodev: + snd_card_free(card); + return err; +} + +static int __devexit loopback_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int loopback_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_card *card = platform_get_drvdata(pdev); + struct loopback *loopback = card->private_data; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + snd_pcm_suspend_all(loopback->pcm[0]); + snd_pcm_suspend_all(loopback->pcm[1]); + return 0; +} + +static int loopback_resume(struct platform_device *pdev) +{ + struct snd_card *card = platform_get_drvdata(pdev); + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + +#define SND_LOOPBACK_DRIVER "snd_aloop" + +static struct platform_driver loopback_driver = { + .probe = loopback_probe, + .remove = __devexit_p(loopback_remove), +#ifdef CONFIG_PM + .suspend = loopback_suspend, + .resume = loopback_resume, +#endif + .driver = { + .name = SND_LOOPBACK_DRIVER + }, +}; + +static void loopback_unregister_all(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(devices); ++i) + platform_device_unregister(devices[i]); + platform_driver_unregister(&loopback_driver); +} + +static int __init alsa_card_loopback_init(void) +{ + int i, err, cards; + + err = platform_driver_register(&loopback_driver); + if (err < 0) + return err; + + + cards = 0; + for (i = 0; i < SNDRV_CARDS; i++) { + struct platform_device *device; + if (!enable[i]) + continue; + device = platform_device_register_simple(SND_LOOPBACK_DRIVER, + i, NULL, 0); + if (IS_ERR(device)) + continue; + if (!platform_get_drvdata(device)) { + platform_device_unregister(device); + continue; + } + devices[i] = device; + cards++; + } + if (!cards) { +#ifdef MODULE + printk(KERN_ERR "aloop: No loopback enabled\n"); +#endif + loopback_unregister_all(); + return -ENODEV; + } + return 0; +} + +static void __exit alsa_card_loopback_exit(void) +{ + loopback_unregister_all(); +} + +module_init(alsa_card_loopback_init) +module_exit(alsa_card_loopback_exit) -- cgit v0.10.2 From 495311927ffbe3604e915aeafdf03325e9925b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Herman?= Date: Wed, 11 Aug 2010 13:08:06 +0200 Subject: ALSA: ISA: New Aztech Sound Galaxy driver This is a new driver for Aztech Sound Galaxy ISA soundcards based on the AZT1605 and AZT2316 chipsets. It's constructed as two seperate drivers for either chipset generated from the same source file, with (very) minimal ifdeffery. The drivers check the SB DSP version to decide if they are being loaded for the right chip. AZT1605 returns 2.1 by default and AZT2316 3.1. This isn't full-proof as the DSP version can actually be set through software but it's close enough -- as far as I've been able to see, the DSP version can not be stored in the EEPROM and the cards will therefore startup with the defaults. This distinction could (with the same success rate) also be used to decide which chip we're looking at at runtime meaning a single, merged driver is also an option but I feel it's actually nicer this way. A merged driver would have to postpone translating the passed in resource values to the card configuration until it knew which one it was looking at and would need to postpone erring out on mpu_irq=10 for azt1605 and mpu_irq=3 for azt2316. The drivers have been tested on various cards. For snd-azt1605: FCC-ID I38-MMSN811: Aztech Sound Galaxy Nova 16 Extra FCC-ID I38-MMSN822: Aztech Sound Galaxy Pro 16 II and for snd-azt2316: FCC-ID I38-MMSN824: Aztech Sound Galaxy Pro 16 AB FCC-ID I38-MMSN826: Trust Sound Expert DeLuxe Wave 32 (05201) FCC-ID I38-MMSN830: Trust Sound Expert DeLuxe 16+ (05202) FCC-ID I38-MMSN837: Packard Bell ISA Soundcard 030069 FCC-ID I38-MMSN846: Trust Sound Expert DeLuxe 16-3D (06300) FCC-ID I38-MMSN847: Trust Sound Expert DeLuxe Wave 32-3D (06301) FCC-ID I38-MMSN852: Aztech Sound Galaxy Waverider Pro 32-3D 826 and 846 were also marketed directly by Aztech and then known as: FCC-ID I38-MMSN826: Aztech Sound Galaxy Waverider 32+ FCC-ID I38-MMSN846: Aztech Sound Galaxy Nova 16 Extra II-3D Together, these cover the AZT1605 and AT2316A, AZT2316R and AZT2316-S chipsets. All cards work fully -- full-duplex PCM, MIDI and FM. Full duplex is a little flaky on some. I38-MSN811 tends to not work in full-duplex but sometimes does with the highest success rate being achieved when you first start the capture and then a playback instead of the other way around (it's a CS4231-KL codec). The cards with an AD1845XP codec (my I38-MMSN826 and one of my I38-MMSN830s) are also somewhat duplex-challenged. Sometimes full-duplex works, sometimes not and this varies from try to try. This seems likely to be a timing problem somewhere inside wss-lib. I38-MMSN826 has an additional "ICS2115 WaveFront" wavetable synth onboard that isn't supported yet. The wavetable synths on I38-MMSN847 and I38-MMSN852 are wired directly to the standard MPU-401 UART and the AUX1 input on the codec and work without problem. CD-ROM audio on the cards is routed to the codec "Line" input, Line-In to its Aux input, and FM/Wavetable to its AUX1 input. I did not rename the controls due to the capture source enumeration: I see that capture-source overrides are hardcoded in wss-lib and this is just too ugly to live. Versus the old snd-sgalaxy driver these drivers add support for the models without a configuration EEPROM (which are common), full-duplex, MPU-401 UART and OPL3. In the future they might grow support for that ICS2115 WaveFront synth on 826 and an hwdep interface to write to the EEPROM on the models that have one. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7f4dceb..e25555c 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. control correctly. If you have problems regarding this, try another ALSA compliant mixer (alsamixer works). + Module snd-azt1605 + ------------------ + + Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605 + chipset. + + port - port # for BASE (0x220,0x240,0x260,0x280) + wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) + irq - IRQ # for WSS (7,9,10,11) + dma1 - DMA # for WSS playback (0,1,3) + dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) + mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) + mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default) + fm_port - port # for OPL3 (0x388), -1 = disabled (default) + + This module supports multiple cards. It does not support autoprobe: port, + wss_port, irq and dma1 have to be specified. The other values are + optional. + + "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) + or the value stored in the card's EEPROM for cards that have an EEPROM and + their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can + be choosen freely from the options enumerated above. + + If dma2 is specified and different from dma1, the card will operate in + full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to + enable capture since only channels 0 and 1 are available for capture. + + Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 + mpu_port=0x330 mpu_irq=9 fm_port=0x388". + + Whatever IRQ and DMA channels you pick, be sure to reserve them for + legacy ISA in your BIOS. + + Module snd-azt2316 + ------------------ + + Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316 + chipset. + + port - port # for BASE (0x220,0x240,0x260,0x280) + wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) + irq - IRQ # for WSS (7,9,10,11) + dma1 - DMA # for WSS playback (0,1,3) + dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) + mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) + mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default) + fm_port - port # for OPL3 (0x388), -1 = disabled (default) + + This module supports multiple cards. It does not support autoprobe: port, + wss_port, irq and dma1 have to be specified. The other values are + optional. + + "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) + or the value stored in the card's EEPROM for cards that have an EEPROM and + their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can + be choosen freely from the options enumerated above. + + If dma2 is specified and different from dma1, the card will operate in + full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to + enable capture since only channels 0 and 1 are available for capture. + + Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 + mpu_port=0x330 mpu_irq=9 fm_port=0x388". + + Whatever IRQ and DMA channels you pick, be sure to reserve them for + legacy ISA in your BIOS. + Module snd-aw2 -------------- diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6990c6..f9aa13d 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -77,6 +77,32 @@ config SND_ALS100 To compile this driver as a module, choose M here: the module will be called snd-als100. +config SND_AZT1605 + tristate "Aztech AZT1605 Driver" + depends on SND + select SND_WSS_LIB + select SND_MPU401_UART + select SND_OPL3_LIB + help + Say Y here to include support for Aztech Sound Galaxy cards + based on the AZT1605 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-azt1605. + +config SND_AZT2316 + tristate "Aztech AZT2316 Driver" + depends on SND + select SND_WSS_LIB + select SND_MPU401_UART + select SND_OPL3_LIB + help + Say Y here to include support for Aztech Sound Galaxy cards + based on the AZT2316 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-azt2316. + config SND_AZT2320 tristate "Aztech Systems AZT2320" depends on PNP diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c73d30c..d2bd8f5 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -24,5 +24,5 @@ obj-$(CONFIG_SND_SC6000) += snd-sc6000.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o -obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \ +obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ sb/ wavefront/ wss/ diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile new file mode 100644 index 0000000..e307066 --- /dev/null +++ b/sound/isa/galaxy/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela +# + +snd-azt1605-objs := azt1605.o +snd-azt2316-objs := azt2316.o + +obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o +obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c new file mode 100644 index 0000000..9a97643 --- /dev/null +++ b/sound/isa/galaxy/azt1605.c @@ -0,0 +1,91 @@ +/* + * Aztech AZT1605 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#define AZT1605 + +#define CRD_NAME "Aztech AZT1605" +#define DRV_NAME "AZT1605" +#define DEV_NAME "azt1605" + +#define GALAXY_DSP_MAJOR 2 +#define GALAXY_DSP_MINOR 1 + +#define GALAXY_CONFIG_SIZE 3 + +/* + * 24-bit config register + */ + +#define GALAXY_CONFIG_SBA_220 (0 << 0) +#define GALAXY_CONFIG_SBA_240 (1 << 0) +#define GALAXY_CONFIG_SBA_260 (2 << 0) +#define GALAXY_CONFIG_SBA_280 (3 << 0) +#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 + +#define GALAXY_CONFIG_MPUA_300 (0 << 2) +#define GALAXY_CONFIG_MPUA_330 (1 << 2) + +#define GALAXY_CONFIG_MPU_ENABLE (1 << 3) + +#define GALAXY_CONFIG_GAME_ENABLE (1 << 4) + +#define GALAXY_CONFIG_CD_PANASONIC (1 << 5) +#define GALAXY_CONFIG_CD_MITSUMI (1 << 6) +#define GALAXY_CONFIG_CD_MASK (\ + GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI) + +#define GALAXY_CONFIG_UNUSED (1 << 7) +#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED + +#define GALAXY_CONFIG_SBIRQ_2 (1 << 8) +#define GALAXY_CONFIG_SBIRQ_3 (1 << 9) +#define GALAXY_CONFIG_SBIRQ_5 (1 << 10) +#define GALAXY_CONFIG_SBIRQ_7 (1 << 11) + +#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12) +#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13) +#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14) +#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15) + +#define GALAXY_CONFIG_WSSA_530 (0 << 16) +#define GALAXY_CONFIG_WSSA_604 (1 << 16) +#define GALAXY_CONFIG_WSSA_E80 (2 << 16) +#define GALAXY_CONFIG_WSSA_F40 (3 << 16) + +#define GALAXY_CONFIG_WSS_ENABLE (1 << 18) + +#define GALAXY_CONFIG_CDIRQ_11 (1 << 19) +#define GALAXY_CONFIG_CDIRQ_12 (1 << 20) +#define GALAXY_CONFIG_CDIRQ_15 (1 << 21) +#define GALAXY_CONFIG_CDIRQ_MASK (\ + GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\ + GALAXY_CONFIG_CDIRQ_15) + +#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22) +#define GALAXY_CONFIG_CDDMA_0 (1 << 22) +#define GALAXY_CONFIG_CDDMA_1 (2 << 22) +#define GALAXY_CONFIG_CDDMA_3 (3 << 22) +#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3 + +#define GALAXY_CONFIG_MASK (\ + GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\ + GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\ + GALAXY_CONFIG_CDDMA_MASK) + +#include "galaxy.c" diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c new file mode 100644 index 0000000..1894411 --- /dev/null +++ b/sound/isa/galaxy/azt2316.c @@ -0,0 +1,111 @@ +/* + * Aztech AZT2316 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#define AZT2316 + +#define CRD_NAME "Aztech AZT2316" +#define DRV_NAME "AZT2316" +#define DEV_NAME "azt2316" + +#define GALAXY_DSP_MAJOR 3 +#define GALAXY_DSP_MINOR 1 + +#define GALAXY_CONFIG_SIZE 4 + +/* + * 32-bit config register + */ + +#define GALAXY_CONFIG_SBA_220 (0 << 0) +#define GALAXY_CONFIG_SBA_240 (1 << 0) +#define GALAXY_CONFIG_SBA_260 (2 << 0) +#define GALAXY_CONFIG_SBA_280 (3 << 0) +#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 + +#define GALAXY_CONFIG_SBIRQ_2 (1 << 2) +#define GALAXY_CONFIG_SBIRQ_5 (1 << 3) +#define GALAXY_CONFIG_SBIRQ_7 (1 << 4) +#define GALAXY_CONFIG_SBIRQ_10 (1 << 5) + +#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6) +#define GALAXY_CONFIG_SBDMA_0 (1 << 6) +#define GALAXY_CONFIG_SBDMA_1 (2 << 6) +#define GALAXY_CONFIG_SBDMA_3 (3 << 6) + +#define GALAXY_CONFIG_WSSA_530 (0 << 8) +#define GALAXY_CONFIG_WSSA_604 (1 << 8) +#define GALAXY_CONFIG_WSSA_E80 (2 << 8) +#define GALAXY_CONFIG_WSSA_F40 (3 << 8) + +#define GALAXY_CONFIG_WSS_ENABLE (1 << 10) + +#define GALAXY_CONFIG_GAME_ENABLE (1 << 11) + +#define GALAXY_CONFIG_MPUA_300 (0 << 12) +#define GALAXY_CONFIG_MPUA_330 (1 << 12) + +#define GALAXY_CONFIG_MPU_ENABLE (1 << 13) + +#define GALAXY_CONFIG_CDA_310 (0 << 14) +#define GALAXY_CONFIG_CDA_320 (1 << 14) +#define GALAXY_CONFIG_CDA_340 (2 << 14) +#define GALAXY_CONFIG_CDA_350 (3 << 14) +#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 + +#define GALAXY_CONFIG_CD_DISABLE (0 << 16) +#define GALAXY_CONFIG_CD_PANASONIC (1 << 16) +#define GALAXY_CONFIG_CD_SONY (2 << 16) +#define GALAXY_CONFIG_CD_MITSUMI (3 << 16) +#define GALAXY_CONFIG_CD_AZTECH (4 << 16) +#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16) +#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16) +#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16) +#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7 + +#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20) +#define GALAXY_CONFIG_CDDMA8_0 (1 << 20) +#define GALAXY_CONFIG_CDDMA8_1 (2 << 20) +#define GALAXY_CONFIG_CDDMA8_3 (3 << 20) +#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 + +#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22) +#define GALAXY_CONFIG_CDDMA16_5 (1 << 22) +#define GALAXY_CONFIG_CDDMA16_6 (2 << 22) +#define GALAXY_CONFIG_CDDMA16_7 (3 << 22) +#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 + +#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24) +#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25) +#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26) +#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27) + +#define GALAXY_CONFIG_CDIRQ_5 (1 << 28) +#define GALAXY_CONFIG_CDIRQ_11 (1 << 29) +#define GALAXY_CONFIG_CDIRQ_12 (1 << 30) +#define GALAXY_CONFIG_CDIRQ_15 (1 << 31) +#define GALAXY_CONFIG_CDIRQ_MASK (\ + GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\ + GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15) + +#define GALAXY_CONFIG_MASK (\ + GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ + GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\ + GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK) + +#include "galaxy.c" diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c new file mode 100644 index 0000000..ee54df0 --- /dev/null +++ b/sound/isa/galaxy/galaxy.c @@ -0,0 +1,652 @@ +/* + * Aztech AZT1605/AZT2316 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION(CRD_NAME); +MODULE_AUTHOR("Rene Herman"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); + +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; + +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); +module_param_array(wss_port, long, NULL, 0444); +MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); +module_param_array(fm_port, long, NULL, 0444); +MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); +module_param_array(dma1, int, NULL, 0444); +MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); + +/* + * Generic SB DSP support routines + */ + +#define DSP_PORT_RESET 0x6 +#define DSP_PORT_READ 0xa +#define DSP_PORT_COMMAND 0xc +#define DSP_PORT_STATUS 0xc +#define DSP_PORT_DATA_AVAIL 0xe + +#define DSP_SIGNATURE 0xaa + +#define DSP_COMMAND_GET_VERSION 0xe1 + +static int __devinit dsp_get_byte(void __iomem *port, u8 *val) +{ + int loops = 1000; + + while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { + if (!loops--) + return -EIO; + cpu_relax(); + } + *val = ioread8(port + DSP_PORT_READ); + return 0; +} + +static int __devinit dsp_reset(void __iomem *port) +{ + u8 val; + + iowrite8(1, port + DSP_PORT_RESET); + udelay(10); + iowrite8(0, port + DSP_PORT_RESET); + + if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) + return -ENODEV; + + return 0; +} + +static int __devinit dsp_command(void __iomem *port, u8 cmd) +{ + int loops = 1000; + + while (ioread8(port + DSP_PORT_STATUS) & 0x80) { + if (!loops--) + return -EIO; + cpu_relax(); + } + iowrite8(cmd, port + DSP_PORT_COMMAND); + return 0; +} + +static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) +{ + int err; + + err = dsp_command(port, DSP_COMMAND_GET_VERSION); + if (err < 0) + return err; + + err = dsp_get_byte(port, major); + if (err < 0) + return err; + + err = dsp_get_byte(port, minor); + if (err < 0) + return err; + + return 0; +} + +/* + * Generic WSS support routines + */ + +#define WSS_CONFIG_DMA_0 (1 << 0) +#define WSS_CONFIG_DMA_1 (2 << 0) +#define WSS_CONFIG_DMA_3 (3 << 0) +#define WSS_CONFIG_DUPLEX (1 << 2) +#define WSS_CONFIG_IRQ_7 (1 << 3) +#define WSS_CONFIG_IRQ_9 (2 << 3) +#define WSS_CONFIG_IRQ_10 (3 << 3) +#define WSS_CONFIG_IRQ_11 (4 << 3) + +#define WSS_PORT_CONFIG 0 +#define WSS_PORT_SIGNATURE 3 + +#define WSS_SIGNATURE 4 + +static int __devinit wss_detect(void __iomem *wss_port) +{ + if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) + return -ENODEV; + + return 0; +} + +static void wss_set_config(void __iomem *wss_port, u8 wss_config) +{ + iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); +} + +/* + * Aztech Sound Galaxy specifics + */ + +#define GALAXY_PORT_CONFIG 1024 +#define CONFIG_PORT_SET 4 + +#define DSP_COMMAND_GALAXY_8 8 +#define GALAXY_COMMAND_GET_TYPE 5 + +#define DSP_COMMAND_GALAXY_9 9 +#define GALAXY_COMMAND_WSSMODE 0 +#define GALAXY_COMMAND_SB8MODE 1 + +#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE +#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE + +struct snd_galaxy { + void __iomem *port; + void __iomem *config_port; + void __iomem *wss_port; + u32 config; + struct resource *res_port; + struct resource *res_config_port; + struct resource *res_wss_port; +}; + +static u32 config[SNDRV_CARDS]; +static u8 wss_config[SNDRV_CARDS]; + +static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) +{ + if (!enable[n]) + return 0; + + switch (port[n]) { + case SNDRV_AUTO_PORT: + dev_err(dev, "please specify port\n"); + return 0; + case 0x220: + config[n] |= GALAXY_CONFIG_SBA_220; + break; + case 0x240: + config[n] |= GALAXY_CONFIG_SBA_240; + break; + case 0x260: + config[n] |= GALAXY_CONFIG_SBA_260; + break; + case 0x280: + config[n] |= GALAXY_CONFIG_SBA_280; + break; + default: + dev_err(dev, "invalid port %#lx\n", port[n]); + return 0; + } + + switch (wss_port[n]) { + case SNDRV_AUTO_PORT: + dev_err(dev, "please specify wss_port\n"); + return 0; + case 0x530: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; + break; + case 0x604: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; + break; + case 0xe80: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; + break; + case 0xf40: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; + break; + default: + dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); + return 0; + } + + switch (irq[n]) { + case SNDRV_AUTO_IRQ: + dev_err(dev, "please specify irq\n"); + return 0; + case 7: + wss_config[n] |= WSS_CONFIG_IRQ_7; + break; + case 2: + irq[n] = 9; + case 9: + wss_config[n] |= WSS_CONFIG_IRQ_9; + break; + case 10: + wss_config[n] |= WSS_CONFIG_IRQ_10; + break; + case 11: + wss_config[n] |= WSS_CONFIG_IRQ_11; + break; + default: + dev_err(dev, "invalid IRQ %d\n", irq[n]); + return 0; + } + + switch (dma1[n]) { + case SNDRV_AUTO_DMA: + dev_err(dev, "please specify dma1\n"); + return 0; + case 0: + wss_config[n] |= WSS_CONFIG_DMA_0; + break; + case 1: + wss_config[n] |= WSS_CONFIG_DMA_1; + break; + case 3: + wss_config[n] |= WSS_CONFIG_DMA_3; + break; + default: + dev_err(dev, "invalid playback DMA %d\n", dma1[n]); + return 0; + } + + if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { + dma2[n] = -1; + goto mpu; + } + + wss_config[n] |= WSS_CONFIG_DUPLEX; + switch (dma2[n]) { + case 0: + break; + case 1: + if (dma1[n] == 0) + break; + default: + dev_err(dev, "invalid capture DMA %d\n", dma2[n]); + return 0; + } + +mpu: + switch (mpu_port[n]) { + case SNDRV_AUTO_PORT: + dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); + mpu_port[n] = -1; + goto fm; + case 0x300: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; + break; + case 0x330: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; + break; + default: + dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); + return 0; + } + + switch (mpu_irq[n]) { + case SNDRV_AUTO_IRQ: + dev_warn(dev, "mpu_irq not specified: using polling mode\n"); + mpu_irq[n] = -1; + break; + case 2: + mpu_irq[n] = 9; + case 9: + config[n] |= GALAXY_CONFIG_MPUIRQ_2; + break; +#ifdef AZT1605 + case 3: + config[n] |= GALAXY_CONFIG_MPUIRQ_3; + break; +#endif + case 5: + config[n] |= GALAXY_CONFIG_MPUIRQ_5; + break; + case 7: + config[n] |= GALAXY_CONFIG_MPUIRQ_7; + break; +#ifdef AZT2316 + case 10: + config[n] |= GALAXY_CONFIG_MPUIRQ_10; + break; +#endif + default: + dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); + return 0; + } + + if (mpu_irq[n] == irq[n]) { + dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); + return 0; + } + +fm: + switch (fm_port[n]) { + case SNDRV_AUTO_PORT: + dev_warn(dev, "fm_port not specified: not using OPL3\n"); + fm_port[n] = -1; + break; + case 0x388: + break; + default: + dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); + return 0; + } + + config[n] |= GALAXY_CONFIG_GAME_ENABLE; + return 1; +} + +static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) +{ + u8 major; + u8 minor; + int err; + + err = dsp_reset(galaxy->port); + if (err < 0) + return err; + + err = dsp_get_version(galaxy->port, &major, &minor); + if (err < 0) + return err; + + if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) + return -ENODEV; + + err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); + if (err < 0) + return err; + + err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); + if (err < 0) + return err; + + err = dsp_get_byte(galaxy->port, type); + if (err < 0) + return err; + + return 0; +} + +static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) +{ + int err; + + err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); + if (err < 0) + return err; + + err = dsp_command(galaxy->port, mode); + if (err < 0) + return err; + +#ifdef AZT1605 + /* + * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again + */ + err = dsp_reset(galaxy->port); + if (err < 0) + return err; +#endif + + return 0; +} + +static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) +{ + u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); + int i; + + iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); + for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { + iowrite8(config, galaxy->config_port + i); + config >>= 8; + } + iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); + msleep(10); +} + +static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) +{ + int i; + + for (i = GALAXY_CONFIG_SIZE; i; i--) { + u8 tmp = ioread8(galaxy->config_port + i - 1); + galaxy->config = (galaxy->config << 8) | tmp; + } + config |= galaxy->config & GALAXY_CONFIG_MASK; + galaxy_set_config(galaxy, config); +} + +static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) +{ + int err; + + err = wss_detect(galaxy->wss_port); + if (err < 0) + return err; + + wss_set_config(galaxy->wss_port, wss_config); + + err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); + if (err < 0) + return err; + + return 0; +} + +static void snd_galaxy_free(struct snd_card *card) +{ + struct snd_galaxy *galaxy = card->private_data; + + if (galaxy->wss_port) { + wss_set_config(galaxy->wss_port, 0); + ioport_unmap(galaxy->wss_port); + release_and_free_resource(galaxy->res_wss_port); + } + if (galaxy->config_port) { + galaxy_set_config(galaxy, galaxy->config); + ioport_unmap(galaxy->config_port); + release_and_free_resource(galaxy->res_config_port); + } + if (galaxy->port) { + ioport_unmap(galaxy->port); + release_and_free_resource(galaxy->res_port); + } +} + +static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) +{ + struct snd_galaxy *galaxy; + struct snd_wss *chip; + struct snd_card *card; + u8 type; + int err; + + err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy, + &card); + if (err < 0) + return err; + + snd_card_set_dev(card, dev); + + card->private_free = snd_galaxy_free; + galaxy = card->private_data; + + galaxy->res_port = request_region(port[n], 16, DRV_NAME); + if (!galaxy->res_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], + port[n] + 15); + err = -EBUSY; + goto error; + } + galaxy->port = ioport_map(port[n], 16); + + err = galaxy_init(galaxy, &type); + if (err < 0) { + dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); + goto error; + } + dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); + + galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, + 16, DRV_NAME); + if (!galaxy->res_config_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", + port[n] + GALAXY_PORT_CONFIG, + port[n] + GALAXY_PORT_CONFIG + 15); + err = -EBUSY; + goto error; + } + galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); + + galaxy_config(galaxy, config[n]); + + galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); + if (!galaxy->res_wss_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], + wss_port[n] + 3); + err = -EBUSY; + goto error; + } + galaxy->wss_port = ioport_map(wss_port[n], 4); + + err = galaxy_wss_config(galaxy, wss_config[n]); + if (err < 0) { + dev_err(dev, "could not configure WSS\n"); + goto error; + } + + strcpy(card->driver, DRV_NAME); + strcpy(card->shortname, DRV_NAME); + sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", + card->shortname, port[n], wss_port[n], irq[n], dma1[n], + dma2[n]); + + err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], + dma2[n], WSS_HW_DETECT, 0, &chip); + if (err < 0) + goto error; + + err = snd_wss_pcm(chip, 0, NULL); + if (err < 0) + goto error; + + err = snd_wss_mixer(chip); + if (err < 0) + goto error; + + err = snd_wss_timer(chip, 0, NULL); + if (err < 0) + goto error; + + if (mpu_port[n] >= 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port[n], 0, mpu_irq[n], + IRQF_DISABLED, NULL); + if (err < 0) + goto error; + } + + if (fm_port[n] >= 0) { + struct snd_opl3 *opl3; + + err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, + OPL3_HW_AUTO, 0, &opl3); + if (err < 0) { + dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); + goto error; + } + err = snd_opl3_timer_new(opl3, 1, 2); + if (err < 0) + goto error; + + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto error; + } + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(dev, card); + return 0; + +error: + snd_card_free(card); + return err; +} + +static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) +{ + snd_card_free(dev_get_drvdata(dev)); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct isa_driver snd_galaxy_driver = { + .match = snd_galaxy_match, + .probe = snd_galaxy_probe, + .remove = __devexit_p(snd_galaxy_remove), + + .driver = { + .name = DEV_NAME + } +}; + +static int __init alsa_card_galaxy_init(void) +{ + return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_galaxy_exit(void) +{ + isa_unregister_driver(&snd_galaxy_driver); +} + +module_init(alsa_card_galaxy_init); +module_exit(alsa_card_galaxy_exit); -- cgit v0.10.2 From cbaa9f60d5d5c3af10f94e0d49789d5b82341a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Herman?= Date: Fri, 13 Aug 2010 10:43:48 +0200 Subject: ALSA: ISA: Remove snd-sgalaxy Its hardware is handled more fully by the new azt1605/azt2316 drivers. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index e25555c..d0eb696 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1709,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This card is also known as Audio Excel DSP 16 or Zoltrix AV302. - Module snd-sgalaxy - ------------------ - - Module for Aztech Sound Galaxy sound card. - - sbport - Port # for SB16 interface (0x220,0x240) - wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604) - irq - IRQ # (7,9,10,11) - dma1 - DMA # - - This module supports multiple cards. - - The power-management is supported. - Module snd-sscape ----------------- diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index f9aa13d..52064cf 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -377,16 +377,6 @@ config SND_SB16_CSP coprocessor can do variable tasks like various compression and decompression algorithms. -config SND_SGALAXY - tristate "Aztech Sound Galaxy" - select SND_WSS_LIB - help - Say Y here to include support for Aztech Sound Galaxy - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-sgalaxy. - config SND_SSCAPE tristate "Ensoniq SoundScape driver" select SND_MPU401_UART diff --git a/sound/isa/Makefile b/sound/isa/Makefile index d2bd8f5..8d781e4 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sc6000-objs := sc6000.o -snd-sgalaxy-objs := sgalaxy.o snd-sscape-objs := sscape.o # Toplevel Module Dependency @@ -21,7 +20,6 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SC6000) += snd-sc6000.o -obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c deleted file mode 100644 index 6fe27b9..0000000 --- a/sound/isa/sgalaxy.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Driver for Aztech Sound Galaxy cards - * Copyright (c) by Christopher Butler -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define SNDRV_LEGACY_FIND_FREE_IRQ -#define SNDRV_LEGACY_FIND_FREE_DMA -#include - -MODULE_AUTHOR("Christopher Butler "); -MODULE_DESCRIPTION("Aztech Sound Galaxy"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ -static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */ -static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ -static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ -static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); -module_param_array(sbport, long, NULL, 0444); -MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); -module_param_array(wssport, long, NULL, 0444); -MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); -module_param_array(irq, int, NULL, 0444); -MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); -module_param_array(dma1, int, NULL, 0444); -MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); - -#define SGALAXY_AUXC_LEFT 18 -#define SGALAXY_AUXC_RIGHT 19 - -#define PFX "sgalaxy: " - -/* - - */ - -#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x ) - -/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */ -/* short time we actually need it.. */ - -static int snd_sgalaxy_sbdsp_reset(unsigned long port) -{ - int i; - - outb(1, SBP1(port, RESET)); - udelay(10); - outb(0, SBP1(port, RESET)); - udelay(30); - for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++); - if (inb(SBP1(port, READ)) != 0xaa) { - snd_printd("sb_reset: failed at 0x%lx!!!\n", port); - return -ENODEV; - } - return 0; -} - -static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port, - unsigned char val) -{ - int i; - - for (i = 10000; i; i--) - if ((inb(SBP1(port, STATUS)) & 0x80) == 0) { - outb(val, SBP1(port, COMMAND)); - return 1; - } - - return 0; -} - -static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) -{ - return IRQ_NONE; -} - -static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) -{ - static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, - 0x10, 0x18, 0x20, -1, -1, -1, -1}; - static int dma_bits[] = {1, 2, 0, 3}; - int tmp, tmp1; - - if ((tmp = inb(port + 3)) == 0xff) - { - snd_printdd("I/O address dead (0x%lx)\n", port); - return 0; - } -#if 0 - snd_printdd("WSS signature = 0x%x\n", tmp); -#endif - - if ((tmp & 0x3f) != 0x04 && - (tmp & 0x3f) != 0x0f && - (tmp & 0x3f) != 0x00) { - snd_printdd("No WSS signature detected on port 0x%lx\n", - port + 3); - return 0; - } - -#if 0 - snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); -#endif - - /* initialize IRQ for WSS codec */ - tmp = interrupt_bits[irq % 16]; - if (tmp < 0) - return -EINVAL; - - if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) { - snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); - return -EIO; - } - - outb(tmp | 0x40, port); - tmp1 = dma_bits[dma % 4]; - outb(tmp | tmp1, port); - - free_irq(irq, NULL); - - return 0; -} - -static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) -{ -#if 0 - snd_printdd(PFX "switching to WSS mode\n"); -#endif - - /* switch to WSS mode */ - snd_sgalaxy_sbdsp_reset(sbport[dev]); - - snd_sgalaxy_sbdsp_command(sbport[dev], 9); - snd_sgalaxy_sbdsp_command(sbport[dev], 0); - - udelay(400); - return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); -} - -static struct snd_kcontrol_new snd_sgalaxy_controls[] = { -WSS_DOUBLE("Aux Playback Switch", 0, - SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) -}; - -static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) -{ - struct snd_card *card = chip->card; - struct snd_ctl_elem_id id1, id2; - unsigned int idx; - int err; - - memset(&id1, 0, sizeof(id1)); - memset(&id2, 0, sizeof(id2)); - id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - /* reassign AUX0 to LINE */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "Line Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "Line Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - /* reassign AUX1 to FM */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "FM Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "FM Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - /* build AUX2 input */ - for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); - if (err < 0) - return err; - } - return 0; -} - -static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev) -{ - if (!enable[dev]) - return 0; - if (sbport[dev] == SNDRV_AUTO_PORT) { - snd_printk(KERN_ERR PFX "specify SB port\n"); - return 0; - } - if (wssport[dev] == SNDRV_AUTO_PORT) { - snd_printk(KERN_ERR PFX "specify WSS port\n"); - return 0; - } - return 1; -} - -static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) -{ - static int possible_irqs[] = {7, 9, 10, 11, -1}; - static int possible_dmas[] = {1, 3, 0, -1}; - int err, xirq, xdma1; - struct snd_card *card; - struct snd_wss *chip; - - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; - - xirq = irq[dev]; - if (xirq == SNDRV_AUTO_IRQ) { - if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); - err = -EBUSY; - goto _err; - } - } - xdma1 = dma1[dev]; - if (xdma1 == SNDRV_AUTO_DMA) { - if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); - err = -EBUSY; - goto _err; - } - } - - if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) - goto _err; - - err = snd_wss_create(card, wssport[dev] + 4, -1, - xirq, xdma1, -1, - WSS_HW_DETECT, 0, &chip); - if (err < 0) - goto _err; - card->private_data = chip; - - err = snd_wss_pcm(chip, 0, NULL); - if (err < 0) { - snd_printdd(PFX "error creating new WSS PCM device\n"); - goto _err; - } - err = snd_wss_mixer(chip); - if (err < 0) { - snd_printdd(PFX "error creating new WSS mixer\n"); - goto _err; - } - if ((err = snd_sgalaxy_mixer(chip)) < 0) { - snd_printdd(PFX "the mixer rewrite failed\n"); - goto _err; - } - - strcpy(card->driver, "Sound Galaxy"); - strcpy(card->shortname, "Sound Galaxy"); - sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", - wssport[dev], xirq, xdma1); - - snd_card_set_dev(card, devptr); - - if ((err = snd_card_register(card)) < 0) - goto _err; - - dev_set_drvdata(devptr, card); - return 0; - - _err: - snd_card_free(card); - return err; -} - -static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev) -{ - snd_card_free(dev_get_drvdata(devptr)); - dev_set_drvdata(devptr, NULL); - return 0; -} - -#ifdef CONFIG_PM -static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, - pm_message_t state) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct snd_wss *chip = card->private_data; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - chip->suspend(chip); - return 0; -} - -static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct snd_wss *chip = card->private_data; - - chip->resume(chip); - snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); - snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); - - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif - -#define DEV_NAME "sgalaxy" - -static struct isa_driver snd_sgalaxy_driver = { - .match = snd_sgalaxy_match, - .probe = snd_sgalaxy_probe, - .remove = __devexit_p(snd_sgalaxy_remove), -#ifdef CONFIG_PM - .suspend = snd_sgalaxy_suspend, - .resume = snd_sgalaxy_resume, -#endif - .driver = { - .name = DEV_NAME - }, -}; - -static int __init alsa_card_sgalaxy_init(void) -{ - return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS); -} - -static void __exit alsa_card_sgalaxy_exit(void) -{ - isa_unregister_driver(&snd_sgalaxy_driver); -} - -module_init(alsa_card_sgalaxy_init) -module_exit(alsa_card_sgalaxy_exit) -- cgit v0.10.2 From 4f4e8f69895c8696a4bcc751817d4b186023ac44 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 13 Aug 2010 12:42:07 -0700 Subject: ALSA: usb: USB3 SuperSpeed sound support This is V2 of the patch, after feedback from Clemens and Daniel. This patch adds SuperSpeed support to the USB drivers under sound/. It adds tests for USB_SPEED_SUPER to the appropriate places that check for the USB speed. This patch has been tested with our SS USB3 device emulating a set of Yamaha speakers and a Logitech microphone, but with the descriptors modified to add USB3 support. It has also been tested with the real speakers and microphone, to make sure that USB2 devices still work. Signed-off-by: Paul Zimmerman Cc: Clemens Ladisch Cc: Daniel Mack Cc: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/sound/usb/card.c b/sound/usb/card.c index 9feb00c..498a2d8 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -299,9 +299,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, *rchip = NULL; - if (snd_usb_get_speed(dev) != USB_SPEED_LOW && - snd_usb_get_speed(dev) != USB_SPEED_FULL && - snd_usb_get_speed(dev) != USB_SPEED_HIGH) { + switch (snd_usb_get_speed(dev)) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); return -ENXIO; } @@ -377,11 +381,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); - strlcat(card->longname, - snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : - snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : - ", high speed", - sizeof(card->longname)); + switch (snd_usb_get_speed(dev)) { + case USB_SPEED_LOW: + strlcat(card->longname, ", low speed", sizeof(card->longname)); + break; + case USB_SPEED_FULL: + strlcat(card->longname, ", full speed", sizeof(card->longname)); + break; + case USB_SPEED_HIGH: + strlcat(card->longname, ", high speed", sizeof(card->longname)); + break; + case USB_SPEED_SUPER: + strlcat(card->longname, ", super speed", sizeof(card->longname)); + break; + default: + break; + } snd_usb_audio_create_proc(chip); diff --git a/sound/usb/helper.c b/sound/usb/helper.c index d48d6f8..f280c19 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, struct usb_host_interface *alts) { - if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && - get_endpoint(alts, 0)->bInterval >= 1 && - get_endpoint(alts, 0)->bInterval <= 4) - return get_endpoint(alts, 0)->bInterval - 1; - else - return 0; + switch (snd_usb_get_speed(chip->dev)) { + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + if (get_endpoint(alts, 0)->bInterval >= 1 && + get_endpoint(alts, 0)->bInterval <= 4) + return get_endpoint(alts, 0)->bInterval - 1; + break; + default: + break; + } + return 0; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b9c2bc6..156cd07 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; + switch (snd_usb_get_speed(ep->umidi->dev)) { + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + count = 1; + break; + default: + count = 2; + } count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4568298..ebd09ac 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -467,7 +467,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, return 0; } /* check whether the period time is >= the data packet interval */ - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { ptime = 125 * (1 << fp->datainterval); if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); @@ -735,7 +735,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre } param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; - if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) /* full speed devices have fixed data packet interval */ ptmin = 1000; if (ptmin == 1000) diff --git a/sound/usb/proc.c b/sound/usb/proc.c index f5e3f35..3c650ab 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s } snd_iprintf(buffer, "\n"); } - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); diff --git a/sound/usb/urb.c b/sound/usb/urb.c index de607d4..8deeaad 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c @@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, else subs->curpacksize = maxsize; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) packs_per_ms = 8 >> subs->datainterval; else packs_per_ms = 1; -- cgit v0.10.2 From bd76af0f87f7a1815b311bde269a3f18305b3169 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:16:54 +0200 Subject: ALSA: pcm midlevel code - add time check for double interrupt acknowledge The current code in pcm_lib.c do all checks using only the position in the ring buffer. Unfortunately, where the interrupts gets delayed or merged into one, we need another timing source to check when the buffer size boundary overlaps to avoid the wrong updating of the ring buffer pointers. This code uses jiffies to check the right time window without any performance impact. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 85f1c6b..dfd9b76 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -278,6 +278,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ + unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e23e0e7..a1707cc 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* delta = "expected next hw_ptr" for in_interrupt != 0 */ delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - goto __delta; + /* check for double acknowledged interrupts */ + hdelta = jiffies - runtime->hw_ptr_jiffies; + if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + goto __delta; + } } } /* new_hw_ptr might be lower than old_hw_ptr in case when */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 134fc6c..e2e7389 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); runtime->hw_ptr_jiffies = jiffies; + runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / + runtime->rate; runtime->status->state = state; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) -- cgit v0.10.2 From d7d28bc29f4ea7c2d23ed002a9973c64a92bcdb8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:16:54 +0200 Subject: ALSA: pcm midlevel code - add time check for double interrupt acknowledge The current code in pcm_lib.c do all checks using only the position in the ring buffer. Unfortunately, where the interrupts gets delayed or merged into one, we need another timing source to check when the buffer size boundary overlaps to avoid the wrong updating of the ring buffer pointers. This code uses jiffies to check the right time window without any performance impact. Signed-off-by: Jaroslav Kysela diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dd76cde..54c4ccf 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -274,6 +274,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ + unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9d98be..d6ecca2 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -329,11 +329,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* delta = "expected next hw_ptr" for in_interrupt != 0 */ delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - goto __delta; + /* check for double acknowledged interrupts */ + hdelta = jiffies - runtime->hw_ptr_jiffies; + if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + goto __delta; + } } } /* new_hw_ptr might be lower than old_hw_ptr in case when */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 303ac04..2d2e1b6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -867,6 +867,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); runtime->hw_ptr_jiffies = jiffies; + runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / + runtime->rate; runtime->status->state = state; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) -- cgit v0.10.2 From 23b224d9d42a111ce451e4300304415a0ba5da75 Mon Sep 17 00:00:00 2001 From: Garnet MacPhee Date: Sat, 21 Aug 2010 14:37:34 -0600 Subject: ALSA: ice1712: Add support for Edirol DA-2496 This device is similar to the M-Audio Delta 1010LT in that it uses the AK4524VF ADC/DAC, but it does not use the CS8427 for SPDIF. The SPDIF appears to be set up correctly, but I am not able to test it as I do not have any devices that use it. This patch makes the ADC/DAC's and the hardware mixer visible to apps such as alsamixer and envy24control. Signed-off-by: Garnet MacPhee Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index d216362..712c171 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_DELTA1010E: case ICE1712_SUBDEVICE_DELTA1010LT: case ICE1712_SUBDEVICE_MEDIASTATION: + case ICE1712_SUBDEVICE_EDIROLDA2496: ice->num_total_dacs = 8; ice->num_total_adcs = 8; break; @@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); break; case ICE1712_SUBDEVICE_DELTA1010LT: + case ICE1712_SUBDEVICE_EDIROLDA2496: err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); break; case ICE1712_SUBDEVICE_DELTA66: @@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_DELTA66: case ICE1712_SUBDEVICE_VX442: case ICE1712_SUBDEVICE_DELTA66E: + case ICE1712_SUBDEVICE_EDIROLDA2496: err = snd_ice1712_akm4xxx_build_controls(ice); if (err < 0) return err; @@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { .chip_init = snd_ice1712_delta_init, .build_controls = snd_ice1712_delta_add_controls, }, + { + .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496, + .name = "Edirol DA2496", + .model = "da2496", + .chip_init = snd_ice1712_delta_init, + .build_controls = snd_ice1712_delta_add_controls, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index f7f14df..1a0ac6c 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h @@ -34,7 +34,8 @@ "{MidiMan M Audio,Delta 410},"\ "{MidiMan M Audio,Audiophile 24/96},"\ "{Digigram,VX442},"\ - "{Lionstracs,Mediastation}," + "{Lionstracs,Mediastation},"\ + "{Edirol,DA2496}," #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 @@ -47,6 +48,7 @@ #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 #define ICE1712_SUBDEVICE_VX442 0x12143cd6 #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 +#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010 /* entry point */ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; -- cgit v0.10.2 From 65f04443c96dbda11b8fff21d6390e082846aa3c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 2 Sep 2010 12:58:25 +0200 Subject: ALSA: usb-audio: fix Fast Track Ultra (8R) 44.1 sample rates The M-Audio Fast Track Ultra series devices did not play sound correctly at 44.1/88.2 kHz. Changing the output endpoint attribute to adaptive fixes this. Signed-off-by: Felix Homann Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 1a701f1..bb9f938 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -404,8 +404,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) break; case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ - case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; break; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 2e8003f..4818fbd 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1830,7 +1830,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), USB_DEVICE(0x0763, 0x2080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ - /* .product_name = "Fast Track Ultra 8", */ + /* .product_name = "Fast Track Ultra", */ .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_COMPOSITE, .data = & (const struct snd_usb_audio_quirk[]) { @@ -1840,11 +1840,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, { .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = 0x09, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, { .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x81, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, /* interface 3 (MIDI) is standard compliant */ { @@ -1867,11 +1907,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, { .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = 0x09, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, { .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x81, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, /* interface 3 (MIDI) is standard compliant */ { -- cgit v0.10.2 From aa70201fdc374f245cfa1874e11df145ace3ffaf Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:32:43 +0200 Subject: ALSA: usb-audio: add Edirol PCR-1 PCM support Add a quirk for the other logical device of the PCR-1 so that not only the MIDI interface but also the audio interface works. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 4818fbd..838b81b 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1136,11 +1136,34 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0066 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0064), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ /* has ID 0x0067 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0065), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "EDIROL", - .product_name = "PCR-1", + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { -- cgit v0.10.2 From 9d0c91938e3a42c683e4e55d108b928e89a3bbc4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:42:17 +0200 Subject: ALSA: usb-audio: add Roland A-PRO support Add a quirk for the Roland/Cakewalk A-300PRO/A-500PRO/A-800PRO keyboards. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 838b81b..92f099a8 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1548,6 +1548,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x0110 when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "A-PRO", */ + .ifnum = 1, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } + } +}, /* Guillemot devices */ { -- cgit v0.10.2 From 7b28079b3284ccb15ad4f003fb7073890600d0c1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:45:38 +0200 Subject: ALSA: usb-audio: add BOSS ME-25 support Add a quirk to make the BOSS ME-25 work. Many thanks to Kees van Veen. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 92f099a8..c86c613 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1562,6 +1562,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0113), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "BOSS", */ + /* .product_name = "ME-25", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { -- cgit v0.10.2 From 831853c87fb7234a8650484d30993242ea9ad6d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 6 Sep 2010 16:08:56 +0100 Subject: ALSA: Add more jack button slots Some devices have more flexible microphone detection and can detect a wider range of buttons. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai diff --git a/include/sound/jack.h b/include/sound/jack.h index d90b9fa..c140fc7 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -47,6 +47,9 @@ enum snd_jack_types { SND_JACK_BTN_0 = 0x4000, SND_JACK_BTN_1 = 0x2000, SND_JACK_BTN_2 = 0x1000, + SND_JACK_BTN_3 = 0x0800, + SND_JACK_BTN_4 = 0x0400, + SND_JACK_BTN_5 = 0x0200, }; struct snd_jack { @@ -55,7 +58,7 @@ struct snd_jack { int type; const char *id; char name[100]; - unsigned int key[3]; /* Keep in sync with definitions above */ + unsigned int key[6]; /* Keep in sync with definitions above */ void *private_data; void (*private_free)(struct snd_jack *); }; -- cgit v0.10.2 From 9fe856e47e1751204faf3d604c6d20ab24bd3b93 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 4 Sep 2010 18:52:54 -0700 Subject: sound: Remove unnecessary casts of private_data Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf2..86afb13c 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) struct snd_mixer_oss_file *fmixer; if (file->private_data) { - fmixer = (struct snd_mixer_oss_file *) file->private_data; + fmixer = file->private_data; module_put(fmixer->card->module); snd_card_file_remove(fmixer->card, file); kfree(fmixer); @@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); + return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); } int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) @@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *left, int *right) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; *left = *right = 100; if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { @@ -691,7 +691,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int left, int right) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); @@ -740,7 +740,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; int left, right; left = right = 1; @@ -753,7 +753,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; int left, right; left = right = 1; @@ -766,7 +766,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); return 0; @@ -776,7 +776,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); return 0; @@ -813,7 +813,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned if (!(mixer->mask_recsrc & (1 << idx))) continue; pslot = &mixer->slots[idx]; - slot = (struct slot *)pslot->private_data; + slot = pslot->private_data; if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) continue; if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) @@ -861,7 +861,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned if (!(mixer->mask_recsrc & (1 << idx))) continue; pslot = &mixer->slots[idx]; - slot = (struct slot *)pslot->private_data; + slot = pslot->private_data; if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) continue; if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) @@ -925,7 +925,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) { - struct slot *p = (struct slot *)chn->private_data; + struct slot *p = chn->private_data; if (p) { if (p->allocated && p->assigned) { kfree(p->assigned->name); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 204af48..88525a9 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data, - buffer); + snd_pcm_proc_info_read(entry->private_data, buffer); } static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0e631c3..f4cd493 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) sizeof(struct snd_card_virmidi), &card); if (err < 0) return err; - vmidi = (struct snd_card_virmidi *)card->private_data; + vmidi = card->private_data; vmidi->card = card; if (midi_devs[dev] > MAX_MIDI_DEVICES) { diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 1adb8a3..ebab6c7 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) static void proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; + struct snd_akm4xxx *ak = entry->private_data; int reg, val, chip; for (chip = 0; chip < ak->num_chips; chip++) { for (reg = 0; reg < ak->total_regs; reg++) { diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index bbcbf92..3cb75bc 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard sizeof(struct snd_card_ad1816a), &card); if (error < 0) return error; - acard = (struct snd_card_ad1816a *)card->private_data; + acard = card->private_data; if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { snd_card_free(card); diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index f7aa637..aac8dc1 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev, sizeof(struct snd_card_azt2320), &card); if (error < 0) return error; - acard = (struct snd_card_azt2320 *)card->private_data; + acard = card->private_data; if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { snd_card_free(card); diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f26eac8..3e4a58b 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip) static void snd_gusmax_free(struct snd_card *card) { - struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data; + struct snd_gusmax *maxcard = card->private_data; if (maxcard == NULL) return; @@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) return err; card->private_free = snd_gusmax_free; - maxcard = (struct snd_gusmax *)card->private_data; + maxcard = card->private_data; maxcard->card = card; maxcard->irq = -1; diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 81284a8..2259e3f 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) static void snd_sb8_free(struct snd_card *card) { - struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data; + struct snd_sb8 *acard = card->private_data; if (acard == NULL) return; diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c6f2621..8a12621 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -171,7 +171,7 @@ au1550_delay(int msec) static u16 rdcodec(struct ac97_codec *codec, u8 addr) { - struct au1550_state *s = (struct au1550_state *)codec->private_data; + struct au1550_state *s = codec->private_data; unsigned long flags; u32 cmd, val; u16 data; @@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) { - struct au1550_state *s = (struct au1550_state *)codec->private_data; + struct au1550_state *s = codec->private_data; unsigned long flags; u32 cmd, val; int i; @@ -820,7 +820,7 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, static long au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct ac97_codec *codec = s->codec; int ret; @@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) static ssize_t au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db = &s->dma_adc; DECLARE_WAITQUEUE(wait, current); ssize_t ret; @@ -1111,7 +1111,7 @@ out2: static ssize_t au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db = &s->dma_dac; DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; @@ -1211,7 +1211,7 @@ out2: static unsigned int au1550_poll(struct file *file, struct poll_table_struct *wait) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; unsigned long flags; unsigned int mask = 0; @@ -1250,7 +1250,7 @@ au1550_poll(struct file *file, struct poll_table_struct *wait) static int au1550_mmap(struct file *file, struct vm_area_struct *vma) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db; unsigned long size; int ret = 0; @@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db) static int au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; @@ -1868,7 +1868,7 @@ out2: static int au1550_release(struct inode *inode, struct file *file) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; lock_kernel(); diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 8578c70..bab5648 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input = static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) { - struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data; + struct snd_emu10k1_midi *midi = rmidi->private_data; midi->interrupt = NULL; midi->rmidi = NULL; } diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6bc3f91..cdb873f 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = { */ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; char line[64]; unsigned int reg, val; mutex_lock(&ice->gpio_mutex); @@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; mutex_lock(&ice->gpio_mutex); @@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; mutex_lock(&ice->gpio_mutex); diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 2a8e5cd..e36ddb9 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) static void stac9460_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; /* registers 0x0 - 0x14 */ for (reg = 0; reg <= 0x15; reg++) { diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d19dc05..d5f5b44 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data) static void snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) { - struct rme96 *rme96 = (struct rme96 *) pcm->private_data; + struct rme96 *rme96 = pcm->private_data; rme96->spdif_pcm = NULL; } static void snd_rme96_free_adat_pcm(struct snd_pcm *pcm) { - struct rme96 *rme96 = (struct rme96 *) pcm->private_data; + struct rme96 *rme96 = pcm->private_data; rme96->adat_pcm = NULL; } @@ -1661,7 +1661,7 @@ static void snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { int n; - struct rme96 *rme96 = (struct rme96 *)entry->private_data; + struct rme96 *rme96 = entry->private_data; rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); @@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci, if (err < 0) return err; card->private_free = snd_rme96_card_free; - rme96 = (struct rme96 *)card->private_data; + rme96 = card->private_data; rme96->card = card; rme96->pci = pci; snd_card_set_dev(card, &pci->dev); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b92adef..599e090 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) static void snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct hdsp *hdsp = (struct hdsp *) entry->private_data; + struct hdsp *hdsp = entry->private_data; unsigned int status; unsigned int status2; char *pref_sync_ref; @@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { - struct hdsp *hdsp = (struct hdsp *)hw->private_data; + struct hdsp *hdsp = hw->private_data; void __user *argp = (void __user *)arg; int err; @@ -5155,7 +5155,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) static void snd_hdsp_card_free(struct snd_card *card) { - struct hdsp *hdsp = (struct hdsp *) card->private_data; + struct hdsp *hdsp = card->private_data; if (hdsp) snd_hdsp_free(hdsp); @@ -5181,7 +5181,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, if (err < 0) return err; - hdsp = (struct hdsp *) card->private_data; + hdsp = card->private_data; card->private_free = snd_hdsp_card_free; hdsp->dev = dev; hdsp->pci = pci; -- cgit v0.10.2 From add7c0a6a4b8669ebd726f9c08ba6002900ca671 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Jul 2009 18:19:12 +0200 Subject: ALSA: ca0106 - clean up playback pointer callback Clean up the playback pointer callback function a bit, and make the pointer check more strictly to avoid bogus pointers. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6..8e69620 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1002,29 +1002,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ca0106_pcm *epcm = runtime->private_data; - snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; + unsigned int ptr, prev_ptr; int channel = epcm->channel_id; + int timeout = 10; if (!epcm->running) return 0; - ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); - ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); - ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); - if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); - ptr2 = bytes_to_frames(runtime, ptr1); - ptr2+= (ptr4 >> 3) * runtime->period_size; - ptr=ptr2; - if (ptr >= runtime->buffer_size) - ptr -= runtime->buffer_size; - /* - printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " - "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", - ptr1, ptr2, ptr, (int)runtime->buffer_size, - (int)runtime->period_size, (int)runtime->frame_bits, - (int)runtime->rate); - */ - return ptr; + prev_ptr = -1; + do { + ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); + ptr = (ptr >> 3) * runtime->period_size; + ptr += bytes_to_frames(runtime, + snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); + if (ptr >= runtime->buffer_size) + ptr -= runtime->buffer_size; + if (prev_ptr == ptr) + return ptr; + prev_ptr = ptr; + } while (--timeout); + snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); + return 0; } /* pointer_capture callback */ -- cgit v0.10.2 From da0dab5ecb5001f76e739e71ee199db4c61e7af2 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:18:35 +0200 Subject: ALSA: virtuoso: fix WM8766 register writes with MSB The check for the volume update latch bit was accidentally in the wrong function, where it would prevent the MSB from being written, instead of correctly ignoring it for cached values. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index b82c1cf..4346006 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -97,8 +97,12 @@ static void wm8766_write(struct oxygen *chip, (0 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); - if (reg < ARRAY_SIZE(data->wm8766_regs)) + if (reg < ARRAY_SIZE(data->wm8766_regs)) { + if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || + (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) + value &= ~WM8766_UPDATE; data->wm8766_regs[reg] = value; + } } static void wm8766_write_cached(struct oxygen *chip, @@ -107,12 +111,8 @@ static void wm8766_write_cached(struct oxygen *chip, struct xonar_wm87x6 *data = chip->model_data; if (reg >= ARRAY_SIZE(data->wm8766_regs) || - value != data->wm8766_regs[reg]) { - if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || - (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) - value &= ~WM8766_UPDATE; + value != data->wm8766_regs[reg]) wm8766_write(chip, reg, value); - } } static void wm8776_registers_init(struct oxygen *chip) -- cgit v0.10.2 From 9bac84edf0360ac94a27308778ef98dc9068777c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:19:21 +0200 Subject: ALSA: virtuoso: fix Xonar DS input switches Use the correct number, register bits, and names for the input switches. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 4346006..fb3f95c 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -29,6 +29,13 @@ * GPIO 6 -> route input jack to input 1/2 (1/0) * GPIO 7 -> enable output to speakers * GPIO 8 -> enable output to speakers + * + * WM8766: + * + * input 1 <- line + * input 2 <- mic + * input 3 <- front mic + * input 4 <- aux */ #include @@ -896,7 +903,10 @@ static const struct snd_kcontrol_new ds_controls[] = { .put = wm8776_input_mux_put, .private_value = 1 << 1, }, - WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), + WM8776_BIT_SWITCH("Front Mic Capture Switch", + WM8776_ADCMUX, 1 << 2, 0, 0), + WM8776_BIT_SWITCH("Aux Capture Switch", + WM8776_ADCMUX, 1 << 3, 0, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "ADC Filter Capture Enum", -- cgit v0.10.2 From 435feac648cab190990aa0bf9355f77d1f082db3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:20:29 +0200 Subject: ALSA: virtuoso: add Xonar DS headphone jack detection Now that the polarity of the headphone detection pin is known, replace the debugging message with a proper jack plug input device. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e7a8cd0..b40f2b8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -817,6 +817,7 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 100/200 (Xonar)" select SND_OXYGEN_LIB + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index fb3f95c..9d57b5e 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -25,8 +25,8 @@ * SPI 0 -> WM8766 (surround, center/LFE, back) * SPI 1 -> WM8776 (front, input) * - * GPIO 4 <- headphone detect - * GPIO 6 -> route input jack to input 1/2 (1/0) + * GPIO 4 <- headphone detect, 0 = plugged + * GPIO 6 -> route input jack to mic-in (0) or line-in (1) * GPIO 7 -> enable output to speakers * GPIO 8 -> enable output to speakers * @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ struct xonar_wm87x6 { struct snd_kcontrol *line_adcmux_control; struct snd_kcontrol *mic_adcmux_control; struct snd_kcontrol *lc_controls[13]; + struct snd_jack *hp_jack; }; static void wm8776_write(struct oxygen *chip, @@ -177,6 +179,16 @@ static void wm8776_init(struct oxygen *chip) wm8776_registers_init(chip); } +static void xonar_ds_report_hp_jack(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + u16 bits; + + bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); + snd_jack_report(data->hp_jack, + bits & GPIO_DS_HP_DETECT ? 0 : SND_JACK_HEADPHONE); +} + static void xonar_ds_init(struct oxygen *chip) { struct xonar_wm87x6 *data = chip->model_data; @@ -195,6 +207,10 @@ static void xonar_ds_init(struct oxygen *chip) xonar_enable_output(chip); + snd_jack_new(chip->card, "Headphone", + SND_JACK_HEADPHONE, &data->hp_jack); + xonar_ds_report_hp_jack(chip); + snd_component_add(chip->card, "WM8776"); snd_component_add(chip->card, "WM8766"); } @@ -332,10 +348,7 @@ static void update_wm87x6_mute(struct oxygen *chip) static void xonar_ds_gpio_changed(struct oxygen *chip) { - u16 bits; - - bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); + xonar_ds_report_hp_jack(chip); } static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, -- cgit v0.10.2 From 84cf83a28d4a3cd1fac1384cbaa4ed0ba650d309 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:23:06 +0200 Subject: ALSA: virtuoso: automatically handle Xonar DS headphone routing Automatically mute the speaker outputs as long as a headphone is plugged. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 9d57b5e..cee07fe 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -27,8 +27,8 @@ * * GPIO 4 <- headphone detect, 0 = plugged * GPIO 6 -> route input jack to mic-in (0) or line-in (1) - * GPIO 7 -> enable output to speakers - * GPIO 8 -> enable output to speakers + * GPIO 7 -> enable output to front L/R speaker channels + * GPIO 8 -> enable output to other speaker channels and front panel headphone * * WM8766: * @@ -52,7 +52,8 @@ #define GPIO_DS_HP_DETECT 0x0010 #define GPIO_DS_INPUT_ROUTE 0x0040 -#define GPIO_DS_OUTPUT_ENABLE 0x0180 +#define GPIO_DS_OUTPUT_FRONTLR 0x0080 +#define GPIO_DS_OUTPUT_ENABLE 0x0100 #define LC_CONTROL_LIMITER 0x40000000 #define LC_CONTROL_ALC 0x20000000 @@ -150,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip) static void wm8766_registers_init(struct oxygen *chip) { + struct xonar_wm87x6 *data = chip->model_data; + wm8766_write(chip, WM8766_RESET, 0); + wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); wm8766_write(chip, WM8766_DAC_CTRL2, WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); @@ -179,14 +183,38 @@ static void wm8776_init(struct oxygen *chip) wm8776_registers_init(chip); } -static void xonar_ds_report_hp_jack(struct oxygen *chip) +static void wm8766_init(struct oxygen *chip) { struct xonar_wm87x6 *data = chip->model_data; - u16 bits; - bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - snd_jack_report(data->hp_jack, - bits & GPIO_DS_HP_DETECT ? 0 : SND_JACK_HEADPHONE); + data->wm8766_regs[WM8766_DAC_CTRL] = + WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; + wm8766_registers_init(chip); +} + +static void xonar_ds_handle_hp_jack(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + bool hp_plugged; + unsigned int reg; + + mutex_lock(&chip->mutex); + + hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_DS_HP_DETECT); + + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, + GPIO_DS_OUTPUT_FRONTLR); + + reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; + if (hp_plugged) + reg |= WM8766_MUTEALL; + wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); + + snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); + + mutex_unlock(&chip->mutex); } static void xonar_ds_init(struct oxygen *chip) @@ -197,10 +225,12 @@ static void xonar_ds_init(struct oxygen *chip) data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; wm8776_init(chip); - wm8766_registers_init(chip); + wm8766_init(chip); - oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, - GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_DS_HP_DETECT); oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); chip->interrupt_mask |= OXYGEN_INT_GPIO; @@ -209,7 +239,7 @@ static void xonar_ds_init(struct oxygen *chip) snd_jack_new(chip->card, "Headphone", SND_JACK_HEADPHONE, &data->hp_jack); - xonar_ds_report_hp_jack(chip); + xonar_ds_handle_hp_jack(chip); snd_component_add(chip->card, "WM8776"); snd_component_add(chip->card, "WM8766"); @@ -231,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip) wm8776_registers_init(chip); wm8766_registers_init(chip); xonar_enable_output(chip); + xonar_ds_handle_hp_jack(chip); } static void wm8776_adc_hardware_filter(unsigned int channel, @@ -348,7 +379,7 @@ static void update_wm87x6_mute(struct oxygen *chip) static void xonar_ds_gpio_changed(struct oxygen *chip) { - xonar_ds_report_hp_jack(chip); + xonar_ds_handle_hp_jack(chip); } static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, -- cgit v0.10.2 From 2dbf0ea29c1e4dff4ee5f0c59b367168fa2e5a40 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:24:35 +0200 Subject: ALSA: virtuoso: Xonar DS: add stereo upmixing to center/LFE channels Add the possibility to route a mix of the two channels of stereo data to the center and LFE outputs. Due to a WM8766 restriction, all surround and back channels also get the mixed L/R signal in this case. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index cee07fe..aceaaa0 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -377,6 +377,24 @@ static void update_wm87x6_mute(struct oxygen *chip) (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); } +static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) +{ + struct xonar_wm87x6 *data = chip->model_data; + unsigned int reg; + + /* + * The WM8766 can mix left and right channels, but this setting + * applies to all three stereo pairs. + */ + reg = data->wm8766_regs[WM8766_DAC_CTRL] & + ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); + if (mixed) + reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; + else + reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; + wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); +} + static void xonar_ds_gpio_changed(struct oxygen *chip) { xonar_ds_handle_hp_jack(chip); @@ -1067,6 +1085,7 @@ static const struct oxygen_model model_xonar_ds = { .set_adc_params = set_wm8776_adc_params, .update_dac_volume = update_wm87x6_volume, .update_dac_mute = update_wm87x6_mute, + .update_center_lfe_mix = update_wm8766_center_lfe_mix, .gpio_changed = xonar_ds_gpio_changed, .dac_tlv = wm87x6_dac_db_scale, .model_data_size = sizeof(struct xonar_wm87x6), -- cgit v0.10.2 From 99f08bf59019ca6c9056f10ee8f7e1ba6663251c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:25:29 +0200 Subject: ALSA: oxygen: fix CONFIG_SND_OXYGEN_LIB dependency selection As the select directive does not handle indirect dependencies, select those explicitly in the driver sections. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index b40f2b8..0e75d55 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -207,12 +207,12 @@ config SND_CMIPCI config SND_OXYGEN_LIB tristate - select SND_PCM - select SND_MPU401_UART config SND_OXYGEN tristate "C-Media 8788 (Oxygen)" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART help Say Y here to include support for sound cards based on the C-Media CMI8788 (Oxygen HD Audio) chip: @@ -581,6 +581,8 @@ config SND_HDSPM config SND_HIFIER tristate "TempoTec HiFier Fantasia" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART help Say Y here to include support for the MediaTek/TempoTec HiFier Fantasia sound card. @@ -817,6 +819,8 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 100/200 (Xonar)" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the -- cgit v0.10.2 From 51485e8e24919be10bd61dba1dede0032de2d952 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:26:52 +0200 Subject: ALSA: virtuoso: update Kconfig text Update the Xonar config texts with the latest information about the Xonar DS, HDAV1.3 Slim, and Xense. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 0e75d55..12e3465 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -817,17 +817,17 @@ config SND_VIA82XX_MODEM will be called snd-via82xx-modem. config SND_VIRTUOSO - tristate "Asus Virtuoso 100/200 (Xonar)" + tristate "Asus Virtuoso 66/100/200 (Xonar)" select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the - Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, + Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), and Essence STX. - Support for the DS is experimental. - Support for the HDAV1.3 (Deluxe) is very experimental. + Support for the HDAV1.3 (Deluxe) is incomplete; for the + HDAV1.3 Slim and Xense, missing. To compile this driver as a module, choose M here: the module will be called snd-virtuoso. -- cgit v0.10.2 From 6008fd5aa4c15f2ea80a9f997983a9cbfa14ba73 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 10 Sep 2010 16:12:34 +0800 Subject: ALSA: snd-usb-caiaq: drop version number Let git do the job. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index cdfb856..da9cb6d 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -36,7 +36,7 @@ #include "input.h" MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21"); +MODULE_DESCRIPTION("caiaq USB audio"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," -- cgit v0.10.2 From 15c5ab607045e278ebf4d2ca4aea2250617d50ca Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 10 Sep 2010 17:04:57 +0800 Subject: ALSA: snd-usb-caiaq: Add support for Traktor Kontrol S4 This patch adds support for the new Traktor Kontrol S4 by Native Instruments. It features a new audio data streaming model, MIDI in and out ports, a huge number of 174 dimmable LEDs, 96 buttons and 46 absolute encoder axis, including some rotary encoders. All features are supported by the driver now. Did some code refactoring along the way. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 44d6d2e..112984f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -65,6 +65,7 @@ config SND_USB_CAIAQ * Native Instruments Guitar Rig Session I/O * Native Instruments Guitar Rig mobile * Native Instruments Traktor Kontrol X1 + * Native Instruments Traktor Kontrol S4 To compile this driver as a module, choose M here: the module will be called snd-usb-caiaq. @@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT * Native Instruments Kore Controller * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 + * Native Instruments Traktor Kontrol S4 config SND_USB_US122L tristate "Tascam US-122L USB driver" diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad..68b9747 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); dev->input_panic = 0; dev->output_panic = 0; - dev->first_packet = 1; + dev->first_packet = 4; dev->streaming = 1; dev->warned = 0; @@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) } static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, - struct snd_pcm_hw_params *hw_params) + struct snd_pcm_hw_params *hw_params) { debug("%s(%p)\n", __func__, sub); return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); @@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) #endif static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 }; + 48000, 64000, 88200, 96000, 176400, 192000 }; static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) { @@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) debug("%s(%p)\n", __func__, substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; - dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; + int out_pos; + + switch (dev->spec.data_alignment) { + case 0: + case 2: + out_pos = BYTES_PER_SAMPLE + 1; + break; + case 3: + default: + out_pos = 0; + break; + } + + dev->period_out_count[index] = out_pos; + dev->audio_out_buf_pos[index] = out_pos; } else { - int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; - dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; - dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; + int in_pos; + + switch (dev->spec.data_alignment) { + case 0: + in_pos = BYTES_PER_SAMPLE + 2; + break; + case 2: + in_pos = BYTES_PER_SAMPLE; + break; + case 3: + default: + in_pos = 0; + break; + } + + dev->period_in_count[index] = in_pos; + dev->audio_in_buf_pos[index] = in_pos; } if (dev->streaming) @@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) snd_pcm_limit_hw_rates(runtime); bytes_per_sample = BYTES_PER_SAMPLE; - if (dev->spec.data_alignment == 2) + if (dev->spec.data_alignment >= 2) bytes_per_sample++; bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) @@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) { struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); + debug("%s(%p) cmd %d\n", __func__, sub, cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, } } +static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, + const struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; + int stream, i; + + /* paranoia check */ + if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) + return; + + for (i = 0; i < iso->actual_length;) { + for (stream = 0; stream < dev->n_streams; stream++) { + struct snd_pcm_substream *sub = dev->sub_capture[stream]; + char *audio_buf = NULL; + int c, n, sz = 0; + + if (sub && !dev->input_panic) { + struct snd_pcm_runtime *rt = sub->runtime; + audio_buf = rt->dma_area; + sz = frames_to_bytes(rt, rt->buffer_size); + } + + for (c = 0; c < CHANNELS_PER_STREAM; c++) { + /* 3 audio data bytes, followed by 1 check byte */ + if (audio_buf) { + for (n = 0; n < BYTES_PER_SAMPLE; n++) { + audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; + + if (dev->audio_in_buf_pos[stream] == sz) + dev->audio_in_buf_pos[stream] = 0; + } + + dev->period_in_count[stream] += BYTES_PER_SAMPLE; + } + + i += BYTES_PER_SAMPLE; + + if (usb_buf[i] != ((stream << 1) | c) && + !dev->first_packet) { + if (!dev->input_panic) + printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", + ((stream << 1) | c), usb_buf[i], c, stream, i); + dev->input_panic = 1; + } + + i++; + } + } + } + + if (dev->first_packet > 0) + dev->first_packet--; +} + static void read_in_urb(struct snd_usb_caiaqdev *dev, const struct urb *urb, const struct usb_iso_packet_descriptor *iso) @@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, case 2: read_in_urb_mode2(dev, urb, iso); break; + case 3: + read_in_urb_mode3(dev, urb, iso); + break; } if ((dev->input_panic || dev->output_panic) && !dev->warned) { @@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, } } -static void fill_out_urb(struct snd_usb_caiaqdev *dev, - struct urb *urb, - const struct usb_iso_packet_descriptor *iso) +static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) { unsigned char *usb_buf = urb->transfer_buffer + iso->offset; struct snd_pcm_substream *sub; @@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, /* fill in the check bytes */ if (dev->spec.data_alignment == 2 && i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == - (dev->n_streams * CHANNELS_PER_STREAM)) - for (stream = 0; stream < dev->n_streams; stream++, i++) - usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); + (dev->n_streams * CHANNELS_PER_STREAM)) + for (stream = 0; stream < dev->n_streams; stream++, i++) + usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); + } +} + +static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; + int stream, i; + + for (i = 0; i < iso->length;) { + for (stream = 0; stream < dev->n_streams; stream++) { + struct snd_pcm_substream *sub = dev->sub_playback[stream]; + char *audio_buf = NULL; + int c, n, sz = 0; + + if (sub) { + struct snd_pcm_runtime *rt = sub->runtime; + audio_buf = rt->dma_area; + sz = frames_to_bytes(rt, rt->buffer_size); + } + + for (c = 0; c < CHANNELS_PER_STREAM; c++) { + for (n = 0; n < BYTES_PER_SAMPLE; n++) { + if (audio_buf) { + usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; + + if (dev->audio_out_buf_pos[stream] == sz) + dev->audio_out_buf_pos[stream] = 0; + } else { + usb_buf[i+n] = 0; + } + } + + if (audio_buf) + dev->period_out_count[stream] += BYTES_PER_SAMPLE; + + i += BYTES_PER_SAMPLE; + + /* fill in the check byte pattern */ + usb_buf[i++] = (stream << 1) | c; + } + } + } +} + +static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + switch (dev->spec.data_alignment) { + case 0: + case 2: + fill_out_urb_mode_0(dev, urb, iso); + break; + case 3: + fill_out_urb_mode_3(dev, urb, iso); + break; } } diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 91c804c..00e5d0a 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol, case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): maxval = 127; break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + maxval = 31; + break; } if (is_intval) { @@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol, struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); int pos = kcontrol->private_value; + int v = ucontrol->value.integer.value[0]; unsigned char cmd = EP1_CMD_WRITE_IO; if (dev->chip.usb_id == @@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol, cmd = EP1_CMD_DIMM_LEDS; if (pos & CNT_INTVAL) { - dev->control_state[pos & ~CNT_INTVAL] - = ucontrol->value.integer.value[0]; - snd_usb_caiaq_send_command(dev, cmd, - dev->control_state, sizeof(dev->control_state)); + int i = pos & ~CNT_INTVAL; + + dev->control_state[i] = v; + + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) { + int actual_len; + + dev->ep8_out_buf[0] = i; + dev->ep8_out_buf[1] = v; + + usb_bulk_msg(dev->chip.dev, + usb_sndbulkpipe(dev->chip.dev, 8), + dev->ep8_out_buf, sizeof(dev->ep8_out_buf), + &actual_len, 200); + } else { + snd_usb_caiaq_send_command(dev, cmd, + dev->control_state, sizeof(dev->control_state)); + } } else { - if (ucontrol->value.integer.value[0]) + if (v) dev->control_state[pos / 8] |= 1 << (pos % 8); else dev->control_state[pos / 8] &= ~(1 << (pos % 8)); @@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = { { "LED Deck B: SYNC", 8 | CNT_INTVAL }, }; +static struct caiaq_controller kontrols4_controller[] = { + { "LED: Master: Quant", 10 | CNT_INTVAL }, + { "LED: Master: Headphone", 11 | CNT_INTVAL }, + { "LED: Master: Master", 12 | CNT_INTVAL }, + { "LED: Master: Snap", 14 | CNT_INTVAL }, + { "LED: Master: Warning", 15 | CNT_INTVAL }, + { "LED: Master: Master button", 112 | CNT_INTVAL }, + { "LED: Master: Snap button", 113 | CNT_INTVAL }, + { "LED: Master: Rec", 118 | CNT_INTVAL }, + { "LED: Master: Size", 119 | CNT_INTVAL }, + { "LED: Master: Quant button", 120 | CNT_INTVAL }, + { "LED: Master: Browser button", 121 | CNT_INTVAL }, + { "LED: Master: Play button", 126 | CNT_INTVAL }, + { "LED: Master: Undo button", 127 | CNT_INTVAL }, + + { "LED: Channel A: >", 4 | CNT_INTVAL }, + { "LED: Channel A: <", 5 | CNT_INTVAL }, + { "LED: Channel A: Meter 1", 97 | CNT_INTVAL }, + { "LED: Channel A: Meter 2", 98 | CNT_INTVAL }, + { "LED: Channel A: Meter 3", 99 | CNT_INTVAL }, + { "LED: Channel A: Meter 4", 100 | CNT_INTVAL }, + { "LED: Channel A: Meter 5", 101 | CNT_INTVAL }, + { "LED: Channel A: Meter 6", 102 | CNT_INTVAL }, + { "LED: Channel A: Meter clip", 103 | CNT_INTVAL }, + { "LED: Channel A: Active", 114 | CNT_INTVAL }, + { "LED: Channel A: Cue", 116 | CNT_INTVAL }, + { "LED: Channel A: FX1", 149 | CNT_INTVAL }, + { "LED: Channel A: FX2", 148 | CNT_INTVAL }, + + { "LED: Channel B: >", 2 | CNT_INTVAL }, + { "LED: Channel B: <", 3 | CNT_INTVAL }, + { "LED: Channel B: Meter 1", 89 | CNT_INTVAL }, + { "LED: Channel B: Meter 2", 90 | CNT_INTVAL }, + { "LED: Channel B: Meter 3", 91 | CNT_INTVAL }, + { "LED: Channel B: Meter 4", 92 | CNT_INTVAL }, + { "LED: Channel B: Meter 5", 93 | CNT_INTVAL }, + { "LED: Channel B: Meter 6", 94 | CNT_INTVAL }, + { "LED: Channel B: Meter clip", 95 | CNT_INTVAL }, + { "LED: Channel B: Active", 122 | CNT_INTVAL }, + { "LED: Channel B: Cue", 125 | CNT_INTVAL }, + { "LED: Channel B: FX1", 147 | CNT_INTVAL }, + { "LED: Channel B: FX2", 146 | CNT_INTVAL }, + + { "LED: Channel C: >", 6 | CNT_INTVAL }, + { "LED: Channel C: <", 7 | CNT_INTVAL }, + { "LED: Channel C: Meter 1", 105 | CNT_INTVAL }, + { "LED: Channel C: Meter 2", 106 | CNT_INTVAL }, + { "LED: Channel C: Meter 3", 107 | CNT_INTVAL }, + { "LED: Channel C: Meter 4", 108 | CNT_INTVAL }, + { "LED: Channel C: Meter 5", 109 | CNT_INTVAL }, + { "LED: Channel C: Meter 6", 110 | CNT_INTVAL }, + { "LED: Channel C: Meter clip", 111 | CNT_INTVAL }, + { "LED: Channel C: Active", 115 | CNT_INTVAL }, + { "LED: Channel C: Cue", 117 | CNT_INTVAL }, + { "LED: Channel C: FX1", 151 | CNT_INTVAL }, + { "LED: Channel C: FX2", 150 | CNT_INTVAL }, + + { "LED: Channel D: >", 0 | CNT_INTVAL }, + { "LED: Channel D: <", 1 | CNT_INTVAL }, + { "LED: Channel D: Meter 1", 81 | CNT_INTVAL }, + { "LED: Channel D: Meter 2", 82 | CNT_INTVAL }, + { "LED: Channel D: Meter 3", 83 | CNT_INTVAL }, + { "LED: Channel D: Meter 4", 84 | CNT_INTVAL }, + { "LED: Channel D: Meter 5", 85 | CNT_INTVAL }, + { "LED: Channel D: Meter 6", 86 | CNT_INTVAL }, + { "LED: Channel D: Meter clip", 87 | CNT_INTVAL }, + { "LED: Channel D: Active", 123 | CNT_INTVAL }, + { "LED: Channel D: Cue", 124 | CNT_INTVAL }, + { "LED: Channel D: FX1", 145 | CNT_INTVAL }, + { "LED: Channel D: FX2", 144 | CNT_INTVAL }, + + { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL }, + { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL }, + { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL }, + { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL }, + { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL }, + { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL }, + { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL }, + { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL }, + { "LED: Deck A: Load", 44 | CNT_INTVAL }, + { "LED: Deck A: Deck C button", 45 | CNT_INTVAL }, + { "LED: Deck A: In", 47 | CNT_INTVAL }, + { "LED: Deck A: Out", 46 | CNT_INTVAL }, + { "LED: Deck A: Shift", 24 | CNT_INTVAL }, + { "LED: Deck A: Sync", 27 | CNT_INTVAL }, + { "LED: Deck A: Cue", 26 | CNT_INTVAL }, + { "LED: Deck A: Play", 25 | CNT_INTVAL }, + { "LED: Deck A: Tempo up", 33 | CNT_INTVAL }, + { "LED: Deck A: Tempo down", 32 | CNT_INTVAL }, + { "LED: Deck A: Master", 34 | CNT_INTVAL }, + { "LED: Deck A: Keylock", 35 | CNT_INTVAL }, + { "LED: Deck A: Deck A", 37 | CNT_INTVAL }, + { "LED: Deck A: Deck C", 36 | CNT_INTVAL }, + { "LED: Deck A: Samples", 38 | CNT_INTVAL }, + { "LED: Deck A: On Air", 39 | CNT_INTVAL }, + { "LED: Deck A: Sample 1", 31 | CNT_INTVAL }, + { "LED: Deck A: Sample 2", 30 | CNT_INTVAL }, + { "LED: Deck A: Sample 3", 29 | CNT_INTVAL }, + { "LED: Deck A: Sample 4", 28 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL }, + + { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL }, + { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL }, + { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL }, + { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL }, + { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL }, + { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL }, + { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL }, + { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL }, + { "LED: Deck B: Load", 180 | CNT_INTVAL }, + { "LED: Deck B: Deck D button", 181 | CNT_INTVAL }, + { "LED: Deck B: In", 183 | CNT_INTVAL }, + { "LED: Deck B: Out", 182 | CNT_INTVAL }, + { "LED: Deck B: Shift", 64 | CNT_INTVAL }, + { "LED: Deck B: Sync", 67 | CNT_INTVAL }, + { "LED: Deck B: Cue", 66 | CNT_INTVAL }, + { "LED: Deck B: Play", 65 | CNT_INTVAL }, + { "LED: Deck B: Tempo up", 185 | CNT_INTVAL }, + { "LED: Deck B: Tempo down", 184 | CNT_INTVAL }, + { "LED: Deck B: Master", 186 | CNT_INTVAL }, + { "LED: Deck B: Keylock", 187 | CNT_INTVAL }, + { "LED: Deck B: Deck B", 189 | CNT_INTVAL }, + { "LED: Deck B: Deck D", 188 | CNT_INTVAL }, + { "LED: Deck B: Samples", 190 | CNT_INTVAL }, + { "LED: Deck B: On Air", 191 | CNT_INTVAL }, + { "LED: Deck B: Sample 1", 71 | CNT_INTVAL }, + { "LED: Deck B: Sample 2", 70 | CNT_INTVAL }, + { "LED: Deck B: Sample 3", 69 | CNT_INTVAL }, + { "LED: Deck B: Sample 4", 68 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL }, + + { "LED: FX1: dry/wet", 153 | CNT_INTVAL }, + { "LED: FX1: 1", 154 | CNT_INTVAL }, + { "LED: FX1: 2", 155 | CNT_INTVAL }, + { "LED: FX1: 3", 156 | CNT_INTVAL }, + { "LED: FX1: Mode", 157 | CNT_INTVAL }, + { "LED: FX2: dry/wet", 129 | CNT_INTVAL }, + { "LED: FX2: 1", 130 | CNT_INTVAL }, + { "LED: FX2: 2", 131 | CNT_INTVAL }, + { "LED: FX2: 3", 132 | CNT_INTVAL }, + { "LED: FX2: Mode", 133 | CNT_INTVAL }, +}; + static int __devinit add_controls(struct caiaq_controller *c, int num, struct snd_usb_caiaqdev *dev) { @@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) ret = add_controls(kontrolx1_controller, ARRAY_SIZE(kontrolx1_controller), dev); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + ret = add_controls(kontrols4_controller, + ARRAY_SIZE(kontrols4_controller), dev); + break; } return ret; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index da9cb6d..6480c32 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, Audio 8 DJ}," "{Native Instruments, Session I/O}," "{Native Instruments, GuitarRig mobile}" - "{Native Instruments, Traktor Kontrol X1}"); + "{Native Instruments, Traktor Kontrol X1}" + "{Native Instruments, Traktor Kontrol S4}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = { .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_TRAKTORKONTROLX1 }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_TRAKTORKONTROLS4 + }, { /* terminator */ } }; diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index f1117ec..e3d8a3e 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -16,6 +16,7 @@ #define USB_PID_SESSIONIO 0x1915 #define USB_PID_GUITARRIGMOBILE 0x0d8d #define USB_PID_TRAKTORKONTROLX1 0x2305 +#define USB_PID_TRAKTORKONTROLS4 0xbaff #define EP1_BUFSIZE 64 #define EP4_BUFSIZE 512 @@ -99,13 +100,14 @@ struct snd_usb_caiaqdev { struct snd_pcm_substream *sub_capture[MAX_STREAMS]; /* Controls */ - unsigned char control_state[64]; + unsigned char control_state[256]; + unsigned char ep8_out_buf[2]; /* Linux input */ #ifdef CONFIG_SND_USB_CAIAQ_INPUT struct input_dev *input_dev; char phys[64]; /* physical device path */ - unsigned short keycode[64]; + unsigned short keycode[128]; struct urb *ep4_in_urb; unsigned char ep4_in_buf[EP4_BUFSIZE]; #endif diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index dcb6207..4432ef7 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = { KEY_BRL_DOT5 }; -#define KONTROLX1_INPUTS 40 +#define KONTROLX1_INPUTS (40) +#define KONTROLS4_BUTTONS (12 * 8) +#define KONTROLS4_AXIS (46) + +#define KONTROLS4_BUTTON(X) ((X) + BTN_MISC) +#define KONTROLS4_ABS(X) ((X) + ABS_HAT0X) #define DEG90 (range / 2) #define DEG180 (range) @@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) #undef HIGH_PEAK #undef LOW_PEAK +static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, + int axis, const unsigned char *buf, + int offset) +{ + input_report_abs(dev->input_dev, axis, + (buf[offset * 2] << 8) | buf[offset * 2 + 1]); +} static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, const unsigned char *buf, @@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); - input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); + snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); - input_sync(input_dev); - break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): - input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); + snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): - input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); - input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); - input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); - input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]); - input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); - input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); + snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); + snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); + snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); + snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); + snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); + snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); break; } + + input_sync(input_dev); } static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, @@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, input_sync(input_dev); } +#define TKS4_MSGBLOCK_SIZE 16 + +static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, + const unsigned char *buf, + unsigned int len) +{ + while (len) { + unsigned int i, block_id = (buf[0] << 8) | buf[1]; + + switch (block_id) { + case 0: + /* buttons */ + for (i = 0; i < KONTROLS4_BUTTONS; i++) + input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), + (buf[4 + (i / 8)] >> (i % 8)) & 1); + break; + + case 1: + /* left wheel */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); + /* right wheel */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); + + /* rotary encoders */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); + + break; + case 2: + /* Volume Fader Channel D */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); + /* Volume Fader Channel B */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); + /* Volume Fader Channel A */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); + /* Volume Fader Channel C */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); + /* Loop Volume */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); + /* Crossfader */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); + + break; + + case 3: + /* Tempo Fader R */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); + /* Tempo Fader L */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); + /* Mic Volume */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); + /* Cue Mix */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); + + break; + + case 4: + /* Wheel distance sensor L */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); + /* Wheel distance sensor R */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); + /* Channel D EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); + /* Channel D EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); + /* Channel D EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); + /* Channel D EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); + /* FX2 - dry/wet */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); + + break; + + case 5: + /* FX2 - 1 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); + /* FX2 - 2 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); + /* FX2 - 3 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); + /* Channel B EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); + /* Channel B EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); + /* Channel B EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); + /* Channel B EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); + + break; + + case 6: + /* Channel A EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); + /* Channel A EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); + /* Channel A EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); + /* Channel A EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); + /* Channel C EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); + /* Channel C EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); + /* Channel C EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); + + break; + + case 7: + /* Channel C EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); + /* FX1 - wet/dry */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); + /* FX1 - 1 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); + /* FX1 - 2 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); + /* FX1 - 3 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); + + break; + + default: + debug("%s(): bogus block (id %d)\n", + __func__, block_id); + return; + } + + len -= TKS4_MSGBLOCK_SIZE; + buf += TKS4_MSGBLOCK_SIZE; + } + + input_sync(dev->input_dev); +} + static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) { struct snd_usb_caiaqdev *dev = urb->context; @@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) if (urb->status || !dev || urb != dev->ep4_in_urb) return; - if (urb->actual_length < 24) - goto requeue; - switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + if (urb->actual_length < 24) + goto requeue; + if (buf[0] & 0x3) snd_caiaq_input_read_io(dev, buf + 1, 7); @@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) snd_caiaq_input_read_analog(dev, buf + 8, 16); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); + break; } requeue: @@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) return -EIO; break; @@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): usb_kill_urb(dev->ep4_in_urb); break; } @@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); + for (i = 0; i < KONTROLS4_BUTTONS; i++) + dev->keycode[i] = KONTROLS4_BUTTON(i); + input->keycodemax = KONTROLS4_BUTTONS; + + for (i = 0; i < KONTROLS4_AXIS; i++) { + int axis = KONTROLS4_ABS(i); + input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); + } + + /* 36 analog potentiometers and faders */ + for (i = 0; i < 36; i++) + input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10); + + /* 2 encoder wheels */ + input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1); + input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1); + + /* 9 rotary encoders */ + for (i = 0; i < 9; i++) + input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); + + dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->ep4_in_urb) { + ret = -ENOMEM; + goto exit_free_idev; + } + + usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, + usb_rcvbulkpipe(usb_dev, 0x4), + dev->ep4_in_buf, EP4_BUFSIZE, + snd_usb_caiaq_ep4_reply_dispatch, dev); + + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); + + break; + default: /* no input methods supported on this device */ goto exit_free_idev; -- cgit v0.10.2 From 47023ec774b6f73bb11d9f3b00b21f2bbd87e0f2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Sep 2010 21:24:02 -0700 Subject: sound: Use static const char * const where possible Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e2e7389..eb40942 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, #ifdef RULES_DEBUG #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -char *snd_pcm_hw_param_names[] = { +static const char * const snd_pcm_hw_param_names[] = { HW_PARAM(ACCESS), HW_PARAM(FORMAT), HW_PARAM(SUBFORMAT), -- cgit v0.10.2 From a254dba37c5a372fc8b44ba29509ba052d4e859d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 12 Sep 2010 02:41:47 +0100 Subject: ALSA: emux: Add trivial compat ioctl handler Reported-by: Carmen Cru Signed-off-by: Ben Hutchings Signed-off-by: Takashi Iwai diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index ff0b2a8..5ae1eae 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu) strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; hw->ops.ioctl = snd_emux_hwdep_ioctl; + /* The ioctl parameter types are compatible between 32- and + * 64-bit architectures, so use the same function. */ + hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; hw->exclusive = 1; hw->private_data = emu; if ((err = snd_card_register(emu->card)) < 0) -- cgit v0.10.2 From 7b6c3a34e93aafc5dd9adc7dee87c7fa61d8bdbb Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sat, 11 Sep 2010 13:16:41 +0200 Subject: ALSA: sound/ppc/powermac: remove undefined operations Modifying an object twice without an intervening sequence point is undefined. Signed-off-by: Andreas Schwab Signed-off-by: Takashi Iwai diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 20afdf9..961d982 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) if (! mix->i2c.client) return -ENODEV; if (mix->capture_source) - mix->acs = mix->acs |= 2; + mix->acs |= 2; else mix->acs &= ~2; return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); -- cgit v0.10.2 From 645ef9ef1fc0ff70456495b1e21d3420b7b08541 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Sep 2010 21:53:41 +0200 Subject: sound: autoconvert trivial BKL users to private mutex The usage of the BKL in the OSS sound drivers is trivial, and each of them only locks against itself, so it can be turned into per-driver mutexes. This is the script that was used for the conversion: file=$1 name=$2 if grep -q lock_kernel ${file} ; then if grep -q 'include.*linux.mutex.h' ${file} ; then sed -i '/include.*/d' ${file} else sed -i 's/include.*.*$/include /g' ${file} fi sed -i ${file} \ -e "/^#include.*linux.mutex.h/,$ { 1,/^\(static\|int\|long\)/ { /^\(static\|int\|long\)/istatic DEFINE_MUTEX(${name}_mutex); } }" \ -e "s/\(un\)*lock_kernel\>[ ]*()/mutex_\1lock(\&${name}_mutex)/g" \ -e '/[ ]*cycle_kernel_lock();/d' else sed -i -e '/include.*\/d' ${file} \ -e '/cycle_kernel_lock()/d' fi Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index 8a12621..a8f626d 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -77,6 +76,7 @@ /* Boot options * 0 = no VRA, 1 = use VRA if codec supports it */ +static DEFINE_MUTEX(au1550_ac97_mutex); static int vra = 1; module_param(vra, bool, 0); MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); @@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin) static int au1550_open_mixdev(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); file->private_data = &au1550_state; - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return 0; } @@ -824,9 +824,9 @@ au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) struct ac97_codec *codec = s->codec; int ret; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); ret = mixdev_ioctl(codec, cmd, arg); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1255,7 +1255,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; int ret = 0; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); mutex_lock(&s->sem); if (vma->vm_flags & VM_WRITE) db = &s->dma_dac; @@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) db->mapped = 1; out: mutex_unlock(&s->sem); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); ret = au1550_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file) #endif file->private_data = s; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); /* wait for device to become free */ mutex_lock(&s->open_mutex); while (s->open_mode & file->f_mode) { @@ -1861,7 +1861,7 @@ au1550_open(struct inode *inode, struct file *file) out: mutex_unlock(&s->open_mutex); out2: - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1870,12 +1870,12 @@ au1550_release(struct inode *inode, struct file *file) { struct au1550_state *s = file->private_data; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); if (file->f_mode & FMODE_WRITE) { - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); drain_dac(s, file->f_flags & O_NONBLOCK); - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); } mutex_lock(&s->open_mutex); @@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file) s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); mutex_unlock(&s->open_mutex); wake_up(&s->open_wait); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return 0; } diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 6ecd41a..87e2c72 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -181,7 +181,7 @@ #include #include #include -#include +#include #include @@ -194,6 +194,7 @@ * Declarations */ +static DEFINE_MUTEX(dmasound_core_mutex); int dmasound_catchRadius = 0; module_param(dmasound_catchRadius, int, 0); @@ -323,22 +324,22 @@ static struct { static int mixer_open(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (!try_module_get(dmasound.mach.owner)) { - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return -ENODEV; } mixer.busy = 1; - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } static int mixer_release(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); mixer.busy = 0; module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } @@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = mixer_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } @@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file) { int rc; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (!try_module_get(dmasound.mach.owner)) { - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return -ENODEV; } @@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file) sound_set_format(AFMT_MU_LAW); } #endif - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; out: module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return rc; } @@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file) { int rc = 0; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (file->f_mode & FMODE_WRITE) { if (write_sq.busy) @@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file) write_sq_wake_up(file); /* checks f_mode */ #endif /* blocking open() */ - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return rc; } @@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = sq_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } @@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file) int len = 0; int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = -EBUSY; if (state.busy) goto out; @@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ; state.len = len; ret = 0; out: - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } static int state_release(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); state.busy = 0; module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 2e48b17..b4c1eb5 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,6 +79,7 @@ dev.rec_sample_rate / \ dev.rec_channels) +static DEFINE_MUTEX(msnd_pinnacle_mutex); static multisound_dev_t dev; #ifndef HAVE_DSPCODEH @@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = -EINVAL; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) ret = dsp_ioctl(file, cmd, arg); else if (minor == dev.mixer_minor) ret = mixer_ioctl(cmd, arg); - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return ret; } @@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file) int minor = iminor(inode); int err = 0; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) { if ((file->f_mode & FMODE_WRITE && test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || @@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file) } else err = -EINVAL; out: - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return err; } @@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file) int minor = iminor(inode); int err = 0; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) err = dsp_release(file); else if (minor == dev.mixer_minor) { /* nothing */ } else err = -EINVAL; - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return err; } diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index 479e302..53bba16b 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,6 +34,7 @@ #define BUFFER_SIZE 48000 +static DEFINE_MUTEX(sh_dac_audio_mutex); static int rate; static int empty; static char *data_buffer, *buffer_begin, *buffer_end; @@ -163,9 +164,9 @@ static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&sh_dac_audio_mutex); ret = dac_audio_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return ret; } @@ -229,16 +230,16 @@ static int dac_audio_open(struct inode *inode, struct file *file) if (file->f_mode & FMODE_READ) return -ENODEV; - lock_kernel(); + mutex_lock(&sh_dac_audio_mutex); if (in_use) { - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return -EBUSY; } in_use = 1; dac_audio_start(); - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return 0; } diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 92aa762..938ed94 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -56,6 +56,7 @@ * Table for permanently allocated memory (used when unloading the module) */ void * sound_mem_blocks[MAX_MEM_BLOCKS]; +static DEFINE_MUTEX(soundcard_mutex); int sound_nblocks = 0; /* Persistent DMA buffers */ @@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof * big one anyway, we might as well bandage here.. */ - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { @@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof case SND_DEV_MIDIN: ret = MIDIbuf_read(dev, file, buf, count); } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou int dev = iminor(file->f_path.dentry->d_inode); int ret = -EINVAL; - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { case SND_DEV_SEQ: @@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou ret = MIDIbuf_write(dev, file, buf, count); break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file) printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } - lock_kernel(); + mutex_lock(&soundcard_mutex); switch (dev & 0x0f) { case SND_DEV_CTL: dev >>= 4; @@ -247,7 +248,7 @@ static int sound_open(struct inode *inode, struct file *file) retval = -ENXIO; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } @@ -255,7 +256,7 @@ static int sound_release(struct inode *inode, struct file *file) { int dev = iminor(inode); - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: @@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file) default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } @@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == OSS_GETVERSION) return __put_user(SOUND_VERSION, (int __user *)p); - lock_kernel(); + mutex_lock(&soundcard_mutex); if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; @@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = sound_mixer_ioctl(dev >> 4, cmd, p); break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); return -EINVAL; } - lock_kernel(); + mutex_lock(&soundcard_mutex); if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ dmap = audio_devs[dev]->dmap_out; else if (vma->vm_flags & VM_READ) dmap = audio_devs[dev]->dmap_in; else { printk(KERN_ERR "Sound: Undefined mmap() access\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EINVAL; } if (dmap == NULL) { printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (dmap->mapping_flags) { printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (vma->vm_pgoff != 0) { printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EINVAL; } size = vma->vm_end - vma->vm_start; @@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EAGAIN; } @@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index b15840a..44357d8 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -94,6 +93,7 @@ struct cs4297a_state; +static DEFINE_MUTEX(swarm_cs4297a_mutex); static void stop_dac(struct cs4297a_state *s); static void stop_adc(struct cs4297a_state *s); static void start_dac(struct cs4297a_state *s); @@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); list_for_each(entry, &cs4297a_devs) { s = list_entry(entry, struct cs4297a_state, list); @@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return -ENODEV; } VALIDATE_STATE(s); @@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return nonseekable_open(inode, file); } @@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, arg); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } @@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = cs4297a_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } @@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = cs4297a_open(inode, file); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 8cd73cd..643f111 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -145,7 +145,6 @@ #include #include -#include #include #include #include @@ -160,6 +159,7 @@ #ifdef VWSND_DEBUG +static DEFINE_MUTEX(vwsnd_mutex); static int shut_up = 1; /* @@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file, vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; int ret; - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->io_mutex); ret = vwsnd_audio_do_ioctl(file, cmd, arg); mutex_unlock(&devc->io_mutex); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return ret; } @@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) DBGE("(inode=0x%p, file=0x%p)\n", inode, file); - lock_kernel(); + mutex_lock(&vwsnd_mutex); INC_USE_COUNT; for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) @@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) if (devc == NULL) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ENODEV; } @@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) mutex_unlock(&devc->open_mutex); if (file->f_flags & O_NONBLOCK) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -EBUSY; } interruptible_sleep_on(&devc->open_wait); if (signal_pending(current)) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ERESTARTSYS; } mutex_lock(&devc->open_mutex); @@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) file->private_data = devc; DBGRV(); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return 0; } @@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) vwsnd_port_t *wport = NULL, *rport = NULL; int err = 0; - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->io_mutex); { DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); @@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) wake_up(&devc->open_wait); DEC_USE_COUNT; DBGR(); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return err; } @@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); INC_USE_COUNT; - lock_kernel(); + mutex_lock(&vwsnd_mutex); for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) if (devc->mixer_minor == iminor(inode)) break; if (devc == NULL) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ENODEV; } file->private_data = devc; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return 0; } @@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file, DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->mix_mutex); { if ((cmd & ~nrmask) == MIXER_READ(0)) @@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file, retval = -EINVAL; } mutex_unlock(&devc->mix_mutex); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return retval; } -- cgit v0.10.2 From 1446c5fba73044a1c72153e1203b23b1820431c5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 15 Sep 2010 08:01:57 +0200 Subject: ALSA: snd-aloop - fix the "PCM Playback Channels" kcontrol Obvious copy-and-paste error. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 3123a15..f2b8f86 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -809,7 +809,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] - [kcontrol->id.device].rate; + [kcontrol->id.device].channels; return 0; } -- cgit v0.10.2 From 1a4e34e67c6de2385d9d493e69c0f6fce886b14d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 07:42:34 +0200 Subject: ALSA: usb-audio - Fix an unused-variable compile warning Used only when CONFIG_SND_DEBUG=y sound/usb/mixer.c: In function 'get_min_max': sound/usb/mixer.c:762: warning: unused variable 'chip' Reported-by: Andrew Morton Signed-off-by: Takashi Iwai diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 3ed3901..5f12e29 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) */ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) { - struct snd_usb_audio *chip = cval->mixer->chip; - /* for failsafe */ cval->min = default_min; cval->max = cval->min + 1; @@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", - cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id); + cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); return -EINVAL; } if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { -- cgit v0.10.2 From 4437ecdc7190302ed02fb1467c116aff29c325b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Sep 2010 10:26:54 +0300 Subject: ALSA: core: Allow card id change to the same string When user want to change the card id to the same string on the card via /sys/class/sound/cardX/id, do not report error. Instead return with success without doing anything. Signed-off-by: Peter Ujfalusi Signed-off-by: Takashi Iwai diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50c..2de45fb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -607,11 +607,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, return -EEXIST; } for (idx = 0; idx < snd_ecards_limit; idx++) { - if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) - goto __exist; + if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { + if (card == snd_cards[idx]) + goto __ok; + else + goto __exist; + } } strcpy(card->id, buf1); snd_info_card_id_change(card); +__ok: mutex_unlock(&snd_card_mutex); return count; -- cgit v0.10.2 From 26e34e9e15aa48e9375ea4e97bc4234ad995b7c8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Sep 2010 20:13:47 +0200 Subject: ALSA: usb/mixer: remove bogus cast "uinfo->value.enumerated.item" is an unsigned int. If it's negative when we do the comparison: if ((int)uinfo->value.enumerated.item >= cval->max) then we would read past the end of the array on the next line. I also changed the strcpy() to strlcpy() out of paranoia. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5f12e29..f2d74d6 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1640,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = cval->max; - if ((int)uinfo->value.enumerated.item >= cval->max) + if (uinfo->value.enumerated.item >= cval->max) uinfo->value.enumerated.item = cval->max - 1; - strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]); + strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); return 0; } -- cgit v0.10.2 From 095a0f6df246bdc57b57d616c4698e41fbd3bf43 Mon Sep 17 00:00:00 2001 From: John Kacur Date: Wed, 22 Sep 2010 13:47:01 +0200 Subject: SOUND-OSS: Remove sh_dac_audio Remove the SH DAC oss driver since there is an equivalent alsa driver. oss has been deprecated for years. Furthermore this driver has BKL code which we are trying to remove. Rather than attempt to fix this, simply remove the driver. Signed-off-by: John Kacur Acked-by: Paul Mundt Acked-by: Ralf Baechle Signed-off-by: Takashi Iwai diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a513651..76c0902 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -545,11 +545,3 @@ config SOUND_KAHLUA endif # SOUND_OSS -config SOUND_SH_DAC_AUDIO - tristate "SuperH DAC audio support" - depends on CPU_SH3 && HIGH_RES_TIMERS - -config SOUND_SH_DAC_AUDIO_CHANNEL - int "DAC channel" - default "1" - depends on SOUND_SH_DAC_AUDIO diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 567b8a7..96f14dc 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o # Please leave it as is, cause the link order is significant ! -obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c deleted file mode 100644 index 53bba16b..0000000 --- a/sound/oss/sh_dac_audio.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * sound/oss/sh_dac_audio.c - * - * SH DAC based sound :( - * - * Copyright (C) 2004,2005 Andriy Skulysh - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MODNAME "sh_dac_audio" - -#define BUFFER_SIZE 48000 - -static DEFINE_MUTEX(sh_dac_audio_mutex); -static int rate; -static int empty; -static char *data_buffer, *buffer_begin, *buffer_end; -static int in_use, device_major; -static struct hrtimer hrtimer; -static ktime_t wakeups_per_second; - -static void dac_audio_start_timer(void) -{ - hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); -} - -static void dac_audio_stop_timer(void) -{ - hrtimer_cancel(&hrtimer); -} - -static void dac_audio_reset(void) -{ - dac_audio_stop_timer(); - buffer_begin = buffer_end = data_buffer; - empty = 1; -} - -static void dac_audio_sync(void) -{ - while (!empty) - schedule(); -} - -static void dac_audio_start(void) -{ - if (mach_is_hp6xx()) { - u16 v = __raw_readw(HD64461_GPADR); - v &= ~HD64461_GPADR_SPEAKER; - __raw_writew(v, HD64461_GPADR); - } - - sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); -} -static void dac_audio_stop(void) -{ - dac_audio_stop_timer(); - - if (mach_is_hp6xx()) { - u16 v = __raw_readw(HD64461_GPADR); - v |= HD64461_GPADR_SPEAKER; - __raw_writew(v, HD64461_GPADR); - } - - sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); - sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); -} - -static void dac_audio_set_rate(void) -{ - wakeups_per_second = ktime_set(0, 1000000000 / rate); -} - -static int dac_audio_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int val; - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *)arg); - - case SNDCTL_DSP_SYNC: - dac_audio_sync(); - return 0; - - case SNDCTL_DSP_RESET: - dac_audio_reset(); - return 0; - - case SNDCTL_DSP_GETFMTS: - return put_user(AFMT_U8, (int *)arg); - - case SNDCTL_DSP_SETFMT: - return put_user(AFMT_U8, (int *)arg); - - case SNDCTL_DSP_NONBLOCK: - spin_lock(&file->f_lock); - file->f_flags |= O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; - - case SNDCTL_DSP_GETCAPS: - return 0; - - case SOUND_PCM_WRITE_RATE: - val = *(int *)arg; - if (val > 0) { - rate = val; - dac_audio_set_rate(); - } - return put_user(rate, (int *)arg); - - case SNDCTL_DSP_STEREO: - return put_user(0, (int *)arg); - - case SOUND_PCM_WRITE_CHANNELS: - return put_user(1, (int *)arg); - - case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; - - case SNDCTL_DSP_PROFILE: - return -EINVAL; - - case SNDCTL_DSP_GETBLKSIZE: - return put_user(BUFFER_SIZE, (int *)arg); - - case SNDCTL_DSP_SETFRAGMENT: - return 0; - - default: - printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n", - cmd); - return -EINVAL; - } - return -EINVAL; -} - -static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) -{ - int ret; - - mutex_lock(&sh_dac_audio_mutex); - ret = dac_audio_ioctl(file, cmd, arg); - mutex_unlock(&sh_dac_audio_mutex); - - return ret; -} - -static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, - loff_t * ppos) -{ - int free; - int nbytes; - - if (!count) { - dac_audio_sync(); - return 0; - } - - free = buffer_begin - buffer_end; - - if (free < 0) - free += BUFFER_SIZE; - if ((free == 0) && (empty)) - free = BUFFER_SIZE; - if (count > free) - count = free; - if (buffer_begin > buffer_end) { - if (copy_from_user((void *)buffer_end, buf, count)) - return -EFAULT; - - buffer_end += count; - } else { - nbytes = data_buffer + BUFFER_SIZE - buffer_end; - if (nbytes > count) { - if (copy_from_user((void *)buffer_end, buf, count)) - return -EFAULT; - buffer_end += count; - } else { - if (copy_from_user((void *)buffer_end, buf, nbytes)) - return -EFAULT; - if (copy_from_user - ((void *)data_buffer, buf + nbytes, count - nbytes)) - return -EFAULT; - buffer_end = data_buffer + count - nbytes; - } - } - - if (empty) { - empty = 0; - dac_audio_start_timer(); - } - - return count; -} - -static ssize_t dac_audio_read(struct file *file, char *buf, size_t count, - loff_t * ppos) -{ - return -EINVAL; -} - -static int dac_audio_open(struct inode *inode, struct file *file) -{ - if (file->f_mode & FMODE_READ) - return -ENODEV; - - mutex_lock(&sh_dac_audio_mutex); - if (in_use) { - mutex_unlock(&sh_dac_audio_mutex); - return -EBUSY; - } - - in_use = 1; - - dac_audio_start(); - mutex_unlock(&sh_dac_audio_mutex); - return 0; -} - -static int dac_audio_release(struct inode *inode, struct file *file) -{ - dac_audio_sync(); - dac_audio_stop(); - in_use = 0; - - return 0; -} - -const struct file_operations dac_audio_fops = { - .read = dac_audio_read, - .write = dac_audio_write, - .unlocked_ioctl = dac_audio_unlocked_ioctl, - .open = dac_audio_open, - .release = dac_audio_release, -}; - -static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) -{ - if (!empty) { - sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); - buffer_begin++; - - if (buffer_begin == data_buffer + BUFFER_SIZE) - buffer_begin = data_buffer; - if (buffer_begin == buffer_end) - empty = 1; - } - - if (!empty) - hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); - - return HRTIMER_NORESTART; -} - -static int __init dac_audio_init(void) -{ - if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { - printk(KERN_ERR "Cannot register dsp device"); - return device_major; - } - - in_use = 0; - - data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); - if (data_buffer == NULL) - return -ENOMEM; - - dac_audio_reset(); - rate = 8000; - dac_audio_set_rate(); - - /* Today: High Resolution Timer driven DAC playback. - * The timer callback gets called once per sample. Ouch. - * - * Future: A much better approach would be to use the - * SH7720 CMT+DMAC+DAC hardware combination like this: - * - Program sample rate using CMT0 or CMT1 - * - Program DMAC to use CMT for timing and output to DAC - * - Play sound using DMAC, let CPU sleep. - * - While at it, rewrite this driver to use ALSA. - */ - - hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer.function = sh_dac_audio_timer; - - return 0; -} - -static void __exit dac_audio_exit(void) -{ - unregister_sound_dsp(device_major); - kfree((void *)data_buffer); -} - -module_init(dac_audio_init); -module_exit(dac_audio_exit); - -MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); -MODULE_DESCRIPTION("SH DAC sound driver"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 20d9a26dbbbec32aa7c9da49b979f201bd7104b9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 30 Sep 2010 00:16:50 +0200 Subject: ALSA: snd-aloop - fix capture buffer silence In a special case, some old samples are left in the capture ring buffer. Fix it. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index f2b8f86..2748fee 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -347,7 +347,7 @@ static void copy_play_buf(struct loopback_pcm *play, unsigned int bytes) { struct snd_pcm_runtime *runtime = play->substream->runtime; - char *src = play->substream->runtime->dma_area; + char *src = runtime->dma_area; char *dst = capt->substream->runtime->dma_area; unsigned int src_off = play->buf_pos; unsigned int dst_off = capt->buf_pos; @@ -385,8 +385,10 @@ static void copy_play_buf(struct loopback_pcm *play, dst_off = (dst_off + size) % capt->pcm_buffer_size; } - if (clear_bytes > 0) + if (clear_bytes > 0) { clear_capture_buf(capt, clear_bytes); + capt->silent_size = 0; + } } #define BYTEPOS_UPDATE_POSONLY 0 -- cgit v0.10.2 From ac446fb7e690b317050ed158ba5dfd9273dc9e74 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 2 Oct 2010 16:00:53 +0200 Subject: ALSA: snd-aloop - fix "PCM Slave Active" element read value Simple coding fix. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 2748fee..040030a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -739,7 +739,7 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); struct loopback_cable *cable = loopback->cables - [kcontrol->id.subdevice][kcontrol->id.device]; + [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; unsigned int val = 0; if (cable != NULL) -- cgit v0.10.2 From 422fdc318efd7d34d8b79decde0f8cb90a336c11 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:09:12 +0200 Subject: ALSA: usb-audio: add more Yamaha USB MIDI devices Add quirks for more devices (according to driver V.3.0.4-2). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c86c613..682e3e0 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL), YAMAHA_DEVICE(0x1050, NULL), YAMAHA_DEVICE(0x1051, NULL), YAMAHA_DEVICE(0x1052, NULL), +YAMAHA_INTERFACE(0x1053, 0, NULL), +YAMAHA_INTERFACE(0x1054, 0, NULL), +YAMAHA_DEVICE(0x1055, NULL), +YAMAHA_DEVICE(0x1056, NULL), +YAMAHA_DEVICE(0x1057, NULL), +YAMAHA_DEVICE(0x1058, NULL), +YAMAHA_DEVICE(0x1059, NULL), +YAMAHA_DEVICE(0x105a, NULL), +YAMAHA_DEVICE(0x105b, NULL), +YAMAHA_DEVICE(0x105c, NULL), +YAMAHA_DEVICE(0x105d, NULL), YAMAHA_DEVICE(0x2000, "DGP-7"), YAMAHA_DEVICE(0x2001, "DGP-5"), YAMAHA_DEVICE(0x2002, NULL), +YAMAHA_DEVICE(0x2003, NULL), YAMAHA_DEVICE(0x5000, "CS1D"), YAMAHA_DEVICE(0x5001, "DSP1D"), YAMAHA_DEVICE(0x5002, "DME32"), -- cgit v0.10.2 From 45bc307f328c044e69cad2a18a9ae972bb15f254 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:17:26 +0200 Subject: ALSA: virtuoso: fix Xonar DS chip name The controller on the Xonar DS is labeled "AV66", not "AV200". Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 06c863e..599bb9a 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -25,9 +25,9 @@ #include "xonar.h" MODULE_AUTHOR("Clemens Ladisch "); -MODULE_DESCRIPTION("Asus AVx00 driver"); +MODULE_DESCRIPTION("Asus Virtuoso driver"); MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); +MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index aceaaa0..5f9f59c 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1071,7 +1071,7 @@ static int xonar_ds_mixer_init(struct oxygen *chip) static const struct oxygen_model model_xonar_ds = { .shortname = "Xonar DS", - .longname = "Asus Virtuoso 200", + .longname = "Asus Virtuoso 66", .chip = "AV200", .init = xonar_ds_init, .control_filter = xonar_ds_control_filter, -- cgit v0.10.2 From b6ca8ab399d913eed0d89d65d6b768337a3d20d7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:21:52 +0200 Subject: ALSA: oxygen: handle CD input configuration with a flag There are more models without a CD input than with one, so handle this explicitly with a device_config flag to avoid having to define a control filter callback to filter it out. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 289cb4d..f4fdf6d 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -505,7 +505,8 @@ static const struct oxygen_model model_generic = { PLAYBACK_2_TO_AC97_1 | CAPTURE_0_FROM_I2S_1 | CAPTURE_1_FROM_SPDIF | - CAPTURE_2_FROM_AC97_1, + CAPTURE_2_FROM_AC97_1 | + AC97_CD_INPUT, .dac_channels = 8, .dac_volume_min = 0, .dac_volume_max = 255, diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a3409ed..7d5222c 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -34,6 +34,7 @@ /* CAPTURE_3_FROM_I2S_3 not implemented */ #define MIDI_OUTPUT 0x0800 #define MIDI_INPUT 0x1000 +#define AC97_CD_INPUT 0x2000 enum { CONTROL_SPDIF_PCM, diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index f375b8a..7d40ba8 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip, if (!strcmp(template.name, "Stereo Upmixing") && chip->model.dac_channels == 2) continue; + if (!strncmp(template.name, "CD Capture ", 11) && + !(chip->model.device_config & AC97_CD_INPUT)) + continue; if (!strcmp(template.name, "Master Playback Volume") && chip->model.dac_tlv) { template.tlv.p = chip->model.dac_tlv; diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 7c4986b..aa27c310 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); -static int xonar_d1_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - return 0; -} - static int xonar_d1_mixer_init(struct oxygen *chip) { int err; @@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = { .longname = "Asus Virtuoso 100", .chip = "AV200", .init = xonar_d1_init, - .control_filter = xonar_d1_control_filter, .mixer_init = xonar_d1_mixer_init, .cleanup = xonar_d1_cleanup, .suspend = xonar_d1_suspend, diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index ba18fb5..338f885 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -915,13 +915,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template) return 0; } -static int xonar_st_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - return 0; -} - static int add_pcm1796_controls(struct oxygen *chip) { int err; @@ -991,7 +984,8 @@ static const struct oxygen_model model_xonar_d2 = { CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF | MIDI_OUTPUT | - MIDI_INPUT, + MIDI_INPUT | + AC97_CD_INPUT, .dac_channels = 8, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, @@ -1037,7 +1031,6 @@ static const struct oxygen_model model_xonar_st = { .longname = "Asus Virtuoso 100", .chip = "AV200", .init = xonar_st_init, - .control_filter = xonar_st_control_filter, .mixer_init = xonar_st_mixer_init, .cleanup = xonar_st_cleanup, .suspend = xonar_st_suspend, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 5f9f59c..200f760 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1028,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = { LC_CONTROL_ALC, wm8776_ngth_db_scale), }; -static int xonar_ds_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - return 0; -} - static int xonar_ds_mixer_init(struct oxygen *chip) { struct xonar_wm87x6 *data = chip->model_data; @@ -1074,7 +1067,6 @@ static const struct oxygen_model model_xonar_ds = { .longname = "Asus Virtuoso 66", .chip = "AV200", .init = xonar_ds_init, - .control_filter = xonar_ds_control_filter, .mixer_init = xonar_ds_mixer_init, .cleanup = xonar_ds_cleanup, .suspend = xonar_ds_suspend, -- cgit v0.10.2 From 2b830bae1fc2a27b3b0ab86091013bdec3c12427 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:22:51 +0200 Subject: ALSA: virtuoso: add HDAV1.3 Slim PCI ID Add a PCI ID for the Xonar HDAV1.3 Slim. There is no actual support, but the presence of the ID allows the EEPROM repair code to work for this card. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 599bb9a..469010a 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, + { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 338f885..571d0ae 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -132,6 +132,18 @@ * GPIO 5 <- 0 */ +/* + * Xonar HDAV1.3 Slim + * ------------------ + * + * CMI8788: + * + * GPIO 1 -> enable output + * + * TXD -> HDMI controller + * RXD <- HDMI controller + */ + #include #include #include @@ -1101,6 +1113,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; break; + case 0x835e: + snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n"); + return -ENODEV; default: return -EINVAL; } -- cgit v0.10.2 From d737f3eedef0717c8b8233bb6455ff13637ff243 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:23:26 +0200 Subject: ALSA: virtuoso: fix Xonar STX anti-pop delay The anti-pop delay for the STX should be 800 ms, not 100 ms like the ST. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 571d0ae..d491fd6 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -374,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; - data->generic.anti_pop_delay = 100; data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; data->dacs = chip->model.private_data ? 4 : 1; data->hp_gain_offset = 2*-18; @@ -420,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; + data->generic.anti_pop_delay = 100; data->has_cs2000 = 1; data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; @@ -440,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip) struct xonar_pcm179x *data = chip->model_data; xonar_st_init_i2c(chip); + data->generic.anti_pop_delay = 800; data->generic.ext_power_reg = OXYGEN_GPI_DATA; data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; data->generic.ext_power_bit = GPI_EXT_POWER; -- cgit v0.10.2 From de0074ee7ae7d61da40567afa53912d7e3e16b25 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:24:43 +0200 Subject: ALSA: oxygen: fix chip ID register symbols Rename the symbol for the XCID pins, fix up a decimal/hex confusion for the CMI8787 package ID, and add the other known package IDs. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 72de159..4dcd41b 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h @@ -436,13 +436,15 @@ /* OXYGEN_CHANNEL_* */ #define OXYGEN_CODEC_VERSION 0xe4 -#define OXYGEN_XCID_MASK 0x07 +#define OXYGEN_CODEC_ID_MASK 0x07 #define OXYGEN_REVISION 0xe6 -#define OXYGEN_REVISION_XPKGID_MASK 0x0007 +#define OXYGEN_PACKAGE_ID_MASK 0x0007 +#define OXYGEN_PACKAGE_ID_8786 0x0004 +#define OXYGEN_PACKAGE_ID_8787 0x0006 +#define OXYGEN_PACKAGE_ID_8788 0x0007 #define OXYGEN_REVISION_MASK 0xfff8 -#define OXYGEN_REVISION_2 0x0008 /* bit flag */ -#define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ +#define OXYGEN_REVISION_2 0x0008 #define OXYGEN_OFFSIN_48K 0xe8 #define OXYGEN_OFFSBASE_48K 0xe9 -- cgit v0.10.2 From 9a0b37926595b57c4b5fc56aa6fd243bed4ee4eb Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Oct 2010 13:25:13 +0200 Subject: ALSA: oxygen: fix input monitor dB scale The input monitor half volume bit results in a factor of 0.5, so the minimum scale value should be -6 dB. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 7d40ba8..2849b36 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ } -static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); +static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0); static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); -- cgit v0.10.2 From 93943beb29be7084afb61556e96bc454079bfb0e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Oct 2010 10:57:11 +0200 Subject: ALSA: oxygen: reduce minimum period count The interrupt counter is independent of the buffer counter, so there are no restrictions on the period size. Having fewer periods also makes PulseAudio happy. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 9dff695..8146674 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { .channels_max = 2, .buffer_bytes_max = BUFFER_BYTES_MAX, .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX / 2, - .periods_min = 2, + .period_bytes_max = BUFFER_BYTES_MAX, + .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, }; static const struct snd_pcm_hardware oxygen_multichannel_hardware = { @@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .channels_max = 8, .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, - .periods_min = 2, + .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, + .periods_min = 1, .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, }; static const struct snd_pcm_hardware oxygen_ac97_hardware = { @@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { .channels_max = 2, .buffer_bytes_max = BUFFER_BYTES_MAX, .period_bytes_min = PERIOD_BYTES_MIN, - .period_bytes_max = BUFFER_BYTES_MAX / 2, - .periods_min = 2, + .period_bytes_max = BUFFER_BYTES_MAX, + .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, }; -- cgit v0.10.2 From 7cb4ced5aa83b681c76b004c8960b4f2a6471fef Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Oct 2010 10:57:50 +0200 Subject: ALSA: oxygen: rewrite PCIe bridge initialization Change the PCIe/PCI bridge initialization code to configure only the bridge that is actually connected to the sound chip, instead of any bridge found in the system. The new code also makes it easier to add other bridges. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 7e93cf8..d10cc6e 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -308,25 +308,31 @@ static void oxygen_restore_eeprom(struct oxygen *chip, } } -static void pci_bridge_magic(void) +static void configure_pcie_bridge(struct pci_dev *pci) { - struct pci_dev *pci = NULL; + enum { PI7C9X110 }; + static const struct pci_device_id bridge_ids[] = { + { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, + { } + }; + struct pci_dev *bridge; + const struct pci_device_id *id; u32 tmp; - for (;;) { - /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ - pci = pci_get_device(0x12d8, 0xe110, pci); - if (!pci) - break; - /* - * ... configure its secondary internal arbiter to park to - * the secondary port, instead of to the last master. - */ - if (!pci_read_config_dword(pci, 0x40, &tmp)) { - tmp |= 1; - pci_write_config_dword(pci, 0x40, tmp); - } - /* Why? Try asking C-Media. */ + if (!pci->bus || !pci->bus->self) + return; + bridge = pci->bus->self; + + id = pci_match_id(bridge_ids, bridge); + if (!id) + return; + + switch (id->driver_data) { + case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ + pci_read_config_dword(bridge, 0x40, &tmp); + tmp |= 1; /* park the PCI arbiter to the sound chip */ + pci_write_config_dword(bridge, 0x40, tmp); + break; } } @@ -613,7 +619,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, snd_card_set_dev(card, &pci->dev); card->private_free = oxygen_card_free; - pci_bridge_magic(); + configure_pcie_bridge(pci); oxygen_init(chip); chip->model.init(chip); -- cgit v0.10.2 From ebebeece4ba596973c0c181a8cce5fd77bae427c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Oct 2010 10:58:50 +0200 Subject: ALSA: oxygen: add PEX8111 initialization Configure the PEX8111 bridge on the PCI Express cards so that the audio DMA controller can do proper burst reads and is less likely to lose data. This is usually done automatically, but is required on older cards where the user has not applied the PLX firmware update. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index d10cc6e..e5ebe56 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -310,8 +310,10 @@ static void oxygen_restore_eeprom(struct oxygen *chip, static void configure_pcie_bridge(struct pci_dev *pci) { - enum { PI7C9X110 }; + enum { PEX811X, PI7C9X110 }; static const struct pci_device_id bridge_ids[] = { + { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, + { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, { } }; @@ -328,6 +330,19 @@ static void configure_pcie_bridge(struct pci_dev *pci) return; switch (id->driver_data) { + case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */ + pci_read_config_dword(bridge, 0x48, &tmp); + tmp |= 1; /* enable blind prefetching */ + tmp |= 1 << 11; /* enable beacon generation */ + pci_write_config_dword(bridge, 0x48, tmp); + + pci_write_config_dword(bridge, 0x84, 0x0c); + pci_read_config_dword(bridge, 0x88, &tmp); + tmp &= ~(7 << 27); + tmp |= 2 << 27; /* set prefetch size to 128 bytes */ + pci_write_config_dword(bridge, 0x88, tmp); + break; + case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ pci_read_config_dword(bridge, 0x40, &tmp); tmp |= 1; /* park the PCI arbiter to the sound chip */ -- cgit v0.10.2 From dd1d3a49db4ae5c6afffadaff526b96c7993c7dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 6 Oct 2010 17:28:56 +0200 Subject: ALSA: oxygen - Add a SSID for CMI8787-HG2PCI This board has a strange PCI SSID 13f6:ffff. Works as compabile as MODEL_CMEDIA_REF. Reported-by: Takashi Sakamoto Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index f4fdf6d..1d915ef 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, + { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, -- cgit v0.10.2 From b1c73fc8e697eb73e23603e465e9af2711ed4183 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 11 Oct 2010 10:45:00 +0200 Subject: ALSA: snd-aloop: Fix hw_params restrictions and checking This patch fixes the hw_params restrictions when first (or playback) stream sets the final hardware parameters. Also, fix the hw_params checking in the trigger callback. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 040030a..3c00882 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -188,7 +188,7 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm) static int loopback_check_format(struct loopback_cable *cable, int stream) { - struct snd_pcm_runtime *runtime; + struct snd_pcm_runtime *runtime, *cruntime; struct loopback_setup *setup; struct snd_card *card; int check; @@ -200,11 +200,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) } runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> substream->runtime; - check = cable->hw.formats != (1ULL << runtime->format) || - cable->hw.rate_min != runtime->rate || - cable->hw.rate_max != runtime->rate || - cable->hw.channels_min != runtime->channels || - cable->hw.channels_max != runtime->channels; + cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> + substream->runtime; + check = runtime->format != cruntime->format || + runtime->rate != cruntime->rate || + runtime->channels != cruntime->channels; if (!check) return 0; if (stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -274,12 +274,42 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } +static void params_change_substream(struct loopback_pcm *dpcm, + struct snd_pcm_runtime *runtime) +{ + struct snd_pcm_runtime *dst_runtime; + + if (dpcm == NULL || dpcm->substream == NULL) + return; + dst_runtime = dpcm->substream->runtime; + if (dst_runtime == NULL) + return; + dst_runtime->hw = dpcm->cable->hw; +} + +static void params_change(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + + cable->hw.formats = (1ULL << runtime->format); + cable->hw.rate_min = runtime->rate; + cable->hw.rate_max = runtime->rate; + cable->hw.channels_min = runtime->channels; + cable->hw.channels_max = runtime->channels; + params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], + runtime); + params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], + runtime); +} + static int loopback_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - unsigned int bps, salign; + int bps, salign; salign = (snd_pcm_format_width(runtime->format) * runtime->channels) / 8; @@ -303,13 +333,10 @@ static int loopback_prepare(struct snd_pcm_substream *substream) dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); mutex_lock(&dpcm->loopback->cable_lock); - if (!(cable->valid & ~(1 << substream->stream))) { - cable->hw.formats = (1ULL << runtime->format); - cable->hw.rate_min = runtime->rate; - cable->hw.rate_max = runtime->rate; - cable->hw.channels_min = runtime->channels; - cable->hw.channels_max = runtime->channels; - } + if (!(cable->valid & ~(1 << substream->stream)) || + (get_setup(dpcm)->notify && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) + params_change(substream); cable->valid |= 1 << substream->stream; mutex_unlock(&dpcm->loopback->cable_lock); @@ -542,6 +569,47 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream) return !substream->stream; } +static int rule_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + + struct snd_pcm_hardware *hw = rule->private; + struct snd_mask *maskp = hw_param_mask(params, rule->var); + + maskp->bits[0] &= (u_int32_t)hw->formats; + maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); + memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ + if (! maskp->bits[0] && ! maskp->bits[1]) + return -EINVAL; + return 0; +} + +static int rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_pcm_hardware *hw = rule->private; + struct snd_interval t; + + t.min = hw->rate_min; + t.max = hw->rate_max; + t.openmin = t.openmax = 0; + t.integer = 0; + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + +static int rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_pcm_hardware *hw = rule->private; + struct snd_interval t; + + t.min = hw->channels_min; + t.max = hw->channels_max; + t.openmin = t.openmax = 0; + t.integer = 0; + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + static int loopback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -579,14 +647,34 @@ static int loopback_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + /* use dynamic rules based on actual runtime->hw values */ + /* note that the default rules created in the PCM midlevel code */ + /* are cached -> they do not reflect the actual state */ + err = snd_pcm_hw_rule_add(runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + rule_format, &runtime->hw, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (err < 0) + goto unlock; + err = snd_pcm_hw_rule_add(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + rule_rate, &runtime->hw, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto unlock; + err = snd_pcm_hw_rule_add(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + rule_channels, &runtime->hw, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + goto unlock; + runtime->private_data = dpcm; runtime->private_free = loopback_runtime_free; - if (get_notify(dpcm) && - substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (get_notify(dpcm)) runtime->hw = loopback_pcm_hardware; - } else { + else runtime->hw = cable->hw; - } unlock: mutex_unlock(&loopback->cable_lock); return err; -- cgit v0.10.2 From 838c364ff05c143fd1810e8ad1469935d6c23a7a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 8 Oct 2010 10:48:50 +0200 Subject: ALSA: OSS mixer emulation - fix locking Fix mutex release and cleanup some locking code. Cc: Signed-off-by: Jaroslav Kysela diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf2..8442a08 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + up_read(&card->controls_rwsem); return; + } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) @@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, return; down_read(&card->controls_rwsem); if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { - up_read(&fmixer->card->controls_rwsem); + up_read(&card->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; - goto __unlock; + goto __free_only; } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = 0; __unlock: up_read(&card->controls_rwsem); + __free_only: kfree(uctl); kfree(uinfo); return err; @@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; - goto __unlock; + goto __free_only; } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = 0; __unlock: up_read(&card->controls_rwsem); + __free_only: kfree(uctl); kfree(uinfo); return err; -- cgit v0.10.2 From b7d22ccf08d67d13f77a9580d07e7f72e6241213 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 10 Oct 2010 19:34:22 +0200 Subject: OSS: soundcard: fix return value of sound_open() Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index a5ab61e..46c0d03 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -249,7 +249,7 @@ static int sound_open(struct inode *inode, struct file *file) } mutex_unlock(&soundcard_mutex); - return 0; + return retval; } static int sound_release(struct inode *inode, struct file *file) -- cgit v0.10.2 From 1d2019fb6be2f318f0aa85be5f224f47a5f006fe Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Tue, 5 Oct 2010 17:38:12 +0200 Subject: ALSA: sound/usb/usx2y: simplify conditional Simplify conditional: (a || (!a && b)) => (a || b) Signed-off-by: Nicolas Kaiser Signed-off-by: Takashi Iwai diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 2a528e5..3146a81 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -54,7 +54,7 @@ #include #include "usbusx2yaudio.c" -#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1) +#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1 #include -- cgit v0.10.2 From 0db710230589b5571c23f59250eabc9504b17c98 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 14 Oct 2010 21:46:12 +0200 Subject: ALSA: snd-aloop - fix issue in the timer start function In some circumstances (the rate shift value was changed), the irq_pos value may be higher than the fraction value in the timer start function. Check for it. Also, to avoid value overflow, decrease maximum period size. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 3c00882..838ad86 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -171,6 +171,10 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) dpcm->pcm_rate_shift = rate_shift; dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); } + if (dpcm->period_size_frac <= dpcm->irq_pos) { + dpcm->irq_pos %= dpcm->period_size_frac; + dpcm->period_update_pending = 1; + } tick = dpcm->period_size_frac - dpcm->irq_pos; tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; dpcm->timer.expires = jiffies + tick; @@ -531,7 +535,9 @@ static struct snd_pcm_hardware loopback_pcm_hardware = .channels_max = 32, .buffer_bytes_max = 2 * 1024 * 1024, .period_bytes_min = 64, - .period_bytes_max = 2 * 1024 * 1024, + /* note check overflow in frac_pos() using pcm_rate_shift before + changing period_bytes_max value */ + .period_bytes_max = 1024 * 1024, .periods_min = 1, .periods_max = 1024, .fifo_size = 0, -- cgit v0.10.2 From fa2eb005ebcbac89745a1f9a9f0c8678ba63f61a Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 16 Oct 2010 15:19:20 +0200 Subject: sound: fixed typos Signed-off-by: Andrea Gelmini Signed-off-by: Takashi Iwai diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index c92f493..557c782 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c @@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex) if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) return err; memset(&ac97, 0, sizeof(ac97)); - // Intialize AC97 codec stuff. + // Initialize AC97 codec stuff. ac97.private_data = vortex; ac97.scaps = AC97_SCAP_NO_SPDIF; err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 40eccfe..4948a79 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -150,7 +150,7 @@ static int __init sffsdr_init(void) sffsdr_snd_resources, ARRAY_SIZE(sffsdr_snd_resources)); if (ret) { - printk(KERN_ERR "platform device add ressources failed\n"); + printk(KERN_ERR "platform device add resources failed\n"); goto error; } diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 209c259..4719558 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -182,7 +182,7 @@ static int neo1973_gta02_voice_hw_params( if (ret < 0) return ret; - /* configue and enable PLL for 12.288MHz output */ + /* configure and enable PLL for 12.288MHz output */ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 0cb4f86..4ac6209 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -201,7 +201,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - /* configue and enable PLL for 12.288MHz output */ + /* configure and enable PLL for 12.288MHz output */ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 3146a81..287ef73 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -36,9 +36,9 @@ plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the cost of easier triggered i.e. aeolus xruns (128 or 256frames, 2periods works but is useless cause of crackling). - + This is a first "proof of concept" implementation. - Later, funcionalities should migrate to more apropriate places: + Later, functionalities should migrate to more apropriate places: Userland: - The jackd could mmap its float-pcm buffers directly from alsa-lib. - alsa-lib could provide power of 2 period sized shaping combined with int/float -- cgit v0.10.2 From 363129ea90e0835b8552b797714cd200f674e287 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 16 Oct 2010 13:24:52 -0400 Subject: ALSA: fix unused warnings with snd_power_get_state If we compile the ASoC code with PM disabled, we hit stuff like: sound/soc/soc-dapm.c: In function 'snd_soc_dapm_suspend_check': sound/soc/soc-dapm.c:440: warning: unused variable 'codec' So tweak the stub macro to avoid these issues. Signed-off-by: Mike Frysinger Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index 89e0ac1..c129f08 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -179,7 +179,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state); #define snd_power_lock(card) do { (void)(card); } while (0) #define snd_power_unlock(card) do { (void)(card); } while (0) static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } -#define snd_power_get_state(card) SNDRV_CTL_POWER_D0 +#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; }) #define snd_power_change_state(card, state) do { (void)(card); } while (0) #endif /* CONFIG_PM */ -- cgit v0.10.2 From 83fc3bc09518d42e8f5073e2a65884701dfadf19 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 18 Oct 2010 12:20:39 +0900 Subject: ALSA: emu10k1: Fix warning: "CCR" redefined CCR is defined in emu10k1, but SuperH is defined too. If user use this driver with SuperH, it becomes a double definition. Signed-off-by: Nobuhiro Iwamatsu Cc: Paul Mundt Signed-off-by: Takashi Iwai diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 7dc97d1..4f865df 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -438,6 +438,8 @@ #define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ #define CCCA_CURRADDR 0x18000008 +/* undefine CCR to avoid conflict with the definition for SH */ +#undef CCR #define CCR 0x09 /* Cache control register */ #define CCR_CACHEINVALIDSIZE 0x07190009 #define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ -- cgit v0.10.2 From e74670b6fdc37b15ebee11825849d8983e52a74a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 18 Oct 2010 09:43:10 +0200 Subject: ALSA: snd-aloop: add cable#0 and cable#1 files to proc card tree Show some useful runtime information using procfs. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 838ad86..66786ea 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -39,6 +39,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jaroslav Kysela "); @@ -184,6 +185,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) static inline void loopback_timer_stop(struct loopback_pcm *dpcm) { del_timer(&dpcm->timer); + dpcm->timer.expires = 0; } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -1011,6 +1013,86 @@ static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) return 0; } +#ifdef CONFIG_PROC_FS + +static void print_dpcm_info(struct snd_info_buffer *buffer, + struct loopback_pcm *dpcm, + const char *id) +{ + snd_iprintf(buffer, " %s\n", id); + if (dpcm == NULL) { + snd_iprintf(buffer, " inactive\n"); + return; + } + snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size); + snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos); + snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size); + snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size); + snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); + snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); + snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); + snd_iprintf(buffer, " update_pending:\t%u\n", + dpcm->period_update_pending); + snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); + snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); + snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", + dpcm->last_jiffies, jiffies); + snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); +} + +static void print_substream_info(struct snd_info_buffer *buffer, + struct loopback *loopback, + int sub, + int num) +{ + struct loopback_cable *cable = loopback->cables[sub][num]; + + snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub); + if (cable == NULL) { + snd_iprintf(buffer, " inactive\n"); + return; + } + snd_iprintf(buffer, " valid: %u\n", cable->valid); + snd_iprintf(buffer, " running: %u\n", cable->running); + print_dpcm_info(buffer, cable->streams[0], "Playback"); + print_dpcm_info(buffer, cable->streams[1], "Capture"); +} + +static void print_cable_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct loopback *loopback = entry->private_data; + int sub, num; + + mutex_lock(&loopback->cable_lock); + num = entry->name[strlen(entry->name)-1]; + num = num == '0' ? 0 : 1; + for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) + print_substream_info(buffer, loopback, sub, num); + mutex_unlock(&loopback->cable_lock); +} + +static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) +{ + char name[32]; + struct snd_info_entry *entry; + int err; + + snprintf(name, sizeof(name), "cable#%d", cidx); + err = snd_card_proc_new(loopback->card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, loopback, print_cable_info); + return 0; +} + +#else /* !CONFIG_PROC_FS */ + +#define loopback_proc_new(loopback, cidx) do { } while (0) + +#endif + static int __devinit loopback_probe(struct platform_device *devptr) { struct snd_card *card; @@ -1041,6 +1123,8 @@ static int __devinit loopback_probe(struct platform_device *devptr) err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); if (err < 0) goto __nodev; + loopback_proc_new(loopback, 0); + loopback_proc_new(loopback, 1); strcpy(card->driver, "Loopback"); strcpy(card->shortname, "Loopback"); sprintf(card->longname, "Loopback %i", dev + 1); -- cgit v0.10.2 From dd04bb12d047a4d4461772093472a40dbe171e5f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Oct 2010 08:27:02 +0200 Subject: ALSA: snd-aloop - fix locking issues (running flag updates) On SMP machines, the cable->running update must be atomic, otherwise stream is not started correctly sometimes. Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 66786ea..38e8351 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -263,13 +263,17 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) return err; dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; - loopback_timer_start(dpcm); + spin_lock(&cable->lock); cable->running |= (1 << substream->stream); + spin_unlock(&cable->lock); + loopback_timer_start(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_STOP: + spin_lock(&cable->lock); cable->running &= ~(1 << substream->stream); + spin_unlock(&cable->lock); loopback_timer_stop(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -454,28 +458,30 @@ static void loopback_bytepos_update(struct loopback_pcm *dpcm, } } -static void loopback_pos_update(struct loopback_cable *cable) +static unsigned int loopback_pos_update(struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; struct loopback_pcm *dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; + unsigned int running; spin_lock(&cable->lock); - if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + running = cable->running; + if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; } - if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { delta_capt = jiffies - dpcm_capt->last_jiffies; dpcm_capt->last_jiffies += delta_capt; } if (delta_play == 0 && delta_capt == 0) { spin_unlock(&cable->lock); - return; + return running; } if (delta_play > delta_capt) { @@ -490,27 +496,27 @@ static void loopback_pos_update(struct loopback_cable *cable) if (delta_play == 0 && delta_capt == 0) { spin_unlock(&cable->lock); - return; + return running; } /* note delta_capt == delta_play at this moment */ loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); spin_unlock(&cable->lock); + return running; } static void loopback_timer_function(unsigned long data) { struct loopback_pcm *dpcm = (struct loopback_pcm *)data; - int stream; + unsigned int running; - loopback_pos_update(dpcm->cable); - stream = dpcm->substream->stream; - if (dpcm->cable->running & (1 << stream)) + running = loopback_pos_update(dpcm->cable); + if (running & (1 << dpcm->substream->stream)) { loopback_timer_start(dpcm); - if (dpcm->period_update_pending) { - dpcm->period_update_pending = 0; - if (dpcm->cable->running & (1 << stream)) + if (dpcm->period_update_pending) { + dpcm->period_update_pending = 0; snd_pcm_period_elapsed(dpcm->substream); + } } } -- cgit v0.10.2 From 5de9e45fcfccdf8151a82fc1a521e7042cbe482a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Oct 2010 09:33:03 +0200 Subject: ALSA: snd-aloop - add pause support Signed-off-by: Jaroslav Kysela diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 38e8351..12b44b0 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -77,6 +77,7 @@ struct loopback_cable { /* flags */ unsigned int valid; unsigned int running; + unsigned int pause; }; struct loopback_setup { @@ -254,7 +255,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - int err; + int err, stream = 1 << substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -264,7 +265,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; spin_lock(&cable->lock); - cable->running |= (1 << substream->stream); + cable->running |= stream; + cable->pause &= ~stream; spin_unlock(&cable->lock); loopback_timer_start(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -272,12 +274,26 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: spin_lock(&cable->lock); - cable->running &= ~(1 << substream->stream); + cable->running &= ~stream; + cable->pause &= ~stream; spin_unlock(&cable->lock); loopback_timer_stop(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock(&cable->lock); + cable->pause |= stream; + spin_unlock(&cable->lock); + loopback_timer_stop(dpcm); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock(&cable->lock); + dpcm->last_jiffies = jiffies; + cable->pause &= ~stream; + spin_unlock(&cable->lock); + loopback_timer_start(dpcm); + break; default: return -EINVAL; } @@ -468,7 +484,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) unsigned int running; spin_lock(&cable->lock); - running = cable->running; + running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; @@ -532,7 +548,7 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_hardware loopback_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), @@ -1060,6 +1076,7 @@ static void print_substream_info(struct snd_info_buffer *buffer, } snd_iprintf(buffer, " valid: %u\n", cable->valid); snd_iprintf(buffer, " running: %u\n", cable->running); + snd_iprintf(buffer, " pause: %u\n", cable->pause); print_dpcm_info(buffer, cable->streams[0], "Playback"); print_dpcm_info(buffer, cable->streams[1], "Capture"); } -- cgit v0.10.2 From c7f572168fc4840727c9bda955b7f103922209cd Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Oct 2010 18:20:48 +0200 Subject: ALSA: usb-audio: add Novation Launchpad support Add a quirk entry for the Novation Launchpad USB MIDI controller. QUIRK_MIDI_FASTLANE gets renamed to *_RAW_BYTES because this quirk type is now shared by different devices. Signed-off-by: Clemens Ladisch Tested-by: Jakob Flierl Signed-off-by: Takashi Iwai diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 156cd07..25bce7e 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = { }; /* - * "raw" protocol: used by the MOTU FastLane. + * "raw" protocol: just move raw MIDI bytes from/to the endpoint */ static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, @@ -2122,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card, umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; - case QUIRK_MIDI_FASTLANE: + case QUIRK_MIDI_RAW_BYTES: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; /* * Interface 1 contains isochronous endpoints, but with the same @@ -2133,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card, * interface 0, so we have to make sure that the USB core looks * again at interface 0 by calling usb_set_interface() on it. */ - usb_set_interface(umidi->dev, 0, 0); + if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */ + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 682e3e0..ad7079d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2078,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = & (const struct snd_usb_audio_quirk[]) { { .ifnum = 0, - .type = QUIRK_MIDI_FASTLANE + .type = QUIRK_MIDI_RAW_BYTES }, { .ifnum = 1, @@ -2227,6 +2227,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + USB_DEVICE(0x1235, 0x000e), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Novation", */ + /* .product_name = "Launchpad", */ + .ifnum = 0, + .type = QUIRK_MIDI_RAW_BYTES + } +}, +{ USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "Novation", diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9a9da09..cf8bf08 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, - [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 24d3319..db3eb21 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -70,7 +70,7 @@ enum quirk_type { QUIRK_MIDI_YAMAHA, QUIRK_MIDI_MIDIMAN, QUIRK_MIDI_NOVATION, - QUIRK_MIDI_FASTLANE, + QUIRK_MIDI_RAW_BYTES, QUIRK_MIDI_EMAGIC, QUIRK_MIDI_CME, QUIRK_MIDI_AKAI, -- cgit v0.10.2 From 23156e8faed5df60364976bffea0711a4f38d88a Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:28 +1100 Subject: ALSA: ca0106 - add Sound Blaster 5.1vx info. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 8e69620..6dc9a5d 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -239,6 +239,16 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .gpio_type = 1, .i2c_adc = 1, .spi_dac = 1 } , + /* Sound Blaster 5.1vx + * Tested: Playback on front, rear, center/lfe speakers + * Not-Tested: Capture + */ + { .serial = 0x10041102, + .name = "Sound Blaster 5.1vx [SB1070]", + .gpio_type = 1, + .i2c_adc = 0, + .spi_dac = 1 + } , /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ /* SB0438 * CTRL:CA0106-DAT -- cgit v0.10.2 From 51630142ed7da31618c0aca8f2767824834e18a8 Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:29 +1100 Subject: ALSA: ca0106: Pull out dac powering routine into separate function. This is ground work for a future commit where cards (such as the Sound Blaster 5.1vx) have different mappings between dacs and channels. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 6dc9a5d..22d2f6b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -514,6 +514,23 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) } } +static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, + int power) +{ + if (chip->details->spi_dac) { + const int reg = spi_dacd_reg[channel_id]; + + if (power) + /* Power up */ + chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; + else + /* Power down */ + chip->spi_dac_reg[reg] |= spi_dacd_bit[channel_id]; + return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + } + return 0; +} + /* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) @@ -553,12 +570,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr return err; snd_pcm_set_sync(substream); - if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { - const int reg = spi_dacd_reg[channel_id]; - - /* Power up dac */ - chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; - err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + /* Front channel dac should already be on */ + if (channel_id != PCM_FRONT_CHANNEL) { + err = snd_ca0106_pcm_power_dac(chip, channel_id, 1); if (err < 0) return err; } @@ -578,13 +592,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) restore_spdif_bits(chip, epcm->channel_id); - if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { - const int reg = spi_dacd_reg[epcm->channel_id]; - - /* Power down DAC */ - chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; - snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + /* Front channel dac should stay on */ + if (epcm->channel_id != PCM_FRONT_CHANNEL) { + int err; + err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0); + if (err < 0) + return err; } + /* FIXME: maybe zero others */ return 0; } -- cgit v0.10.2 From 9bfd94132dd97b76af41024eb7e980a5cb41afee Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:30 +1100 Subject: ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 22d2f6b..46ae98d 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1385,7 +1385,7 @@ static unsigned int spi_dac_init[] = { SPI_REG(12, 0x00), SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), - SPI_REG(SPI_DACD4_REG, 0x00), + SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT), }; static unsigned int i2c_adc_init[][2] = { @@ -1576,6 +1576,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) if (reg < ARRAY_SIZE(chip->spi_dac_reg)) chip->spi_dac_reg[reg] = spi_dac_init[n]; } + + /* Enable front dac only */ + snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1); } } -- cgit v0.10.2 From 861391d3a037fab38020c741baffdb147e1c732a Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:31 +1100 Subject: ALSA: ca0106: Create a nice spot for mapping channels to dacs. This is to allow a future patch to have card specific mappings between dacs, which is required since the Sound Blaster 5.1vx seems to have a different mapping to what was previously used. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 46ae98d..da91003 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -493,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) } static const int spi_dacd_reg[] = { - [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, - [PCM_REAR_CHANNEL] = SPI_DACD0_REG, - [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, - [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, + SPI_DACD0_REG, + SPI_DACD1_REG, + SPI_DACD2_REG, + 0, + SPI_DACD4_REG, }; static const int spi_dacd_bit[] = { - [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, - [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, - [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, - [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, + SPI_DACD0_BIT, + SPI_DACD1_BIT, + SPI_DACD2_BIT, + 0, + SPI_DACD4_BIT, }; static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) @@ -514,18 +516,34 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) } } +static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, + int channel_id) +{ + switch (channel_id) { + case PCM_FRONT_CHANNEL: return 4; + case PCM_REAR_CHANNEL: return 0; + case PCM_CENTER_LFE_CHANNEL: return 2; + case PCM_UNKNOWN_CHANNEL: return 1; + } + snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", channel_id); + return 0; +} + static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, int power) { if (chip->details->spi_dac) { - const int reg = spi_dacd_reg[channel_id]; + const int dac = snd_ca0106_channel_dac(chip->details, + channel_id); + const int reg = spi_dacd_reg[dac]; + const int bit = spi_dacd_bit[dac]; if (power) /* Power up */ - chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; + chip->spi_dac_reg[reg] &= ~bit; else /* Power down */ - chip->spi_dac_reg[reg] |= spi_dacd_bit[channel_id]; + chip->spi_dac_reg[reg] |= bit; return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); } return 0; -- cgit v0.10.2 From 6fef153afa8b25f81417488150e04db7c6b0b229 Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:32 +1100 Subject: ALSA: ca0106: Allow different sound cards to use different SPI channel mappings. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 14b8d9a..f19c110 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -670,8 +670,9 @@ struct snd_ca0106_details { gpio_type = 2 -> shared side-out/line-in. */ int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume controls, phone, mic, line-in and aux. */ - int spi_dac; /* spi_dac=1 adds the mute switch for each analog - output, front, rear, etc. */ + u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs + spi_dac = 0x + -> specifies DAC id for each channel pair. */ }; // definition of the chip-specific record diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index da91003..d2d12c0 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "Audigy SE [SB0570]", .gpio_type = 1, .i2c_adc = 1, - .spi_dac = 1 } , + .spi_dac = 0x4021 } , /* New Audigy LS. Has a different DAC. */ /* SB0570: * CTRL:CA0106-DAT @@ -238,7 +238,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "Audigy SE OEM [SB0570a]", .gpio_type = 1, .i2c_adc = 1, - .spi_dac = 1 } , + .spi_dac = 0x4021 } , /* Sound Blaster 5.1vx * Tested: Playback on front, rear, center/lfe speakers * Not-Tested: Capture @@ -247,7 +247,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "Sound Blaster 5.1vx [SB1070]", .gpio_type = 1, .i2c_adc = 0, - .spi_dac = 1 + .spi_dac = 0x0124 } , /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ /* SB0438 @@ -264,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "MSI K8N Diamond MB", .gpio_type = 2, .i2c_adc = 1, - .spi_dac = 1 } , + .spi_dac = 0x4021 } , /* Giga-byte GA-G1975X mobo * Novell bnc#395807 */ @@ -520,12 +520,18 @@ static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, int channel_id) { switch (channel_id) { - case PCM_FRONT_CHANNEL: return 4; - case PCM_REAR_CHANNEL: return 0; - case PCM_CENTER_LFE_CHANNEL: return 2; - case PCM_UNKNOWN_CHANNEL: return 1; + case PCM_FRONT_CHANNEL: + return (details->spi_dac & 0xf000) >> (4 * 3); + case PCM_REAR_CHANNEL: + return (details->spi_dac & 0x0f00) >> (4 * 2); + case PCM_CENTER_LFE_CHANNEL: + return (details->spi_dac & 0x00f0) >> (4 * 1); + case PCM_UNKNOWN_CHANNEL: + return (details->spi_dac & 0x000f) >> (4 * 0); + default: + snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", + channel_id); } - snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", channel_id); return 0; } @@ -1582,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ } - if (chip->details->spi_dac == 1) { + if (chip->details->spi_dac) { /* The SB0570 use SPI to control DAC. */ int size, n; diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 85fd315..b522401 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -832,7 +832,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) if (err < 0) return err; } - if (emu->details->spi_dac == 1) + if (emu->details->spi_dac) ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); /* Create virtual master controls */ @@ -845,7 +845,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return err; add_slaves(card, vmaster, slave_vols); - if (emu->details->spi_dac == 1) { + if (emu->details->spi_dac) { vmaster = snd_ctl_make_virtual_master("Master Playback Switch", NULL); if (!vmaster) -- cgit v0.10.2 From 64e5310a249ba641ab6a00c6c1d61146d51b7984 Mon Sep 17 00:00:00 2001 From: Andy Owen Date: Sat, 23 Oct 2010 22:12:33 +1100 Subject: ALSA: ca0106: Use card specific dac id for mute controls. Signed-off-by: Andy Owen Signed-off-by: Takashi Iwai diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index b522401..630aa49 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = I2C_VOLUME("Aux Capture Volume", 3), }; -#define SPI_SWITCH(xname,reg,bit) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = spi_mute_info, \ - .get = spi_mute_get, \ - .put = spi_mute_put, \ - .private_value = (reg<spi_dac & 0xf000) >> (4 * 3); + break; + case PCM_REAR_CHANNEL: + spi_switch.name = "Analog Rear Playback Switch"; + dac_id = (details->spi_dac & 0x0f00) >> (4 * 2); + break; + case PCM_CENTER_LFE_CHANNEL: + spi_switch.name = "Analog Center/LFE Playback Switch"; + dac_id = (details->spi_dac & 0x00f0) >> (4 * 1); + break; + case PCM_UNKNOWN_CHANNEL: + spi_switch.name = "Analog Side Playback Switch"; + dac_id = (details->spi_dac & 0x000f) >> (4 * 0); + break; + default: + /* Unused channel */ + spi_switch.name = NULL; + dac_id = 0; + } + reg = spi_dmute_reg[dac_id]; + bit = spi_dmute_bit[dac_id]; + + spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit; + + return spi_switch; +} + static int __devinit remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; @@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) if (err < 0) return err; } - if (emu->details->spi_dac) - ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); + if (emu->details->spi_dac) { + int i; + for (i = 0;; i++) { + struct snd_kcontrol_new ctl; + ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i); + if (!ctl.name) + break; + err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu)); + if (err < 0) + return err; + } + } /* Create virtual master controls */ vmaster = snd_ctl_make_virtual_master("Master Playback Volume", -- cgit v0.10.2 From 97c44b2dbd0060e2e6bd56236eb638ab02ec7f30 Mon Sep 17 00:00:00 2001 From: Mandar Joshi Date: Sun, 24 Oct 2010 04:07:00 +0000 Subject: ALSA: usb - Creative USB X-Fi volume knob support Adds an entry for Creative USB X-Fi to the rc_config array in mixer_quirks.c to allow use of volume knob on the device. The action of the volume knob is received by lirc when its using the alsa_usb driver. Signed-off-by: Mandar Joshi Signed-off-by: Takashi Iwai diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e7df1e5..7dae05d 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -60,6 +60,7 @@ static const struct rc_config { { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ + { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */ { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ }; -- cgit v0.10.2