162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Line 6 Linux USB driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <sound/core.h> 1162306a36Sopenharmony_ci#include <sound/control.h> 1262306a36Sopenharmony_ci#include <sound/pcm.h> 1362306a36Sopenharmony_ci#include <sound/pcm_params.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "capture.h" 1662306a36Sopenharmony_ci#include "driver.h" 1762306a36Sopenharmony_ci#include "playback.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* impulse response volume controls */ 2062306a36Sopenharmony_cistatic int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol, 2162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2462306a36Sopenharmony_ci uinfo->count = 1; 2562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 2662306a36Sopenharmony_ci uinfo->value.integer.max = 255; 2762306a36Sopenharmony_ci return 0; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol, 3162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = line6pcm->impulse_volume; 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, 4062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 4362306a36Sopenharmony_ci int value = ucontrol->value.integer.value[0]; 4462306a36Sopenharmony_ci int err; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (line6pcm->impulse_volume == value) 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci line6pcm->impulse_volume = value; 5062306a36Sopenharmony_ci if (value > 0) { 5162306a36Sopenharmony_ci err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE, true); 5262306a36Sopenharmony_ci if (err < 0) { 5362306a36Sopenharmony_ci line6pcm->impulse_volume = 0; 5462306a36Sopenharmony_ci return err; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci } else { 5762306a36Sopenharmony_ci line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci return 1; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* impulse response period controls */ 6362306a36Sopenharmony_cistatic int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol, 6462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6762306a36Sopenharmony_ci uinfo->count = 1; 6862306a36Sopenharmony_ci uinfo->value.integer.min = 0; 6962306a36Sopenharmony_ci uinfo->value.integer.max = 2000; 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol, 7462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = line6pcm->impulse_period; 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, 8362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 8662306a36Sopenharmony_ci int value = ucontrol->value.integer.value[0]; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (line6pcm->impulse_period == value) 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci line6pcm->impulse_period = value; 9262306a36Sopenharmony_ci return 1; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* 9662306a36Sopenharmony_ci Unlink all currently active URBs. 9762306a36Sopenharmony_ci*/ 9862306a36Sopenharmony_cistatic void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm, 9962306a36Sopenharmony_ci struct line6_pcm_stream *pcms) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int i; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci for (i = 0; i < line6pcm->line6->iso_buffers; i++) { 10462306a36Sopenharmony_ci if (test_bit(i, &pcms->active_urbs)) { 10562306a36Sopenharmony_ci if (!test_and_set_bit(i, &pcms->unlink_urbs)) 10662306a36Sopenharmony_ci usb_unlink_urb(pcms->urbs[i]); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci Wait until unlinking of all currently active URBs has been finished. 11362306a36Sopenharmony_ci*/ 11462306a36Sopenharmony_cistatic void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, 11562306a36Sopenharmony_ci struct line6_pcm_stream *pcms) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int timeout = HZ; 11862306a36Sopenharmony_ci int i; 11962306a36Sopenharmony_ci int alive; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci do { 12262306a36Sopenharmony_ci alive = 0; 12362306a36Sopenharmony_ci for (i = 0; i < line6pcm->line6->iso_buffers; i++) { 12462306a36Sopenharmony_ci if (test_bit(i, &pcms->active_urbs)) 12562306a36Sopenharmony_ci alive++; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci if (!alive) 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 13062306a36Sopenharmony_ci schedule_timeout(1); 13162306a36Sopenharmony_ci } while (--timeout > 0); 13262306a36Sopenharmony_ci if (alive) 13362306a36Sopenharmony_ci dev_err(line6pcm->line6->ifcdev, 13462306a36Sopenharmony_ci "timeout: still %d active urbs..\n", alive); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline struct line6_pcm_stream * 13862306a36Sopenharmony_ciget_stream(struct snd_line6_pcm *line6pcm, int direction) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? 14162306a36Sopenharmony_ci &line6pcm->out : &line6pcm->in; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* allocate a buffer if not opened yet; 14562306a36Sopenharmony_ci * call this in line6pcm.state_mutex 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistatic int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, 14862306a36Sopenharmony_ci struct line6_pcm_stream *pstr, int direction, int type) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci const int pkt_size = 15162306a36Sopenharmony_ci (direction == SNDRV_PCM_STREAM_PLAYBACK) ? 15262306a36Sopenharmony_ci line6pcm->max_packet_size_out : 15362306a36Sopenharmony_ci line6pcm->max_packet_size_in; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Invoked multiple times in a row so allocate once only */ 15662306a36Sopenharmony_ci if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { 15762306a36Sopenharmony_ci pstr->buffer = 15862306a36Sopenharmony_ci kmalloc(array3_size(line6pcm->line6->iso_buffers, 15962306a36Sopenharmony_ci LINE6_ISO_PACKETS, pkt_size), 16062306a36Sopenharmony_ci GFP_KERNEL); 16162306a36Sopenharmony_ci if (!pstr->buffer) 16262306a36Sopenharmony_ci return -ENOMEM; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* free a buffer if all streams are closed; 16862306a36Sopenharmony_ci * call this in line6pcm.state_mutex 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic void line6_buffer_release(struct snd_line6_pcm *line6pcm, 17162306a36Sopenharmony_ci struct line6_pcm_stream *pstr, int type) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci clear_bit(type, &pstr->opened); 17462306a36Sopenharmony_ci if (!pstr->opened) { 17562306a36Sopenharmony_ci line6_wait_clear_audio_urbs(line6pcm, pstr); 17662306a36Sopenharmony_ci kfree(pstr->buffer); 17762306a36Sopenharmony_ci pstr->buffer = NULL; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* start a PCM stream */ 18262306a36Sopenharmony_cistatic int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, 18362306a36Sopenharmony_ci int type) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci unsigned long flags; 18662306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); 18762306a36Sopenharmony_ci int ret = 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci spin_lock_irqsave(&pstr->lock, flags); 19062306a36Sopenharmony_ci if (!test_and_set_bit(type, &pstr->running) && 19162306a36Sopenharmony_ci !(pstr->active_urbs || pstr->unlink_urbs)) { 19262306a36Sopenharmony_ci pstr->count = 0; 19362306a36Sopenharmony_ci /* Submit all currently available URBs */ 19462306a36Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) 19562306a36Sopenharmony_ci ret = line6_submit_audio_out_all_urbs(line6pcm); 19662306a36Sopenharmony_ci else 19762306a36Sopenharmony_ci ret = line6_submit_audio_in_all_urbs(line6pcm); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (ret < 0) 20162306a36Sopenharmony_ci clear_bit(type, &pstr->running); 20262306a36Sopenharmony_ci spin_unlock_irqrestore(&pstr->lock, flags); 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* stop a PCM stream; this doesn't sync with the unlinked URBs */ 20762306a36Sopenharmony_cistatic void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, 20862306a36Sopenharmony_ci int type) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci unsigned long flags; 21162306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci spin_lock_irqsave(&pstr->lock, flags); 21462306a36Sopenharmony_ci clear_bit(type, &pstr->running); 21562306a36Sopenharmony_ci if (!pstr->running) { 21662306a36Sopenharmony_ci spin_unlock_irqrestore(&pstr->lock, flags); 21762306a36Sopenharmony_ci line6_unlink_audio_urbs(line6pcm, pstr); 21862306a36Sopenharmony_ci spin_lock_irqsave(&pstr->lock, flags); 21962306a36Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_CAPTURE) { 22062306a36Sopenharmony_ci line6pcm->prev_fbuf = NULL; 22162306a36Sopenharmony_ci line6pcm->prev_fsize = 0; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci spin_unlock_irqrestore(&pstr->lock, flags); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* common PCM trigger callback */ 22862306a36Sopenharmony_ciint snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 23162306a36Sopenharmony_ci struct snd_pcm_substream *s; 23262306a36Sopenharmony_ci int err; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 23762306a36Sopenharmony_ci if (s->pcm->card != substream->pcm->card) 23862306a36Sopenharmony_ci continue; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci switch (cmd) { 24162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 24262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 24362306a36Sopenharmony_ci if (s->stream == SNDRV_PCM_STREAM_CAPTURE && 24462306a36Sopenharmony_ci (line6pcm->line6->properties->capabilities & 24562306a36Sopenharmony_ci LINE6_CAP_IN_NEEDS_OUT)) { 24662306a36Sopenharmony_ci err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK, 24762306a36Sopenharmony_ci LINE6_STREAM_CAPTURE_HELPER); 24862306a36Sopenharmony_ci if (err < 0) 24962306a36Sopenharmony_ci return err; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci err = line6_stream_start(line6pcm, s->stream, 25262306a36Sopenharmony_ci LINE6_STREAM_PCM); 25362306a36Sopenharmony_ci if (err < 0) 25462306a36Sopenharmony_ci return err; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 25862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 25962306a36Sopenharmony_ci if (s->stream == SNDRV_PCM_STREAM_CAPTURE && 26062306a36Sopenharmony_ci (line6pcm->line6->properties->capabilities & 26162306a36Sopenharmony_ci LINE6_CAP_IN_NEEDS_OUT)) { 26262306a36Sopenharmony_ci line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK, 26362306a36Sopenharmony_ci LINE6_STREAM_CAPTURE_HELPER); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci line6_stream_stop(line6pcm, s->stream, 26662306a36Sopenharmony_ci LINE6_STREAM_PCM); 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 27062306a36Sopenharmony_ci if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 27662306a36Sopenharmony_ci if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci default: 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* common PCM pointer callback */ 29062306a36Sopenharmony_cisnd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 29362306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return pstr->pos_done; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* Acquire and optionally start duplex streams: 29962306a36Sopenharmony_ci * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ciint line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct line6_pcm_stream *pstr; 30462306a36Sopenharmony_ci int ret = 0, dir; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */ 30762306a36Sopenharmony_ci mutex_lock(&line6pcm->state_mutex); 30862306a36Sopenharmony_ci for (dir = 0; dir < 2; dir++) { 30962306a36Sopenharmony_ci pstr = get_stream(line6pcm, dir); 31062306a36Sopenharmony_ci ret = line6_buffer_acquire(line6pcm, pstr, dir, type); 31162306a36Sopenharmony_ci if (ret < 0) 31262306a36Sopenharmony_ci goto error; 31362306a36Sopenharmony_ci if (!pstr->running) 31462306a36Sopenharmony_ci line6_wait_clear_audio_urbs(line6pcm, pstr); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci if (start) { 31762306a36Sopenharmony_ci for (dir = 0; dir < 2; dir++) { 31862306a36Sopenharmony_ci ret = line6_stream_start(line6pcm, dir, type); 31962306a36Sopenharmony_ci if (ret < 0) 32062306a36Sopenharmony_ci goto error; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci error: 32462306a36Sopenharmony_ci mutex_unlock(&line6pcm->state_mutex); 32562306a36Sopenharmony_ci if (ret < 0) 32662306a36Sopenharmony_ci line6_pcm_release(line6pcm, type); 32762306a36Sopenharmony_ci return ret; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_pcm_acquire); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* Stop and release duplex streams */ 33262306a36Sopenharmony_civoid line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct line6_pcm_stream *pstr; 33562306a36Sopenharmony_ci int dir; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci mutex_lock(&line6pcm->state_mutex); 33862306a36Sopenharmony_ci for (dir = 0; dir < 2; dir++) 33962306a36Sopenharmony_ci line6_stream_stop(line6pcm, dir, type); 34062306a36Sopenharmony_ci for (dir = 0; dir < 2; dir++) { 34162306a36Sopenharmony_ci pstr = get_stream(line6pcm, dir); 34262306a36Sopenharmony_ci line6_buffer_release(line6pcm, pstr, type); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci mutex_unlock(&line6pcm->state_mutex); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_pcm_release); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* common PCM hw_params callback */ 34962306a36Sopenharmony_ciint snd_line6_hw_params(struct snd_pcm_substream *substream, 35062306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci int ret; 35362306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 35462306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci mutex_lock(&line6pcm->state_mutex); 35762306a36Sopenharmony_ci ret = line6_buffer_acquire(line6pcm, pstr, substream->stream, 35862306a36Sopenharmony_ci LINE6_STREAM_PCM); 35962306a36Sopenharmony_ci if (ret < 0) 36062306a36Sopenharmony_ci goto error; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci pstr->period = params_period_bytes(hw_params); 36362306a36Sopenharmony_ci error: 36462306a36Sopenharmony_ci mutex_unlock(&line6pcm->state_mutex); 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/* common PCM hw_free callback */ 36962306a36Sopenharmony_ciint snd_line6_hw_free(struct snd_pcm_substream *substream) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 37262306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci mutex_lock(&line6pcm->state_mutex); 37562306a36Sopenharmony_ci line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); 37662306a36Sopenharmony_ci mutex_unlock(&line6pcm->state_mutex); 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* control info callback */ 38262306a36Sopenharmony_cistatic int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, 38362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 38662306a36Sopenharmony_ci uinfo->count = 2; 38762306a36Sopenharmony_ci uinfo->value.integer.min = 0; 38862306a36Sopenharmony_ci uinfo->value.integer.max = 256; 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/* control get callback */ 39362306a36Sopenharmony_cistatic int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, 39462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci int i; 39762306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci for (i = 0; i < 2; i++) 40062306a36Sopenharmony_ci ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* control put callback */ 40662306a36Sopenharmony_cistatic int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, 40762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci int i, changed = 0; 41062306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (i = 0; i < 2; i++) 41362306a36Sopenharmony_ci if (line6pcm->volume_playback[i] != 41462306a36Sopenharmony_ci ucontrol->value.integer.value[i]) { 41562306a36Sopenharmony_ci line6pcm->volume_playback[i] = 41662306a36Sopenharmony_ci ucontrol->value.integer.value[i]; 41762306a36Sopenharmony_ci changed = 1; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return changed; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* control definition */ 42462306a36Sopenharmony_cistatic const struct snd_kcontrol_new line6_controls[] = { 42562306a36Sopenharmony_ci { 42662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 42762306a36Sopenharmony_ci .name = "PCM Playback Volume", 42862306a36Sopenharmony_ci .info = snd_line6_control_playback_info, 42962306a36Sopenharmony_ci .get = snd_line6_control_playback_get, 43062306a36Sopenharmony_ci .put = snd_line6_control_playback_put 43162306a36Sopenharmony_ci }, 43262306a36Sopenharmony_ci { 43362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 43462306a36Sopenharmony_ci .name = "Impulse Response Volume", 43562306a36Sopenharmony_ci .info = snd_line6_impulse_volume_info, 43662306a36Sopenharmony_ci .get = snd_line6_impulse_volume_get, 43762306a36Sopenharmony_ci .put = snd_line6_impulse_volume_put 43862306a36Sopenharmony_ci }, 43962306a36Sopenharmony_ci { 44062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 44162306a36Sopenharmony_ci .name = "Impulse Response Period", 44262306a36Sopenharmony_ci .info = snd_line6_impulse_period_info, 44362306a36Sopenharmony_ci .get = snd_line6_impulse_period_get, 44462306a36Sopenharmony_ci .put = snd_line6_impulse_period_put 44562306a36Sopenharmony_ci }, 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* 44962306a36Sopenharmony_ci Cleanup the PCM device. 45062306a36Sopenharmony_ci*/ 45162306a36Sopenharmony_cistatic void cleanup_urbs(struct line6_pcm_stream *pcms, int iso_buffers) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci int i; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Most likely impossible in current code... */ 45662306a36Sopenharmony_ci if (pcms->urbs == NULL) 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci for (i = 0; i < iso_buffers; i++) { 46062306a36Sopenharmony_ci if (pcms->urbs[i]) { 46162306a36Sopenharmony_ci usb_kill_urb(pcms->urbs[i]); 46262306a36Sopenharmony_ci usb_free_urb(pcms->urbs[i]); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci kfree(pcms->urbs); 46662306a36Sopenharmony_ci pcms->urbs = NULL; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void line6_cleanup_pcm(struct snd_pcm *pcm) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci cleanup_urbs(&line6pcm->out, line6pcm->line6->iso_buffers); 47462306a36Sopenharmony_ci cleanup_urbs(&line6pcm->in, line6pcm->line6->iso_buffers); 47562306a36Sopenharmony_ci kfree(line6pcm); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* create a PCM device */ 47962306a36Sopenharmony_cistatic int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct snd_pcm *pcm; 48262306a36Sopenharmony_ci int err; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci err = snd_pcm_new(line6->card, (char *)line6->properties->name, 48562306a36Sopenharmony_ci 0, 1, 1, pcm_ret); 48662306a36Sopenharmony_ci if (err < 0) 48762306a36Sopenharmony_ci return err; 48862306a36Sopenharmony_ci pcm = *pcm_ret; 48962306a36Sopenharmony_ci strcpy(pcm->name, line6->properties->name); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* set operators */ 49262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 49362306a36Sopenharmony_ci &snd_line6_playback_ops); 49462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* pre-allocation of buffers */ 49762306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 49862306a36Sopenharmony_ci NULL, 64 * 1024, 128 * 1024); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* 50362306a36Sopenharmony_ci Sync with PCM stream stops. 50462306a36Sopenharmony_ci*/ 50562306a36Sopenharmony_civoid line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci line6_unlink_audio_urbs(line6pcm, &line6pcm->out); 50862306a36Sopenharmony_ci line6_unlink_audio_urbs(line6pcm, &line6pcm->in); 50962306a36Sopenharmony_ci line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); 51062306a36Sopenharmony_ci line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/* 51462306a36Sopenharmony_ci Create and register the PCM device and mixer entries. 51562306a36Sopenharmony_ci Create URBs for playback and capture. 51662306a36Sopenharmony_ci*/ 51762306a36Sopenharmony_ciint line6_init_pcm(struct usb_line6 *line6, 51862306a36Sopenharmony_ci struct line6_pcm_properties *properties) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci int i, err; 52162306a36Sopenharmony_ci unsigned ep_read = line6->properties->ep_audio_r; 52262306a36Sopenharmony_ci unsigned ep_write = line6->properties->ep_audio_w; 52362306a36Sopenharmony_ci struct snd_pcm *pcm; 52462306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (!(line6->properties->capabilities & LINE6_CAP_PCM)) 52762306a36Sopenharmony_ci return 0; /* skip PCM initialization and report success */ 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci err = snd_line6_new_pcm(line6, &pcm); 53062306a36Sopenharmony_ci if (err < 0) 53162306a36Sopenharmony_ci return err; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); 53462306a36Sopenharmony_ci if (!line6pcm) 53562306a36Sopenharmony_ci return -ENOMEM; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci mutex_init(&line6pcm->state_mutex); 53862306a36Sopenharmony_ci line6pcm->pcm = pcm; 53962306a36Sopenharmony_ci line6pcm->properties = properties; 54062306a36Sopenharmony_ci line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; 54162306a36Sopenharmony_ci line6pcm->volume_monitor = 255; 54262306a36Sopenharmony_ci line6pcm->line6 = line6; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci spin_lock_init(&line6pcm->out.lock); 54562306a36Sopenharmony_ci spin_lock_init(&line6pcm->in.lock); 54662306a36Sopenharmony_ci line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci line6->line6pcm = line6pcm; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci pcm->private_data = line6pcm; 55162306a36Sopenharmony_ci pcm->private_free = line6_cleanup_pcm; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci line6pcm->max_packet_size_in = 55462306a36Sopenharmony_ci usb_maxpacket(line6->usbdev, 55562306a36Sopenharmony_ci usb_rcvisocpipe(line6->usbdev, ep_read)); 55662306a36Sopenharmony_ci line6pcm->max_packet_size_out = 55762306a36Sopenharmony_ci usb_maxpacket(line6->usbdev, 55862306a36Sopenharmony_ci usb_sndisocpipe(line6->usbdev, ep_write)); 55962306a36Sopenharmony_ci if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) { 56062306a36Sopenharmony_ci dev_err(line6pcm->line6->ifcdev, 56162306a36Sopenharmony_ci "cannot get proper max packet size\n"); 56262306a36Sopenharmony_ci return -EINVAL; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci err = line6_create_audio_out_urbs(line6pcm); 56662306a36Sopenharmony_ci if (err < 0) 56762306a36Sopenharmony_ci return err; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci err = line6_create_audio_in_urbs(line6pcm); 57062306a36Sopenharmony_ci if (err < 0) 57162306a36Sopenharmony_ci return err; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* mixer: */ 57462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(line6_controls); i++) { 57562306a36Sopenharmony_ci err = snd_ctl_add(line6->card, 57662306a36Sopenharmony_ci snd_ctl_new1(&line6_controls[i], line6pcm)); 57762306a36Sopenharmony_ci if (err < 0) 57862306a36Sopenharmony_ci return err; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(line6_init_pcm); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/* prepare pcm callback */ 58662306a36Sopenharmony_ciint snd_line6_prepare(struct snd_pcm_substream *substream) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 58962306a36Sopenharmony_ci struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci mutex_lock(&line6pcm->state_mutex); 59262306a36Sopenharmony_ci if (!pstr->running) 59362306a36Sopenharmony_ci line6_wait_clear_audio_urbs(line6pcm, pstr); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { 59662306a36Sopenharmony_ci line6pcm->out.count = 0; 59762306a36Sopenharmony_ci line6pcm->out.pos = 0; 59862306a36Sopenharmony_ci line6pcm->out.pos_done = 0; 59962306a36Sopenharmony_ci line6pcm->out.bytes = 0; 60062306a36Sopenharmony_ci line6pcm->in.count = 0; 60162306a36Sopenharmony_ci line6pcm->in.pos_done = 0; 60262306a36Sopenharmony_ci line6pcm->in.bytes = 0; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci mutex_unlock(&line6pcm->state_mutex); 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 608