162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for Echoaudio soundcards. 462306a36Sopenharmony_ci * Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it> 562306a36Sopenharmony_ci * Copyright (C) 2020 Mark Hills <mark@xwax.org> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciMODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>"); 1162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1262306a36Sopenharmony_ciMODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver"); 1362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_echo_ids); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 1662306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 1762306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 2062306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard."); 2162306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 2262306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard."); 2362306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 2462306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; 2762306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int get_firmware(const struct firmware **fw_entry, 3262306a36Sopenharmony_ci struct echoaudio *chip, const short fw_index) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci int err; 3562306a36Sopenharmony_ci char name[30]; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3862306a36Sopenharmony_ci if (chip->fw_cache[fw_index]) { 3962306a36Sopenharmony_ci dev_dbg(chip->card->dev, 4062306a36Sopenharmony_ci "firmware requested: %s is cached\n", 4162306a36Sopenharmony_ci card_fw[fw_index].data); 4262306a36Sopenharmony_ci *fw_entry = chip->fw_cache[fw_index]; 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci#endif 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci dev_dbg(chip->card->dev, 4862306a36Sopenharmony_ci "firmware requested: %s\n", card_fw[fw_index].data); 4962306a36Sopenharmony_ci snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); 5062306a36Sopenharmony_ci err = request_firmware(fw_entry, name, &chip->pci->dev); 5162306a36Sopenharmony_ci if (err < 0) 5262306a36Sopenharmony_ci dev_err(chip->card->dev, 5362306a36Sopenharmony_ci "get_firmware(): Firmware not available (%d)\n", err); 5462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci chip->fw_cache[fw_index] = *fw_entry; 5762306a36Sopenharmony_ci#endif 5862306a36Sopenharmony_ci return err; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void free_firmware(const struct firmware *fw_entry, 6462306a36Sopenharmony_ci struct echoaudio *chip) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6762306a36Sopenharmony_ci dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n"); 6862306a36Sopenharmony_ci#else 6962306a36Sopenharmony_ci release_firmware(fw_entry); 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void free_firmware_cache(struct echoaudio *chip) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7862306a36Sopenharmony_ci int i; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (i = 0; i < 8 ; i++) 8162306a36Sopenharmony_ci if (chip->fw_cache[i]) { 8262306a36Sopenharmony_ci release_firmware(chip->fw_cache[i]); 8362306a36Sopenharmony_ci dev_dbg(chip->card->dev, "release_firmware(%d)\n", i); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#endif 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/****************************************************************************** 9262306a36Sopenharmony_ci PCM interface 9362306a36Sopenharmony_ci******************************************************************************/ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void audiopipe_free(struct snd_pcm_runtime *runtime) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct audiopipe *pipe = runtime->private_data; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (pipe->sgpage.area) 10062306a36Sopenharmony_ci snd_dma_free_pages(&pipe->sgpage); 10162306a36Sopenharmony_ci kfree(pipe); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, 10762306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 11062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 11162306a36Sopenharmony_ci struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 11262306a36Sopenharmony_ci struct snd_mask fmt; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci snd_mask_any(&fmt); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 11762306a36Sopenharmony_ci /* >=2 channels cannot be S32_BE */ 11862306a36Sopenharmony_ci if (c->min == 2) { 11962306a36Sopenharmony_ci fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE; 12062306a36Sopenharmony_ci return snd_mask_refine(f, &fmt); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci /* > 2 channels cannot be U8 and S32_BE */ 12462306a36Sopenharmony_ci if (c->min > 2) { 12562306a36Sopenharmony_ci fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE); 12662306a36Sopenharmony_ci return snd_mask_refine(f, &fmt); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci /* Mono is ok with any format */ 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, 13562306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 13862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 13962306a36Sopenharmony_ci struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 14062306a36Sopenharmony_ci struct snd_interval ch; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci snd_interval_any(&ch); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* S32_BE is mono (and stereo) only */ 14562306a36Sopenharmony_ci if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) { 14662306a36Sopenharmony_ci ch.min = 1; 14762306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 14862306a36Sopenharmony_ci ch.max = 2; 14962306a36Sopenharmony_ci#else 15062306a36Sopenharmony_ci ch.max = 1; 15162306a36Sopenharmony_ci#endif 15262306a36Sopenharmony_ci ch.integer = 1; 15362306a36Sopenharmony_ci return snd_interval_refine(c, &ch); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci /* U8 can be only mono or stereo */ 15662306a36Sopenharmony_ci if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) { 15762306a36Sopenharmony_ci ch.min = 1; 15862306a36Sopenharmony_ci ch.max = 2; 15962306a36Sopenharmony_ci ch.integer = 1; 16062306a36Sopenharmony_ci return snd_interval_refine(c, &ch); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci /* S16_LE, S24_3LE and S32_LE support any number of channels. */ 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, 16962306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 17262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 17362306a36Sopenharmony_ci struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 17462306a36Sopenharmony_ci struct snd_mask fmt; 17562306a36Sopenharmony_ci u64 fmask; 17662306a36Sopenharmony_ci snd_mask_any(&fmt); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* >2 channels must be S16_LE, S24_3LE or S32_LE */ 18162306a36Sopenharmony_ci if (c->min > 2) { 18262306a36Sopenharmony_ci fmask &= SNDRV_PCM_FMTBIT_S16_LE | 18362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | 18462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE; 18562306a36Sopenharmony_ci /* 1 channel must be S32_BE or S32_LE */ 18662306a36Sopenharmony_ci } else if (c->max == 1) 18762306a36Sopenharmony_ci fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE; 18862306a36Sopenharmony_ci#ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 18962306a36Sopenharmony_ci /* 2 channels cannot be S32_BE */ 19062306a36Sopenharmony_ci else if (c->min == 2 && c->max == 2) 19162306a36Sopenharmony_ci fmask &= ~SNDRV_PCM_FMTBIT_S32_BE; 19262306a36Sopenharmony_ci#endif 19362306a36Sopenharmony_ci else 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci fmt.bits[0] &= (u32)fmask; 19762306a36Sopenharmony_ci fmt.bits[1] &= (u32)(fmask >> 32); 19862306a36Sopenharmony_ci return snd_mask_refine(f, &fmt); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params, 20462306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct snd_interval *c = hw_param_interval(params, 20762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 20862306a36Sopenharmony_ci struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 20962306a36Sopenharmony_ci struct snd_interval ch; 21062306a36Sopenharmony_ci u64 fmask; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci snd_interval_any(&ch); 21362306a36Sopenharmony_ci ch.integer = 1; 21462306a36Sopenharmony_ci fmask = f->bits[0] + ((u64)f->bits[1] << 32); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* S32_BE is mono (and stereo) only */ 21762306a36Sopenharmony_ci if (fmask == SNDRV_PCM_FMTBIT_S32_BE) { 21862306a36Sopenharmony_ci ch.min = 1; 21962306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 22062306a36Sopenharmony_ci ch.max = 2; 22162306a36Sopenharmony_ci#else 22262306a36Sopenharmony_ci ch.max = 1; 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci /* U8 is stereo only */ 22562306a36Sopenharmony_ci } else if (fmask == SNDRV_PCM_FMTBIT_U8) 22662306a36Sopenharmony_ci ch.min = ch.max = 2; 22762306a36Sopenharmony_ci /* S16_LE and S24_3LE must be at least stereo */ 22862306a36Sopenharmony_ci else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE | 22962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE))) 23062306a36Sopenharmony_ci ch.min = 2; 23162306a36Sopenharmony_ci else 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return snd_interval_refine(c, &ch); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* Since the sample rate is a global setting, do allow the user to change the 24062306a36Sopenharmony_cisample rate only if there is only one pcm device open. */ 24162306a36Sopenharmony_cistatic int hw_rule_sample_rate(struct snd_pcm_hw_params *params, 24262306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct snd_interval *rate = hw_param_interval(params, 24562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 24662306a36Sopenharmony_ci struct echoaudio *chip = rule->private; 24762306a36Sopenharmony_ci struct snd_interval fixed; 24862306a36Sopenharmony_ci int err; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (chip->can_set_rate) { 25362306a36Sopenharmony_ci err = 0; 25462306a36Sopenharmony_ci } else { 25562306a36Sopenharmony_ci snd_interval_any(&fixed); 25662306a36Sopenharmony_ci fixed.min = fixed.max = chip->sample_rate; 25762306a36Sopenharmony_ci err = snd_interval_refine(rate, &fixed); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 26162306a36Sopenharmony_ci return err; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int pcm_open(struct snd_pcm_substream *substream, 26662306a36Sopenharmony_ci signed char max_channels) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct echoaudio *chip; 26962306a36Sopenharmony_ci struct snd_pcm_runtime *runtime; 27062306a36Sopenharmony_ci struct audiopipe *pipe; 27162306a36Sopenharmony_ci int err, i; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (max_channels <= 0) 27462306a36Sopenharmony_ci return -EAGAIN; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci chip = snd_pcm_substream_chip(substream); 27762306a36Sopenharmony_ci runtime = substream->runtime; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci pipe = kzalloc(sizeof(struct audiopipe), GFP_KERNEL); 28062306a36Sopenharmony_ci if (!pipe) 28162306a36Sopenharmony_ci return -ENOMEM; 28262306a36Sopenharmony_ci pipe->index = -1; /* Not configured yet */ 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Set up hw capabilities and contraints */ 28562306a36Sopenharmony_ci memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware)); 28662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "max_channels=%d\n", max_channels); 28762306a36Sopenharmony_ci pipe->constr.list = channels_list; 28862306a36Sopenharmony_ci pipe->constr.mask = 0; 28962306a36Sopenharmony_ci for (i = 0; channels_list[i] <= max_channels; i++); 29062306a36Sopenharmony_ci pipe->constr.count = i; 29162306a36Sopenharmony_ci if (pipe->hw.channels_max > max_channels) 29262306a36Sopenharmony_ci pipe->hw.channels_max = max_channels; 29362306a36Sopenharmony_ci if (chip->digital_mode == DIGITAL_MODE_ADAT) { 29462306a36Sopenharmony_ci pipe->hw.rate_max = 48000; 29562306a36Sopenharmony_ci pipe->hw.rates &= SNDRV_PCM_RATE_8000_48000; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci runtime->hw = pipe->hw; 29962306a36Sopenharmony_ci runtime->private_data = pipe; 30062306a36Sopenharmony_ci runtime->private_free = audiopipe_free; 30162306a36Sopenharmony_ci snd_pcm_set_sync(substream); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Only mono and any even number of channels are allowed */ 30462306a36Sopenharmony_ci err = snd_pcm_hw_constraint_list(runtime, 0, 30562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 30662306a36Sopenharmony_ci &pipe->constr); 30762306a36Sopenharmony_ci if (err < 0) 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* All periods should have the same size */ 31162306a36Sopenharmony_ci err = snd_pcm_hw_constraint_integer(runtime, 31262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 31362306a36Sopenharmony_ci if (err < 0) 31462306a36Sopenharmony_ci return err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* The hw accesses memory in chunks 32 frames long and they should be 31762306a36Sopenharmony_ci 32-bytes-aligned. It's not a requirement, but it seems that IRQs are 31862306a36Sopenharmony_ci generated with a resolution of 32 frames. Thus we need the following */ 31962306a36Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 32062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); 32162306a36Sopenharmony_ci if (err < 0) 32262306a36Sopenharmony_ci return err; 32362306a36Sopenharmony_ci err = snd_pcm_hw_constraint_step(runtime, 0, 32462306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); 32562306a36Sopenharmony_ci if (err < 0) 32662306a36Sopenharmony_ci return err; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 32962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 33062306a36Sopenharmony_ci hw_rule_sample_rate, chip, 33162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 33262306a36Sopenharmony_ci if (err < 0) 33362306a36Sopenharmony_ci return err; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Allocate a page for the scatter-gather list */ 33662306a36Sopenharmony_ci err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, 33762306a36Sopenharmony_ci &chip->pci->dev, 33862306a36Sopenharmony_ci PAGE_SIZE, &pipe->sgpage); 33962306a36Sopenharmony_ci if (err < 0) { 34062306a36Sopenharmony_ci dev_err(chip->card->dev, "s-g list allocation failed\n"); 34162306a36Sopenharmony_ci return err; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * Sole ownership required to set the rate 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d", 34962306a36Sopenharmony_ci chip->opencount, chip->can_set_rate, chip->rate_set); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci chip->opencount++; 35262306a36Sopenharmony_ci if (chip->opencount > 1 && chip->rate_set) 35362306a36Sopenharmony_ci chip->can_set_rate = 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int pcm_analog_in_open(struct snd_pcm_substream *substream) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 36362306a36Sopenharmony_ci int err; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci err = pcm_open(substream, 36662306a36Sopenharmony_ci num_analog_busses_in(chip) - substream->number); 36762306a36Sopenharmony_ci if (err < 0) 36862306a36Sopenharmony_ci return err; 36962306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 37062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 37162306a36Sopenharmony_ci hw_rule_capture_channels_by_format, NULL, 37262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 37362306a36Sopenharmony_ci if (err < 0) 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 37662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 37762306a36Sopenharmony_ci hw_rule_capture_format_by_channels, NULL, 37862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 37962306a36Sopenharmony_ci if (err < 0) 38062306a36Sopenharmony_ci return err; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int pcm_analog_out_open(struct snd_pcm_substream *substream) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 39062306a36Sopenharmony_ci int max_channels, err; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 39362306a36Sopenharmony_ci max_channels = num_pipes_out(chip); 39462306a36Sopenharmony_ci#else 39562306a36Sopenharmony_ci max_channels = num_analog_busses_out(chip); 39662306a36Sopenharmony_ci#endif 39762306a36Sopenharmony_ci err = pcm_open(substream, max_channels - substream->number); 39862306a36Sopenharmony_ci if (err < 0) 39962306a36Sopenharmony_ci return err; 40062306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 40162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 40262306a36Sopenharmony_ci hw_rule_playback_channels_by_format, 40362306a36Sopenharmony_ci NULL, 40462306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 40562306a36Sopenharmony_ci if (err < 0) 40662306a36Sopenharmony_ci return err; 40762306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 40862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 40962306a36Sopenharmony_ci hw_rule_playback_format_by_channels, 41062306a36Sopenharmony_ci NULL, 41162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 41262306a36Sopenharmony_ci if (err < 0) 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int pcm_digital_in_open(struct snd_pcm_substream *substream) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 42562306a36Sopenharmony_ci int err, max_channels; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci max_channels = num_digital_busses_in(chip) - substream->number; 42862306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 42962306a36Sopenharmony_ci if (chip->digital_mode == DIGITAL_MODE_ADAT) 43062306a36Sopenharmony_ci err = pcm_open(substream, max_channels); 43162306a36Sopenharmony_ci else /* If the card has ADAT, subtract the 6 channels 43262306a36Sopenharmony_ci * that S/PDIF doesn't have 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (err < 0) 43762306a36Sopenharmony_ci goto din_exit; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 44062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 44162306a36Sopenharmony_ci hw_rule_capture_channels_by_format, NULL, 44262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 44362306a36Sopenharmony_ci if (err < 0) 44462306a36Sopenharmony_ci goto din_exit; 44562306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 44662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 44762306a36Sopenharmony_ci hw_rule_capture_format_by_channels, NULL, 44862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 44962306a36Sopenharmony_ci if (err < 0) 45062306a36Sopenharmony_ci goto din_exit; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cidin_exit: 45362306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 45462306a36Sopenharmony_ci return err; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci#ifndef ECHOCARD_HAS_VMIXER /* See the note in snd_echo_new_pcm() */ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int pcm_digital_out_open(struct snd_pcm_substream *substream) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 46462306a36Sopenharmony_ci int err, max_channels; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci max_channels = num_digital_busses_out(chip) - substream->number; 46762306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 46862306a36Sopenharmony_ci if (chip->digital_mode == DIGITAL_MODE_ADAT) 46962306a36Sopenharmony_ci err = pcm_open(substream, max_channels); 47062306a36Sopenharmony_ci else /* If the card has ADAT, subtract the 6 channels 47162306a36Sopenharmony_ci * that S/PDIF doesn't have 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (err < 0) 47662306a36Sopenharmony_ci goto dout_exit; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 47962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 48062306a36Sopenharmony_ci hw_rule_playback_channels_by_format, 48162306a36Sopenharmony_ci NULL, SNDRV_PCM_HW_PARAM_FORMAT, 48262306a36Sopenharmony_ci -1); 48362306a36Sopenharmony_ci if (err < 0) 48462306a36Sopenharmony_ci goto dout_exit; 48562306a36Sopenharmony_ci err = snd_pcm_hw_rule_add(substream->runtime, 0, 48662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 48762306a36Sopenharmony_ci hw_rule_playback_format_by_channels, 48862306a36Sopenharmony_ci NULL, SNDRV_PCM_HW_PARAM_CHANNELS, 48962306a36Sopenharmony_ci -1); 49062306a36Sopenharmony_ci if (err < 0) 49162306a36Sopenharmony_ci goto dout_exit; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cidout_exit: 49462306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 49562306a36Sopenharmony_ci return err; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci#endif /* !ECHOCARD_HAS_VMIXER */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int pcm_close(struct snd_pcm_substream *substream) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* Nothing to do here. Audio is already off and pipe will be 50962306a36Sopenharmony_ci * freed by its callback 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d", 51562306a36Sopenharmony_ci chip->opencount, chip->can_set_rate, chip->rate_set); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci chip->opencount--; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci switch (chip->opencount) { 52062306a36Sopenharmony_ci case 1: 52162306a36Sopenharmony_ci chip->can_set_rate = 1; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci case 0: 52562306a36Sopenharmony_ci chip->rate_set = 0; 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* Channel allocation and scatter-gather list setup */ 53662306a36Sopenharmony_cistatic int init_engine(struct snd_pcm_substream *substream, 53762306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params, 53862306a36Sopenharmony_ci int pipe_index, int interleave) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct echoaudio *chip; 54162306a36Sopenharmony_ci int err, per, rest, page, edge, offs; 54262306a36Sopenharmony_ci struct audiopipe *pipe; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci chip = snd_pcm_substream_chip(substream); 54562306a36Sopenharmony_ci pipe = (struct audiopipe *) substream->runtime->private_data; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Sets up che hardware. If it's already initialized, reset and 54862306a36Sopenharmony_ci * redo with the new parameters 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 55162306a36Sopenharmony_ci if (pipe->index >= 0) { 55262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index); 55362306a36Sopenharmony_ci err = free_pipes(chip, pipe); 55462306a36Sopenharmony_ci snd_BUG_ON(err); 55562306a36Sopenharmony_ci chip->substream[pipe->index] = NULL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci err = allocate_pipes(chip, pipe, pipe_index, interleave); 55962306a36Sopenharmony_ci if (err < 0) { 56062306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 56162306a36Sopenharmony_ci dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n", 56262306a36Sopenharmony_ci pipe_index, err); 56362306a36Sopenharmony_ci return err; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 56662306a36Sopenharmony_ci dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci dev_dbg(chip->card->dev, 56962306a36Sopenharmony_ci "pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n", 57062306a36Sopenharmony_ci params_buffer_bytes(hw_params), params_periods(hw_params), 57162306a36Sopenharmony_ci params_period_bytes(hw_params)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci sglist_init(chip, pipe); 57462306a36Sopenharmony_ci edge = PAGE_SIZE; 57562306a36Sopenharmony_ci for (offs = page = per = 0; offs < params_buffer_bytes(hw_params); 57662306a36Sopenharmony_ci per++) { 57762306a36Sopenharmony_ci rest = params_period_bytes(hw_params); 57862306a36Sopenharmony_ci if (offs + rest > params_buffer_bytes(hw_params)) 57962306a36Sopenharmony_ci rest = params_buffer_bytes(hw_params) - offs; 58062306a36Sopenharmony_ci while (rest) { 58162306a36Sopenharmony_ci dma_addr_t addr; 58262306a36Sopenharmony_ci addr = snd_pcm_sgbuf_get_addr(substream, offs); 58362306a36Sopenharmony_ci if (rest <= edge - offs) { 58462306a36Sopenharmony_ci sglist_add_mapping(chip, pipe, addr, rest); 58562306a36Sopenharmony_ci sglist_add_irq(chip, pipe); 58662306a36Sopenharmony_ci offs += rest; 58762306a36Sopenharmony_ci rest = 0; 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci sglist_add_mapping(chip, pipe, addr, 59062306a36Sopenharmony_ci edge - offs); 59162306a36Sopenharmony_ci rest -= edge - offs; 59262306a36Sopenharmony_ci offs = edge; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci if (offs == edge) { 59562306a36Sopenharmony_ci edge += PAGE_SIZE; 59662306a36Sopenharmony_ci page++; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Close the ring buffer */ 60262306a36Sopenharmony_ci sglist_wrap(chip, pipe); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* This stuff is used by the irq handler, so it must be 60562306a36Sopenharmony_ci * initialized before chip->substream 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ci pipe->last_period = 0; 60862306a36Sopenharmony_ci pipe->last_counter = 0; 60962306a36Sopenharmony_ci pipe->position = 0; 61062306a36Sopenharmony_ci smp_wmb(); 61162306a36Sopenharmony_ci chip->substream[pipe_index] = substream; 61262306a36Sopenharmony_ci chip->rate_set = 1; 61362306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 61462306a36Sopenharmony_ci set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den); 61562306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int pcm_analog_in_hw_params(struct snd_pcm_substream *substream, 62262306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return init_engine(substream, hw_params, px_analog_in(chip) + 62762306a36Sopenharmony_ci substream->number, params_channels(hw_params)); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int pcm_analog_out_hw_params(struct snd_pcm_substream *substream, 63362306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci return init_engine(substream, hw_params, substream->number, 63662306a36Sopenharmony_ci params_channels(hw_params)); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int pcm_digital_in_hw_params(struct snd_pcm_substream *substream, 64462306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return init_engine(substream, hw_params, px_digital_in(chip) + 64962306a36Sopenharmony_ci substream->number, params_channels(hw_params)); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci#ifndef ECHOCARD_HAS_VMIXER /* See the note in snd_echo_new_pcm() */ 65562306a36Sopenharmony_cistatic int pcm_digital_out_hw_params(struct snd_pcm_substream *substream, 65662306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci return init_engine(substream, hw_params, px_digital_out(chip) + 66162306a36Sopenharmony_ci substream->number, params_channels(hw_params)); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci#endif /* !ECHOCARD_HAS_VMIXER */ 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int pcm_hw_free(struct snd_pcm_substream *substream) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct echoaudio *chip; 67262306a36Sopenharmony_ci struct audiopipe *pipe; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci chip = snd_pcm_substream_chip(substream); 67562306a36Sopenharmony_ci pipe = (struct audiopipe *) substream->runtime->private_data; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 67862306a36Sopenharmony_ci if (pipe->index >= 0) { 67962306a36Sopenharmony_ci dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index); 68062306a36Sopenharmony_ci free_pipes(chip, pipe); 68162306a36Sopenharmony_ci chip->substream[pipe->index] = NULL; 68262306a36Sopenharmony_ci pipe->index = -1; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int pcm_prepare(struct snd_pcm_substream *substream) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 69462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 69562306a36Sopenharmony_ci struct audioformat format; 69662306a36Sopenharmony_ci int pipe_index = ((struct audiopipe *)runtime->private_data)->index; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci dev_dbg(chip->card->dev, "Prepare rate=%d format=%d channels=%d\n", 69962306a36Sopenharmony_ci runtime->rate, runtime->format, runtime->channels); 70062306a36Sopenharmony_ci format.interleave = runtime->channels; 70162306a36Sopenharmony_ci format.data_are_bigendian = 0; 70262306a36Sopenharmony_ci format.mono_to_stereo = 0; 70362306a36Sopenharmony_ci switch (runtime->format) { 70462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 70562306a36Sopenharmony_ci format.bits_per_sample = 8; 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 70862306a36Sopenharmony_ci format.bits_per_sample = 16; 70962306a36Sopenharmony_ci break; 71062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 71162306a36Sopenharmony_ci format.bits_per_sample = 24; 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_BE: 71462306a36Sopenharmony_ci format.data_are_bigendian = 1; 71562306a36Sopenharmony_ci fallthrough; 71662306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 71762306a36Sopenharmony_ci format.bits_per_sample = 32; 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci default: 72062306a36Sopenharmony_ci dev_err(chip->card->dev, 72162306a36Sopenharmony_ci "Prepare error: unsupported format %d\n", 72262306a36Sopenharmony_ci runtime->format); 72362306a36Sopenharmony_ci return -EINVAL; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (snd_BUG_ON(pipe_index >= px_num(chip))) 72762306a36Sopenharmony_ci return -EINVAL; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* 73062306a36Sopenharmony_ci * We passed checks we can do independently; now take 73162306a36Sopenharmony_ci * exclusive control 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index))) { 73762306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 73862306a36Sopenharmony_ci return -EINVAL; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci set_audio_format(chip, pipe_index, &format); 74262306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int pcm_trigger(struct snd_pcm_substream *substream, int cmd) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct echoaudio *chip = snd_pcm_substream_chip(substream); 75262306a36Sopenharmony_ci struct audiopipe *pipe; 75362306a36Sopenharmony_ci int i, err; 75462306a36Sopenharmony_ci u32 channelmask = 0; 75562306a36Sopenharmony_ci struct snd_pcm_substream *s; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci snd_pcm_group_for_each_entry(s, substream) { 75862306a36Sopenharmony_ci for (i = 0; i < DSP_MAXPIPES; i++) { 75962306a36Sopenharmony_ci if (s == chip->substream[i]) { 76062306a36Sopenharmony_ci channelmask |= 1 << i; 76162306a36Sopenharmony_ci snd_pcm_trigger_done(s, substream); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci spin_lock(&chip->lock); 76762306a36Sopenharmony_ci switch (cmd) { 76862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 76962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 77062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 77162306a36Sopenharmony_ci for (i = 0; i < DSP_MAXPIPES; i++) { 77262306a36Sopenharmony_ci if (channelmask & (1 << i)) { 77362306a36Sopenharmony_ci pipe = chip->substream[i]->runtime->private_data; 77462306a36Sopenharmony_ci switch (pipe->state) { 77562306a36Sopenharmony_ci case PIPE_STATE_STOPPED: 77662306a36Sopenharmony_ci pipe->last_period = 0; 77762306a36Sopenharmony_ci pipe->last_counter = 0; 77862306a36Sopenharmony_ci pipe->position = 0; 77962306a36Sopenharmony_ci *pipe->dma_counter = 0; 78062306a36Sopenharmony_ci fallthrough; 78162306a36Sopenharmony_ci case PIPE_STATE_PAUSED: 78262306a36Sopenharmony_ci pipe->state = PIPE_STATE_STARTED; 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci case PIPE_STATE_STARTED: 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci err = start_transport(chip, channelmask, 79062306a36Sopenharmony_ci chip->pipe_cyclic_mask); 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 79362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 79462306a36Sopenharmony_ci for (i = 0; i < DSP_MAXPIPES; i++) { 79562306a36Sopenharmony_ci if (channelmask & (1 << i)) { 79662306a36Sopenharmony_ci pipe = chip->substream[i]->runtime->private_data; 79762306a36Sopenharmony_ci pipe->state = PIPE_STATE_STOPPED; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci err = stop_transport(chip, channelmask); 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 80362306a36Sopenharmony_ci for (i = 0; i < DSP_MAXPIPES; i++) { 80462306a36Sopenharmony_ci if (channelmask & (1 << i)) { 80562306a36Sopenharmony_ci pipe = chip->substream[i]->runtime->private_data; 80662306a36Sopenharmony_ci pipe->state = PIPE_STATE_PAUSED; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci err = pause_transport(chip, channelmask); 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci default: 81262306a36Sopenharmony_ci err = -EINVAL; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci spin_unlock(&chip->lock); 81562306a36Sopenharmony_ci return err; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 82362306a36Sopenharmony_ci struct audiopipe *pipe = runtime->private_data; 82462306a36Sopenharmony_ci u32 counter, step; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* 82762306a36Sopenharmony_ci * IRQ handling runs concurrently. Do not share tracking of 82862306a36Sopenharmony_ci * counter with it, which would race or require locking 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci counter = le32_to_cpu(*pipe->dma_counter); /* presumed atomic */ 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci step = counter - pipe->last_counter; /* handles wrapping */ 83462306a36Sopenharmony_ci pipe->last_counter = counter; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* counter doesn't neccessarily wrap on a multiple of 83762306a36Sopenharmony_ci * buffer_size, so can't derive the position; must 83862306a36Sopenharmony_ci * accumulate */ 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci pipe->position += step; 84162306a36Sopenharmony_ci pipe->position %= frames_to_bytes(runtime, runtime->buffer_size); /* wrap */ 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return bytes_to_frames(runtime, pipe->position); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* pcm *_ops structures */ 84962306a36Sopenharmony_cistatic const struct snd_pcm_ops analog_playback_ops = { 85062306a36Sopenharmony_ci .open = pcm_analog_out_open, 85162306a36Sopenharmony_ci .close = pcm_close, 85262306a36Sopenharmony_ci .hw_params = pcm_analog_out_hw_params, 85362306a36Sopenharmony_ci .hw_free = pcm_hw_free, 85462306a36Sopenharmony_ci .prepare = pcm_prepare, 85562306a36Sopenharmony_ci .trigger = pcm_trigger, 85662306a36Sopenharmony_ci .pointer = pcm_pointer, 85762306a36Sopenharmony_ci}; 85862306a36Sopenharmony_cistatic const struct snd_pcm_ops analog_capture_ops = { 85962306a36Sopenharmony_ci .open = pcm_analog_in_open, 86062306a36Sopenharmony_ci .close = pcm_close, 86162306a36Sopenharmony_ci .hw_params = pcm_analog_in_hw_params, 86262306a36Sopenharmony_ci .hw_free = pcm_hw_free, 86362306a36Sopenharmony_ci .prepare = pcm_prepare, 86462306a36Sopenharmony_ci .trigger = pcm_trigger, 86562306a36Sopenharmony_ci .pointer = pcm_pointer, 86662306a36Sopenharmony_ci}; 86762306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 86862306a36Sopenharmony_ci#ifndef ECHOCARD_HAS_VMIXER 86962306a36Sopenharmony_cistatic const struct snd_pcm_ops digital_playback_ops = { 87062306a36Sopenharmony_ci .open = pcm_digital_out_open, 87162306a36Sopenharmony_ci .close = pcm_close, 87262306a36Sopenharmony_ci .hw_params = pcm_digital_out_hw_params, 87362306a36Sopenharmony_ci .hw_free = pcm_hw_free, 87462306a36Sopenharmony_ci .prepare = pcm_prepare, 87562306a36Sopenharmony_ci .trigger = pcm_trigger, 87662306a36Sopenharmony_ci .pointer = pcm_pointer, 87762306a36Sopenharmony_ci}; 87862306a36Sopenharmony_ci#endif /* !ECHOCARD_HAS_VMIXER */ 87962306a36Sopenharmony_cistatic const struct snd_pcm_ops digital_capture_ops = { 88062306a36Sopenharmony_ci .open = pcm_digital_in_open, 88162306a36Sopenharmony_ci .close = pcm_close, 88262306a36Sopenharmony_ci .hw_params = pcm_digital_in_hw_params, 88362306a36Sopenharmony_ci .hw_free = pcm_hw_free, 88462306a36Sopenharmony_ci .prepare = pcm_prepare, 88562306a36Sopenharmony_ci .trigger = pcm_trigger, 88662306a36Sopenharmony_ci .pointer = pcm_pointer, 88762306a36Sopenharmony_ci}; 88862306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/* Preallocate memory only for the first substream because it's the most 89362306a36Sopenharmony_ci * used one 89462306a36Sopenharmony_ci */ 89562306a36Sopenharmony_cistatic void snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct snd_pcm_substream *ss; 89862306a36Sopenharmony_ci int stream; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci for (stream = 0; stream < 2; stream++) 90162306a36Sopenharmony_ci for (ss = pcm->streams[stream].substream; ss; ss = ss->next) 90262306a36Sopenharmony_ci snd_pcm_set_managed_buffer(ss, SNDRV_DMA_TYPE_DEV_SG, 90362306a36Sopenharmony_ci dev, 90462306a36Sopenharmony_ci ss->number ? 0 : 128<<10, 90562306a36Sopenharmony_ci 256<<10); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci/*<--snd_echo_probe() */ 91162306a36Sopenharmony_cistatic int snd_echo_new_pcm(struct echoaudio *chip) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct snd_pcm *pcm; 91462306a36Sopenharmony_ci int err; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 91762306a36Sopenharmony_ci /* This card has a Vmixer, that is there is no direct mapping from PCM 91862306a36Sopenharmony_ci streams to physical outputs. The user can mix the streams as he wishes 91962306a36Sopenharmony_ci via control interface and it's possible to send any stream to any 92062306a36Sopenharmony_ci output, thus it makes no sense to keep analog and digital outputs 92162306a36Sopenharmony_ci separated */ 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* PCM#0 Virtual outputs and analog inputs */ 92462306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip), 92562306a36Sopenharmony_ci num_analog_busses_in(chip), &pcm); 92662306a36Sopenharmony_ci if (err < 0) 92762306a36Sopenharmony_ci return err; 92862306a36Sopenharmony_ci pcm->private_data = chip; 92962306a36Sopenharmony_ci chip->analog_pcm = pcm; 93062306a36Sopenharmony_ci strcpy(pcm->name, chip->card->shortname); 93162306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); 93262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); 93362306a36Sopenharmony_ci snd_echo_preallocate_pages(pcm, &chip->pci->dev); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 93662306a36Sopenharmony_ci /* PCM#1 Digital inputs, no outputs */ 93762306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Digital PCM", 1, 0, 93862306a36Sopenharmony_ci num_digital_busses_in(chip), &pcm); 93962306a36Sopenharmony_ci if (err < 0) 94062306a36Sopenharmony_ci return err; 94162306a36Sopenharmony_ci pcm->private_data = chip; 94262306a36Sopenharmony_ci chip->digital_pcm = pcm; 94362306a36Sopenharmony_ci strcpy(pcm->name, chip->card->shortname); 94462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); 94562306a36Sopenharmony_ci snd_echo_preallocate_pages(pcm, &chip->pci->dev); 94662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci#else /* ECHOCARD_HAS_VMIXER */ 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci /* The card can manage substreams formed by analog and digital channels 95162306a36Sopenharmony_ci at the same time, but I prefer to keep analog and digital channels 95262306a36Sopenharmony_ci separated, because that mixed thing is confusing and useless. So we 95362306a36Sopenharmony_ci register two PCM devices: */ 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* PCM#0 Analog i/o */ 95662306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Analog PCM", 0, 95762306a36Sopenharmony_ci num_analog_busses_out(chip), 95862306a36Sopenharmony_ci num_analog_busses_in(chip), &pcm); 95962306a36Sopenharmony_ci if (err < 0) 96062306a36Sopenharmony_ci return err; 96162306a36Sopenharmony_ci pcm->private_data = chip; 96262306a36Sopenharmony_ci chip->analog_pcm = pcm; 96362306a36Sopenharmony_ci strcpy(pcm->name, chip->card->shortname); 96462306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); 96562306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); 96662306a36Sopenharmony_ci snd_echo_preallocate_pages(pcm, &chip->pci->dev); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 96962306a36Sopenharmony_ci /* PCM#1 Digital i/o */ 97062306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "Digital PCM", 1, 97162306a36Sopenharmony_ci num_digital_busses_out(chip), 97262306a36Sopenharmony_ci num_digital_busses_in(chip), &pcm); 97362306a36Sopenharmony_ci if (err < 0) 97462306a36Sopenharmony_ci return err; 97562306a36Sopenharmony_ci pcm->private_data = chip; 97662306a36Sopenharmony_ci chip->digital_pcm = pcm; 97762306a36Sopenharmony_ci strcpy(pcm->name, chip->card->shortname); 97862306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops); 97962306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); 98062306a36Sopenharmony_ci snd_echo_preallocate_pages(pcm, &chip->pci->dev); 98162306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_VMIXER */ 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return 0; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/****************************************************************************** 99262306a36Sopenharmony_ci Control interface 99362306a36Sopenharmony_ci******************************************************************************/ 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci#if !defined(ECHOCARD_HAS_VMIXER) || defined(ECHOCARD_HAS_LINE_OUT_GAIN) 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci/******************* PCM output volume *******************/ 99862306a36Sopenharmony_cistatic int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol, 99962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct echoaudio *chip; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 100462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 100562306a36Sopenharmony_ci uinfo->count = num_busses_out(chip); 100662306a36Sopenharmony_ci uinfo->value.integer.min = ECHOGAIN_MINOUT; 100762306a36Sopenharmony_ci uinfo->value.integer.max = ECHOGAIN_MAXOUT; 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int snd_echo_output_gain_get(struct snd_kcontrol *kcontrol, 101262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct echoaudio *chip; 101562306a36Sopenharmony_ci int c; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 101862306a36Sopenharmony_ci for (c = 0; c < num_busses_out(chip); c++) 101962306a36Sopenharmony_ci ucontrol->value.integer.value[c] = chip->output_gain[c]; 102062306a36Sopenharmony_ci return 0; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, 102462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci struct echoaudio *chip; 102762306a36Sopenharmony_ci int c, changed, gain; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci changed = 0; 103062306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 103162306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 103262306a36Sopenharmony_ci for (c = 0; c < num_busses_out(chip); c++) { 103362306a36Sopenharmony_ci gain = ucontrol->value.integer.value[c]; 103462306a36Sopenharmony_ci /* Ignore out of range values */ 103562306a36Sopenharmony_ci if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) 103662306a36Sopenharmony_ci continue; 103762306a36Sopenharmony_ci if (chip->output_gain[c] != gain) { 103862306a36Sopenharmony_ci set_output_gain(chip, c, gain); 103962306a36Sopenharmony_ci changed = 1; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci if (changed) 104362306a36Sopenharmony_ci update_output_line_level(chip); 104462306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 104562306a36Sopenharmony_ci return changed; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_LINE_OUT_GAIN 104962306a36Sopenharmony_ci/* On the Mia this one controls the line-out volume */ 105062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_line_output_gain = { 105162306a36Sopenharmony_ci .name = "Line Playback Volume", 105262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 105362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 105462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 105562306a36Sopenharmony_ci .info = snd_echo_output_gain_info, 105662306a36Sopenharmony_ci .get = snd_echo_output_gain_get, 105762306a36Sopenharmony_ci .put = snd_echo_output_gain_put, 105862306a36Sopenharmony_ci .tlv = {.p = db_scale_output_gain}, 105962306a36Sopenharmony_ci}; 106062306a36Sopenharmony_ci#else 106162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_pcm_output_gain = { 106262306a36Sopenharmony_ci .name = "PCM Playback Volume", 106362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 106462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, 106562306a36Sopenharmony_ci .info = snd_echo_output_gain_info, 106662306a36Sopenharmony_ci .get = snd_echo_output_gain_get, 106762306a36Sopenharmony_ci .put = snd_echo_output_gain_put, 106862306a36Sopenharmony_ci .tlv = {.p = db_scale_output_gain}, 106962306a36Sopenharmony_ci}; 107062306a36Sopenharmony_ci#endif 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci#endif /* !ECHOCARD_HAS_VMIXER || ECHOCARD_HAS_LINE_OUT_GAIN */ 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_INPUT_GAIN 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/******************* Analog input volume *******************/ 107962306a36Sopenharmony_cistatic int snd_echo_input_gain_info(struct snd_kcontrol *kcontrol, 108062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct echoaudio *chip; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 108562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 108662306a36Sopenharmony_ci uinfo->count = num_analog_busses_in(chip); 108762306a36Sopenharmony_ci uinfo->value.integer.min = ECHOGAIN_MININP; 108862306a36Sopenharmony_ci uinfo->value.integer.max = ECHOGAIN_MAXINP; 108962306a36Sopenharmony_ci return 0; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int snd_echo_input_gain_get(struct snd_kcontrol *kcontrol, 109362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct echoaudio *chip; 109662306a36Sopenharmony_ci int c; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 109962306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_in(chip); c++) 110062306a36Sopenharmony_ci ucontrol->value.integer.value[c] = chip->input_gain[c]; 110162306a36Sopenharmony_ci return 0; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, 110562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct echoaudio *chip; 110862306a36Sopenharmony_ci int c, gain, changed; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci changed = 0; 111162306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 111262306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 111362306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_in(chip); c++) { 111462306a36Sopenharmony_ci gain = ucontrol->value.integer.value[c]; 111562306a36Sopenharmony_ci /* Ignore out of range values */ 111662306a36Sopenharmony_ci if (gain < ECHOGAIN_MININP || gain > ECHOGAIN_MAXINP) 111762306a36Sopenharmony_ci continue; 111862306a36Sopenharmony_ci if (chip->input_gain[c] != gain) { 111962306a36Sopenharmony_ci set_input_gain(chip, c, gain); 112062306a36Sopenharmony_ci changed = 1; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci if (changed) 112462306a36Sopenharmony_ci update_input_line_level(chip); 112562306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 112662306a36Sopenharmony_ci return changed; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_line_input_gain = { 113262306a36Sopenharmony_ci .name = "Line Capture Volume", 113362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 113462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, 113562306a36Sopenharmony_ci .info = snd_echo_input_gain_info, 113662306a36Sopenharmony_ci .get = snd_echo_input_gain_get, 113762306a36Sopenharmony_ci .put = snd_echo_input_gain_put, 113862306a36Sopenharmony_ci .tlv = {.p = db_scale_input_gain}, 113962306a36Sopenharmony_ci}; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_INPUT_GAIN */ 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci/************ Analog output nominal level (+4dBu / -10dBV) ***************/ 114862306a36Sopenharmony_cistatic int snd_echo_output_nominal_info (struct snd_kcontrol *kcontrol, 114962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct echoaudio *chip; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 115462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 115562306a36Sopenharmony_ci uinfo->count = num_analog_busses_out(chip); 115662306a36Sopenharmony_ci uinfo->value.integer.min = 0; 115762306a36Sopenharmony_ci uinfo->value.integer.max = 1; 115862306a36Sopenharmony_ci return 0; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int snd_echo_output_nominal_get(struct snd_kcontrol *kcontrol, 116262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci struct echoaudio *chip; 116562306a36Sopenharmony_ci int c; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 116862306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_out(chip); c++) 116962306a36Sopenharmony_ci ucontrol->value.integer.value[c] = chip->nominal_level[c]; 117062306a36Sopenharmony_ci return 0; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, 117462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci struct echoaudio *chip; 117762306a36Sopenharmony_ci int c, changed; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci changed = 0; 118062306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 118162306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 118262306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_out(chip); c++) { 118362306a36Sopenharmony_ci if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) { 118462306a36Sopenharmony_ci set_nominal_level(chip, c, 118562306a36Sopenharmony_ci ucontrol->value.integer.value[c]); 118662306a36Sopenharmony_ci changed = 1; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci if (changed) 119062306a36Sopenharmony_ci update_output_line_level(chip); 119162306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 119262306a36Sopenharmony_ci return changed; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_output_nominal_level = { 119662306a36Sopenharmony_ci .name = "Line Playback Switch (-10dBV)", 119762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 119862306a36Sopenharmony_ci .info = snd_echo_output_nominal_info, 119962306a36Sopenharmony_ci .get = snd_echo_output_nominal_get, 120062306a36Sopenharmony_ci .put = snd_echo_output_nominal_put, 120162306a36Sopenharmony_ci}; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL */ 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/*************** Analog input nominal level (+4dBu / -10dBV) ***************/ 121062306a36Sopenharmony_cistatic int snd_echo_input_nominal_info(struct snd_kcontrol *kcontrol, 121162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct echoaudio *chip; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 121662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 121762306a36Sopenharmony_ci uinfo->count = num_analog_busses_in(chip); 121862306a36Sopenharmony_ci uinfo->value.integer.min = 0; 121962306a36Sopenharmony_ci uinfo->value.integer.max = 1; 122062306a36Sopenharmony_ci return 0; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic int snd_echo_input_nominal_get(struct snd_kcontrol *kcontrol, 122462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct echoaudio *chip; 122762306a36Sopenharmony_ci int c; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 123062306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_in(chip); c++) 123162306a36Sopenharmony_ci ucontrol->value.integer.value[c] = 123262306a36Sopenharmony_ci chip->nominal_level[bx_analog_in(chip) + c]; 123362306a36Sopenharmony_ci return 0; 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, 123762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci struct echoaudio *chip; 124062306a36Sopenharmony_ci int c, changed; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci changed = 0; 124362306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 124462306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 124562306a36Sopenharmony_ci for (c = 0; c < num_analog_busses_in(chip); c++) { 124662306a36Sopenharmony_ci if (chip->nominal_level[bx_analog_in(chip) + c] != 124762306a36Sopenharmony_ci ucontrol->value.integer.value[c]) { 124862306a36Sopenharmony_ci set_nominal_level(chip, bx_analog_in(chip) + c, 124962306a36Sopenharmony_ci ucontrol->value.integer.value[c]); 125062306a36Sopenharmony_ci changed = 1; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci if (changed) 125462306a36Sopenharmony_ci update_output_line_level(chip); /* "Output" is not a mistake 125562306a36Sopenharmony_ci * here. 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 125862306a36Sopenharmony_ci return changed; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_intput_nominal_level = { 126262306a36Sopenharmony_ci .name = "Line Capture Switch (-10dBV)", 126362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 126462306a36Sopenharmony_ci .info = snd_echo_input_nominal_info, 126562306a36Sopenharmony_ci .get = snd_echo_input_nominal_get, 126662306a36Sopenharmony_ci .put = snd_echo_input_nominal_put, 126762306a36Sopenharmony_ci}; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_INPUT_NOMINAL_LEVEL */ 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MONITOR 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci/******************* Monitor mixer *******************/ 127662306a36Sopenharmony_cistatic int snd_echo_mixer_info(struct snd_kcontrol *kcontrol, 127762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 128062306a36Sopenharmony_ci uinfo->count = 1; 128162306a36Sopenharmony_ci uinfo->value.integer.min = ECHOGAIN_MINOUT; 128262306a36Sopenharmony_ci uinfo->value.integer.max = ECHOGAIN_MAXOUT; 128362306a36Sopenharmony_ci return 0; 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic int snd_echo_mixer_get(struct snd_kcontrol *kcontrol, 128762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci struct echoaudio *chip = snd_kcontrol_chip(kcontrol); 129062306a36Sopenharmony_ci unsigned int out = ucontrol->id.index / num_busses_in(chip); 129162306a36Sopenharmony_ci unsigned int in = ucontrol->id.index % num_busses_in(chip); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (out >= ECHO_MAXAUDIOOUTPUTS || in >= ECHO_MAXAUDIOINPUTS) 129462306a36Sopenharmony_ci return -EINVAL; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->monitor_gain[out][in]; 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, 130162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct echoaudio *chip; 130462306a36Sopenharmony_ci int changed, gain; 130562306a36Sopenharmony_ci unsigned int out, in; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci changed = 0; 130862306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 130962306a36Sopenharmony_ci out = ucontrol->id.index / num_busses_in(chip); 131062306a36Sopenharmony_ci in = ucontrol->id.index % num_busses_in(chip); 131162306a36Sopenharmony_ci if (out >= ECHO_MAXAUDIOOUTPUTS || in >= ECHO_MAXAUDIOINPUTS) 131262306a36Sopenharmony_ci return -EINVAL; 131362306a36Sopenharmony_ci gain = ucontrol->value.integer.value[0]; 131462306a36Sopenharmony_ci if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) 131562306a36Sopenharmony_ci return -EINVAL; 131662306a36Sopenharmony_ci if (chip->monitor_gain[out][in] != gain) { 131762306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 131862306a36Sopenharmony_ci set_monitor_gain(chip, out, in, gain); 131962306a36Sopenharmony_ci update_output_line_level(chip); 132062306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 132162306a36Sopenharmony_ci changed = 1; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci return changed; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic struct snd_kcontrol_new snd_echo_monitor_mixer = { 132762306a36Sopenharmony_ci .name = "Monitor Mixer Volume", 132862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 132962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, 133062306a36Sopenharmony_ci .info = snd_echo_mixer_info, 133162306a36Sopenharmony_ci .get = snd_echo_mixer_get, 133262306a36Sopenharmony_ci .put = snd_echo_mixer_put, 133362306a36Sopenharmony_ci .tlv = {.p = db_scale_output_gain}, 133462306a36Sopenharmony_ci}; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_MONITOR */ 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci/******************* Vmixer *******************/ 134362306a36Sopenharmony_cistatic int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol, 134462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 134762306a36Sopenharmony_ci uinfo->count = 1; 134862306a36Sopenharmony_ci uinfo->value.integer.min = ECHOGAIN_MINOUT; 134962306a36Sopenharmony_ci uinfo->value.integer.max = ECHOGAIN_MAXOUT; 135062306a36Sopenharmony_ci return 0; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int snd_echo_vmixer_get(struct snd_kcontrol *kcontrol, 135462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct echoaudio *chip; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 135962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 136062306a36Sopenharmony_ci chip->vmixer_gain[ucontrol->id.index / num_pipes_out(chip)] 136162306a36Sopenharmony_ci [ucontrol->id.index % num_pipes_out(chip)]; 136262306a36Sopenharmony_ci return 0; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, 136662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct echoaudio *chip; 136962306a36Sopenharmony_ci int gain, changed; 137062306a36Sopenharmony_ci short vch, out; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci changed = 0; 137362306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 137462306a36Sopenharmony_ci out = ucontrol->id.index / num_pipes_out(chip); 137562306a36Sopenharmony_ci vch = ucontrol->id.index % num_pipes_out(chip); 137662306a36Sopenharmony_ci gain = ucontrol->value.integer.value[0]; 137762306a36Sopenharmony_ci if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) 137862306a36Sopenharmony_ci return -EINVAL; 137962306a36Sopenharmony_ci if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) { 138062306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 138162306a36Sopenharmony_ci set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]); 138262306a36Sopenharmony_ci update_vmixer_level(chip); 138362306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 138462306a36Sopenharmony_ci changed = 1; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci return changed; 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic struct snd_kcontrol_new snd_echo_vmixer = { 139062306a36Sopenharmony_ci .name = "VMixer Volume", 139162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 139262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, 139362306a36Sopenharmony_ci .info = snd_echo_vmixer_info, 139462306a36Sopenharmony_ci .get = snd_echo_vmixer_get, 139562306a36Sopenharmony_ci .put = snd_echo_vmixer_put, 139662306a36Sopenharmony_ci .tlv = {.p = db_scale_output_gain}, 139762306a36Sopenharmony_ci}; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_VMIXER */ 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci/******************* Digital mode switch *******************/ 140662306a36Sopenharmony_cistatic int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol, 140762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci static const char * const names[4] = { 141062306a36Sopenharmony_ci "S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical", 141162306a36Sopenharmony_ci "S/PDIF Cdrom" 141262306a36Sopenharmony_ci }; 141362306a36Sopenharmony_ci struct echoaudio *chip; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 141662306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, chip->num_digital_modes, names); 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol, 142062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct echoaudio *chip; 142362306a36Sopenharmony_ci int i, mode; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 142662306a36Sopenharmony_ci mode = chip->digital_mode; 142762306a36Sopenharmony_ci for (i = chip->num_digital_modes - 1; i >= 0; i--) 142862306a36Sopenharmony_ci if (mode == chip->digital_mode_list[i]) { 142962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = i; 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci return 0; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, 143662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci struct echoaudio *chip; 143962306a36Sopenharmony_ci int changed; 144062306a36Sopenharmony_ci unsigned short emode, dmode; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci changed = 0; 144362306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci emode = ucontrol->value.enumerated.item[0]; 144662306a36Sopenharmony_ci if (emode >= chip->num_digital_modes) 144762306a36Sopenharmony_ci return -EINVAL; 144862306a36Sopenharmony_ci dmode = chip->digital_mode_list[emode]; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (dmode != chip->digital_mode) { 145162306a36Sopenharmony_ci /* mode_mutex is required to make this operation atomic wrt 145262306a36Sopenharmony_ci pcm_digital_*_open() and set_input_clock() functions. */ 145362306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* Do not allow the user to change the digital mode when a pcm 145662306a36Sopenharmony_ci device is open because it also changes the number of channels 145762306a36Sopenharmony_ci and the allowed sample rates */ 145862306a36Sopenharmony_ci if (chip->opencount) { 145962306a36Sopenharmony_ci changed = -EAGAIN; 146062306a36Sopenharmony_ci } else { 146162306a36Sopenharmony_ci changed = set_digital_mode(chip, dmode); 146262306a36Sopenharmony_ci /* If we had to change the clock source, report it */ 146362306a36Sopenharmony_ci if (changed > 0 && chip->clock_src_ctl) { 146462306a36Sopenharmony_ci snd_ctl_notify(chip->card, 146562306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_VALUE, 146662306a36Sopenharmony_ci &chip->clock_src_ctl->id); 146762306a36Sopenharmony_ci dev_dbg(chip->card->dev, 146862306a36Sopenharmony_ci "SDM() =%d\n", changed); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci if (changed >= 0) 147162306a36Sopenharmony_ci changed = 1; /* No errors */ 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci return changed; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_digital_mode_switch = { 147962306a36Sopenharmony_ci .name = "Digital mode Switch", 148062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 148162306a36Sopenharmony_ci .info = snd_echo_digital_mode_info, 148262306a36Sopenharmony_ci .get = snd_echo_digital_mode_get, 148362306a36Sopenharmony_ci .put = snd_echo_digital_mode_put, 148462306a36Sopenharmony_ci}; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */ 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci/******************* S/PDIF mode switch *******************/ 149362306a36Sopenharmony_cistatic int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol, 149462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 149562306a36Sopenharmony_ci{ 149662306a36Sopenharmony_ci static const char * const names[2] = {"Consumer", "Professional"}; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, names); 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol, 150262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci struct echoaudio *chip; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 150762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = !!chip->professional_spdif; 150862306a36Sopenharmony_ci return 0; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, 151262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci struct echoaudio *chip; 151562306a36Sopenharmony_ci int mode; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 151862306a36Sopenharmony_ci mode = !!ucontrol->value.enumerated.item[0]; 151962306a36Sopenharmony_ci if (mode != chip->professional_spdif) { 152062306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 152162306a36Sopenharmony_ci set_professional_spdif(chip, mode); 152262306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 152362306a36Sopenharmony_ci return 1; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci return 0; 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_spdif_mode_switch = { 152962306a36Sopenharmony_ci .name = "S/PDIF mode Switch", 153062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 153162306a36Sopenharmony_ci .info = snd_echo_spdif_mode_info, 153262306a36Sopenharmony_ci .get = snd_echo_spdif_mode_get, 153362306a36Sopenharmony_ci .put = snd_echo_spdif_mode_put, 153462306a36Sopenharmony_ci}; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IO */ 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci/******************* Select input clock source *******************/ 154362306a36Sopenharmony_cistatic int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol, 154462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci static const char * const names[8] = { 154762306a36Sopenharmony_ci "Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync", 154862306a36Sopenharmony_ci "ESync96", "MTC" 154962306a36Sopenharmony_ci }; 155062306a36Sopenharmony_ci struct echoaudio *chip; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 155362306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, chip->num_clock_sources, names); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol, 155762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 155862306a36Sopenharmony_ci{ 155962306a36Sopenharmony_ci struct echoaudio *chip; 156062306a36Sopenharmony_ci int i, clock; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 156362306a36Sopenharmony_ci clock = chip->input_clock; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci for (i = 0; i < chip->num_clock_sources; i++) 156662306a36Sopenharmony_ci if (clock == chip->clock_source_list[i]) 156762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = i; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci return 0; 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, 157362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci struct echoaudio *chip; 157662306a36Sopenharmony_ci int changed; 157762306a36Sopenharmony_ci unsigned int eclock, dclock; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci changed = 0; 158062306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 158162306a36Sopenharmony_ci eclock = ucontrol->value.enumerated.item[0]; 158262306a36Sopenharmony_ci if (eclock >= chip->input_clock_types) 158362306a36Sopenharmony_ci return -EINVAL; 158462306a36Sopenharmony_ci dclock = chip->clock_source_list[eclock]; 158562306a36Sopenharmony_ci if (chip->input_clock != dclock) { 158662306a36Sopenharmony_ci mutex_lock(&chip->mode_mutex); 158762306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 158862306a36Sopenharmony_ci changed = set_input_clock(chip, dclock); 158962306a36Sopenharmony_ci if (!changed) 159062306a36Sopenharmony_ci changed = 1; /* no errors */ 159162306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 159262306a36Sopenharmony_ci mutex_unlock(&chip->mode_mutex); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (changed < 0) 159662306a36Sopenharmony_ci dev_dbg(chip->card->dev, 159762306a36Sopenharmony_ci "seticlk val%d err 0x%x\n", dclock, changed); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return changed; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_clock_source_switch = { 160362306a36Sopenharmony_ci .name = "Sample Clock Source", 160462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 160562306a36Sopenharmony_ci .info = snd_echo_clock_source_info, 160662306a36Sopenharmony_ci .get = snd_echo_clock_source_get, 160762306a36Sopenharmony_ci .put = snd_echo_clock_source_put, 160862306a36Sopenharmony_ci}; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_PHANTOM_POWER 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci/******************* Phantom power switch *******************/ 161762306a36Sopenharmony_ci#define snd_echo_phantom_power_info snd_ctl_boolean_mono_info 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_cistatic int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol, 162062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci struct echoaudio *chip = snd_kcontrol_chip(kcontrol); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->phantom_power; 162562306a36Sopenharmony_ci return 0; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, 162962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci struct echoaudio *chip = snd_kcontrol_chip(kcontrol); 163262306a36Sopenharmony_ci int power, changed = 0; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci power = !!ucontrol->value.integer.value[0]; 163562306a36Sopenharmony_ci if (chip->phantom_power != power) { 163662306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 163762306a36Sopenharmony_ci changed = set_phantom_power(chip, power); 163862306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 163962306a36Sopenharmony_ci if (changed == 0) 164062306a36Sopenharmony_ci changed = 1; /* no errors */ 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci return changed; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_phantom_power_switch = { 164662306a36Sopenharmony_ci .name = "Phantom power Switch", 164762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 164862306a36Sopenharmony_ci .info = snd_echo_phantom_power_info, 164962306a36Sopenharmony_ci .get = snd_echo_phantom_power_get, 165062306a36Sopenharmony_ci .put = snd_echo_phantom_power_put, 165162306a36Sopenharmony_ci}; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_PHANTOM_POWER */ 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci/******************* Digital input automute switch *******************/ 166062306a36Sopenharmony_ci#define snd_echo_automute_info snd_ctl_boolean_mono_info 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic int snd_echo_automute_get(struct snd_kcontrol *kcontrol, 166362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 166462306a36Sopenharmony_ci{ 166562306a36Sopenharmony_ci struct echoaudio *chip = snd_kcontrol_chip(kcontrol); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->digital_in_automute; 166862306a36Sopenharmony_ci return 0; 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic int snd_echo_automute_put(struct snd_kcontrol *kcontrol, 167262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci struct echoaudio *chip = snd_kcontrol_chip(kcontrol); 167562306a36Sopenharmony_ci int automute, changed = 0; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci automute = !!ucontrol->value.integer.value[0]; 167862306a36Sopenharmony_ci if (chip->digital_in_automute != automute) { 167962306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 168062306a36Sopenharmony_ci changed = set_input_auto_mute(chip, automute); 168162306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 168262306a36Sopenharmony_ci if (changed == 0) 168362306a36Sopenharmony_ci changed = 1; /* no errors */ 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci return changed; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_automute_switch = { 168962306a36Sopenharmony_ci .name = "Digital Capture Switch (automute)", 169062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 169162306a36Sopenharmony_ci .info = snd_echo_automute_info, 169262306a36Sopenharmony_ci .get = snd_echo_automute_get, 169362306a36Sopenharmony_ci .put = snd_echo_automute_put, 169462306a36Sopenharmony_ci}; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE */ 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci/******************* VU-meters switch *******************/ 170162306a36Sopenharmony_ci#define snd_echo_vumeters_switch_info snd_ctl_boolean_mono_info 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, 170462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct echoaudio *chip; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 170962306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 171062306a36Sopenharmony_ci set_meters_on(chip, ucontrol->value.integer.value[0]); 171162306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 171262306a36Sopenharmony_ci return 1; 171362306a36Sopenharmony_ci} 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_vumeters_switch = { 171662306a36Sopenharmony_ci .name = "VU-meters Switch", 171762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 171862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_WRITE, 171962306a36Sopenharmony_ci .info = snd_echo_vumeters_switch_info, 172062306a36Sopenharmony_ci .put = snd_echo_vumeters_switch_put, 172162306a36Sopenharmony_ci}; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci/***** Read VU-meters (input, output, analog and digital together) *****/ 172662306a36Sopenharmony_cistatic int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, 172762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 173062306a36Sopenharmony_ci uinfo->count = 96; 173162306a36Sopenharmony_ci uinfo->value.integer.min = ECHOGAIN_MINOUT; 173262306a36Sopenharmony_ci uinfo->value.integer.max = 0; 173362306a36Sopenharmony_ci return 0; 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, 173762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct echoaudio *chip; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 174262306a36Sopenharmony_ci get_audio_meters(chip, ucontrol->value.integer.value); 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_vumeters = { 174762306a36Sopenharmony_ci .name = "VU-meters", 174862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 174962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 175062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE | 175162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 175262306a36Sopenharmony_ci .info = snd_echo_vumeters_info, 175362306a36Sopenharmony_ci .get = snd_echo_vumeters_get, 175462306a36Sopenharmony_ci .tlv = {.p = db_scale_output_gain}, 175562306a36Sopenharmony_ci}; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci/*** Channels info - it exports informations about the number of channels ***/ 176062306a36Sopenharmony_cistatic int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol, 176162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 176462306a36Sopenharmony_ci uinfo->count = 6; 176562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 176662306a36Sopenharmony_ci uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER; 176762306a36Sopenharmony_ci return 0; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_cistatic int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol, 177162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 177262306a36Sopenharmony_ci{ 177362306a36Sopenharmony_ci struct echoaudio *chip; 177462306a36Sopenharmony_ci int detected, clocks, bit, src; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci chip = snd_kcontrol_chip(kcontrol); 177762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = num_busses_in(chip); 177862306a36Sopenharmony_ci ucontrol->value.integer.value[1] = num_analog_busses_in(chip); 177962306a36Sopenharmony_ci ucontrol->value.integer.value[2] = num_busses_out(chip); 178062306a36Sopenharmony_ci ucontrol->value.integer.value[3] = num_analog_busses_out(chip); 178162306a36Sopenharmony_ci ucontrol->value.integer.value[4] = num_pipes_out(chip); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci /* Compute the bitmask of the currently valid input clocks */ 178462306a36Sopenharmony_ci detected = detect_input_clocks(chip); 178562306a36Sopenharmony_ci clocks = 0; 178662306a36Sopenharmony_ci src = chip->num_clock_sources - 1; 178762306a36Sopenharmony_ci for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--) 178862306a36Sopenharmony_ci if (detected & (1 << bit)) 178962306a36Sopenharmony_ci for (; src >= 0; src--) 179062306a36Sopenharmony_ci if (bit == chip->clock_source_list[src]) { 179162306a36Sopenharmony_ci clocks |= 1 << src; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci ucontrol->value.integer.value[5] = clocks; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci return 0; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_echo_channels_info = { 180062306a36Sopenharmony_ci .name = "Channels info", 180162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, 180262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 180362306a36Sopenharmony_ci .info = snd_echo_channels_info_info, 180462306a36Sopenharmony_ci .get = snd_echo_channels_info_get, 180562306a36Sopenharmony_ci}; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci/****************************************************************************** 181162306a36Sopenharmony_ci IRQ Handling 181262306a36Sopenharmony_ci******************************************************************************/ 181362306a36Sopenharmony_ci/* Check if a period has elapsed since last interrupt 181462306a36Sopenharmony_ci * 181562306a36Sopenharmony_ci * Don't make any updates to state; PCM core handles this with the 181662306a36Sopenharmony_ci * correct locks. 181762306a36Sopenharmony_ci * 181862306a36Sopenharmony_ci * \return true if a period has elapsed, otherwise false 181962306a36Sopenharmony_ci */ 182062306a36Sopenharmony_cistatic bool period_has_elapsed(struct snd_pcm_substream *substream) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 182362306a36Sopenharmony_ci struct audiopipe *pipe = runtime->private_data; 182462306a36Sopenharmony_ci u32 counter, step; 182562306a36Sopenharmony_ci size_t period_bytes; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci if (pipe->state != PIPE_STATE_STARTED) 182862306a36Sopenharmony_ci return false; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci period_bytes = frames_to_bytes(runtime, runtime->period_size); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci counter = le32_to_cpu(*pipe->dma_counter); /* presumed atomic */ 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci step = counter - pipe->last_period; /* handles wrapping */ 183562306a36Sopenharmony_ci step -= step % period_bytes; /* acknowledge whole periods only */ 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci if (step == 0) 183862306a36Sopenharmony_ci return false; /* haven't advanced a whole period yet */ 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci pipe->last_period += step; /* used exclusively by us */ 184162306a36Sopenharmony_ci return true; 184262306a36Sopenharmony_ci} 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_cistatic irqreturn_t snd_echo_interrupt(int irq, void *dev_id) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci struct echoaudio *chip = dev_id; 184762306a36Sopenharmony_ci int ss, st; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci spin_lock(&chip->lock); 185062306a36Sopenharmony_ci st = service_irq(chip); 185162306a36Sopenharmony_ci if (st < 0) { 185262306a36Sopenharmony_ci spin_unlock(&chip->lock); 185362306a36Sopenharmony_ci return IRQ_NONE; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci /* The hardware doesn't tell us which substream caused the irq, 185662306a36Sopenharmony_ci thus we have to check all running substreams. */ 185762306a36Sopenharmony_ci for (ss = 0; ss < DSP_MAXPIPES; ss++) { 185862306a36Sopenharmony_ci struct snd_pcm_substream *substream; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci substream = chip->substream[ss]; 186162306a36Sopenharmony_ci if (substream && period_has_elapsed(substream)) { 186262306a36Sopenharmony_ci spin_unlock(&chip->lock); 186362306a36Sopenharmony_ci snd_pcm_period_elapsed(substream); 186462306a36Sopenharmony_ci spin_lock(&chip->lock); 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci spin_unlock(&chip->lock); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 187062306a36Sopenharmony_ci if (st > 0 && chip->midi_in) { 187162306a36Sopenharmony_ci snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st); 187262306a36Sopenharmony_ci dev_dbg(chip->card->dev, "rawmidi_iread=%d\n", st); 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci#endif 187562306a36Sopenharmony_ci return IRQ_HANDLED; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci/****************************************************************************** 188262306a36Sopenharmony_ci Module construction / destruction 188362306a36Sopenharmony_ci******************************************************************************/ 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_cistatic void snd_echo_free(struct snd_card *card) 188662306a36Sopenharmony_ci{ 188762306a36Sopenharmony_ci struct echoaudio *chip = card->private_data; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci if (chip->comm_page) 189062306a36Sopenharmony_ci rest_in_peace(chip); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (chip->irq >= 0) 189362306a36Sopenharmony_ci free_irq(chip->irq, chip); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci /* release chip data */ 189662306a36Sopenharmony_ci free_firmware_cache(chip); 189762306a36Sopenharmony_ci} 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci/* <--snd_echo_probe() */ 190062306a36Sopenharmony_cistatic int snd_echo_create(struct snd_card *card, 190162306a36Sopenharmony_ci struct pci_dev *pci) 190262306a36Sopenharmony_ci{ 190362306a36Sopenharmony_ci struct echoaudio *chip = card->private_data; 190462306a36Sopenharmony_ci int err; 190562306a36Sopenharmony_ci size_t sz; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci err = pcim_enable_device(pci); 191062306a36Sopenharmony_ci if (err < 0) 191162306a36Sopenharmony_ci return err; 191262306a36Sopenharmony_ci pci_set_master(pci); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci /* Allocate chip if needed */ 191562306a36Sopenharmony_ci spin_lock_init(&chip->lock); 191662306a36Sopenharmony_ci chip->card = card; 191762306a36Sopenharmony_ci chip->pci = pci; 191862306a36Sopenharmony_ci chip->irq = -1; 191962306a36Sopenharmony_ci chip->opencount = 0; 192062306a36Sopenharmony_ci mutex_init(&chip->mode_mutex); 192162306a36Sopenharmony_ci chip->can_set_rate = 1; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* PCI resource allocation */ 192462306a36Sopenharmony_ci err = pci_request_regions(pci, ECHOCARD_NAME); 192562306a36Sopenharmony_ci if (err < 0) 192662306a36Sopenharmony_ci return err; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci chip->dsp_registers_phys = pci_resource_start(pci, 0); 192962306a36Sopenharmony_ci sz = pci_resource_len(pci, 0); 193062306a36Sopenharmony_ci if (sz > PAGE_SIZE) 193162306a36Sopenharmony_ci sz = PAGE_SIZE; /* We map only the required part */ 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci chip->dsp_registers = devm_ioremap(&pci->dev, chip->dsp_registers_phys, sz); 193462306a36Sopenharmony_ci if (!chip->dsp_registers) { 193562306a36Sopenharmony_ci dev_err(chip->card->dev, "ioremap failed\n"); 193662306a36Sopenharmony_ci return -ENOMEM; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, 194062306a36Sopenharmony_ci KBUILD_MODNAME, chip)) { 194162306a36Sopenharmony_ci dev_err(chip->card->dev, "cannot grab irq\n"); 194262306a36Sopenharmony_ci return -EBUSY; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci chip->irq = pci->irq; 194562306a36Sopenharmony_ci card->sync_irq = chip->irq; 194662306a36Sopenharmony_ci dev_dbg(card->dev, "pci=%p irq=%d subdev=%04x Init hardware...\n", 194762306a36Sopenharmony_ci chip->pci, chip->irq, chip->pci->subsystem_device); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci card->private_free = snd_echo_free; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci /* Create the DSP comm page - this is the area of memory used for most 195262306a36Sopenharmony_ci of the communication with the DSP, which accesses it via bus mastering */ 195362306a36Sopenharmony_ci chip->commpage_dma_buf = 195462306a36Sopenharmony_ci snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, 195562306a36Sopenharmony_ci sizeof(struct comm_page)); 195662306a36Sopenharmony_ci if (!chip->commpage_dma_buf) 195762306a36Sopenharmony_ci return -ENOMEM; 195862306a36Sopenharmony_ci chip->comm_page_phys = chip->commpage_dma_buf->addr; 195962306a36Sopenharmony_ci chip->comm_page = (struct comm_page *)chip->commpage_dma_buf->area; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); 196262306a36Sopenharmony_ci if (err >= 0) 196362306a36Sopenharmony_ci err = set_mixer_defaults(chip); 196462306a36Sopenharmony_ci if (err < 0) { 196562306a36Sopenharmony_ci dev_err(card->dev, "init_hw err=%d\n", err); 196662306a36Sopenharmony_ci return err; 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci return 0; 197062306a36Sopenharmony_ci} 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci/* constructor */ 197362306a36Sopenharmony_cistatic int __snd_echo_probe(struct pci_dev *pci, 197462306a36Sopenharmony_ci const struct pci_device_id *pci_id) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci static int dev; 197762306a36Sopenharmony_ci struct snd_card *card; 197862306a36Sopenharmony_ci struct echoaudio *chip; 197962306a36Sopenharmony_ci char *dsp; 198062306a36Sopenharmony_ci __maybe_unused int i; 198162306a36Sopenharmony_ci int err; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (dev >= SNDRV_CARDS) 198462306a36Sopenharmony_ci return -ENODEV; 198562306a36Sopenharmony_ci if (!enable[dev]) { 198662306a36Sopenharmony_ci dev++; 198762306a36Sopenharmony_ci return -ENOENT; 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci i = 0; 199162306a36Sopenharmony_ci err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 199262306a36Sopenharmony_ci sizeof(*chip), &card); 199362306a36Sopenharmony_ci if (err < 0) 199462306a36Sopenharmony_ci return err; 199562306a36Sopenharmony_ci chip = card->private_data; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci err = snd_echo_create(card, pci); 199862306a36Sopenharmony_ci if (err < 0) 199962306a36Sopenharmony_ci return err; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci strcpy(card->driver, "Echo_" ECHOCARD_NAME); 200262306a36Sopenharmony_ci strcpy(card->shortname, chip->card_name); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci dsp = "56301"; 200562306a36Sopenharmony_ci if (pci_id->device == 0x3410) 200662306a36Sopenharmony_ci dsp = "56361"; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i", 200962306a36Sopenharmony_ci card->shortname, pci_id->subdevice & 0x000f, dsp, 201062306a36Sopenharmony_ci chip->dsp_registers_phys, chip->irq); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci err = snd_echo_new_pcm(chip); 201362306a36Sopenharmony_ci if (err < 0) { 201462306a36Sopenharmony_ci dev_err(chip->card->dev, "new pcm error %d\n", err); 201562306a36Sopenharmony_ci return err; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 201962306a36Sopenharmony_ci if (chip->has_midi) { /* Some Mia's do not have midi */ 202062306a36Sopenharmony_ci err = snd_echo_midi_create(card, chip); 202162306a36Sopenharmony_ci if (err < 0) { 202262306a36Sopenharmony_ci dev_err(chip->card->dev, "new midi error %d\n", err); 202362306a36Sopenharmony_ci return err; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci#endif 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_VMIXER 202962306a36Sopenharmony_ci snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip); 203062306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip)); 203162306a36Sopenharmony_ci if (err < 0) 203262306a36Sopenharmony_ci return err; 203362306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_LINE_OUT_GAIN 203462306a36Sopenharmony_ci err = snd_ctl_add(chip->card, 203562306a36Sopenharmony_ci snd_ctl_new1(&snd_echo_line_output_gain, chip)); 203662306a36Sopenharmony_ci if (err < 0) 203762306a36Sopenharmony_ci return err; 203862306a36Sopenharmony_ci#endif 203962306a36Sopenharmony_ci#else /* ECHOCARD_HAS_VMIXER */ 204062306a36Sopenharmony_ci err = snd_ctl_add(chip->card, 204162306a36Sopenharmony_ci snd_ctl_new1(&snd_echo_pcm_output_gain, chip)); 204262306a36Sopenharmony_ci if (err < 0) 204362306a36Sopenharmony_ci return err; 204462306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_VMIXER */ 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_INPUT_GAIN 204762306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip)); 204862306a36Sopenharmony_ci if (err < 0) 204962306a36Sopenharmony_ci return err; 205062306a36Sopenharmony_ci#endif 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL 205362306a36Sopenharmony_ci if (!chip->hasnt_input_nominal_level) { 205462306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip)); 205562306a36Sopenharmony_ci if (err < 0) 205662306a36Sopenharmony_ci return err; 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci#endif 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL 206162306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip)); 206262306a36Sopenharmony_ci if (err < 0) 206362306a36Sopenharmony_ci return err; 206462306a36Sopenharmony_ci#endif 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip)); 206762306a36Sopenharmony_ci if (err < 0) 206862306a36Sopenharmony_ci return err; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip)); 207162306a36Sopenharmony_ci if (err < 0) 207262306a36Sopenharmony_ci return err; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MONITOR 207562306a36Sopenharmony_ci snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip); 207662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip)); 207762306a36Sopenharmony_ci if (err < 0) 207862306a36Sopenharmony_ci return err; 207962306a36Sopenharmony_ci#endif 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE 208262306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip)); 208362306a36Sopenharmony_ci if (err < 0) 208462306a36Sopenharmony_ci return err; 208562306a36Sopenharmony_ci#endif 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip)); 208862306a36Sopenharmony_ci if (err < 0) 208962306a36Sopenharmony_ci return err; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH 209262306a36Sopenharmony_ci /* Creates a list of available digital modes */ 209362306a36Sopenharmony_ci chip->num_digital_modes = 0; 209462306a36Sopenharmony_ci for (i = 0; i < 6; i++) 209562306a36Sopenharmony_ci if (chip->digital_modes & (1 << i)) 209662306a36Sopenharmony_ci chip->digital_mode_list[chip->num_digital_modes++] = i; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip)); 209962306a36Sopenharmony_ci if (err < 0) 210062306a36Sopenharmony_ci return err; 210162306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */ 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK 210462306a36Sopenharmony_ci /* Creates a list of available clock sources */ 210562306a36Sopenharmony_ci chip->num_clock_sources = 0; 210662306a36Sopenharmony_ci for (i = 0; i < 10; i++) 210762306a36Sopenharmony_ci if (chip->input_clock_types & (1 << i)) 210862306a36Sopenharmony_ci chip->clock_source_list[chip->num_clock_sources++] = i; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci if (chip->num_clock_sources > 1) { 211162306a36Sopenharmony_ci chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip); 211262306a36Sopenharmony_ci err = snd_ctl_add(chip->card, chip->clock_src_ctl); 211362306a36Sopenharmony_ci if (err < 0) 211462306a36Sopenharmony_ci return err; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_DIGITAL_IO 211962306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip)); 212062306a36Sopenharmony_ci if (err < 0) 212162306a36Sopenharmony_ci return err; 212262306a36Sopenharmony_ci#endif 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_PHANTOM_POWER 212562306a36Sopenharmony_ci if (chip->has_phantom_power) { 212662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip)); 212762306a36Sopenharmony_ci if (err < 0) 212862306a36Sopenharmony_ci return err; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci#endif 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci err = snd_card_register(card); 213362306a36Sopenharmony_ci if (err < 0) 213462306a36Sopenharmony_ci return err; 213562306a36Sopenharmony_ci dev_info(card->dev, "Card registered: %s\n", card->longname); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci pci_set_drvdata(pci, chip); 213862306a36Sopenharmony_ci dev++; 213962306a36Sopenharmony_ci return 0; 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_cistatic int snd_echo_probe(struct pci_dev *pci, 214362306a36Sopenharmony_ci const struct pci_device_id *pci_id) 214462306a36Sopenharmony_ci{ 214562306a36Sopenharmony_ci return snd_card_free_on_error(&pci->dev, __snd_echo_probe(pci, pci_id)); 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic int snd_echo_suspend(struct device *dev) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci struct echoaudio *chip = dev_get_drvdata(dev); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 215662306a36Sopenharmony_ci /* This call can sleep */ 215762306a36Sopenharmony_ci if (chip->midi_out) 215862306a36Sopenharmony_ci snd_echo_midi_output_trigger(chip->midi_out, 0); 215962306a36Sopenharmony_ci#endif 216062306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 216162306a36Sopenharmony_ci if (wait_handshake(chip)) { 216262306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 216362306a36Sopenharmony_ci return -EIO; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci clear_handshake(chip); 216662306a36Sopenharmony_ci if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { 216762306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 216862306a36Sopenharmony_ci return -EIO; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci chip->dsp_code = NULL; 217362306a36Sopenharmony_ci free_irq(chip->irq, chip); 217462306a36Sopenharmony_ci chip->irq = -1; 217562306a36Sopenharmony_ci chip->card->sync_irq = -1; 217662306a36Sopenharmony_ci return 0; 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_cistatic int snd_echo_resume(struct device *dev) 218262306a36Sopenharmony_ci{ 218362306a36Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 218462306a36Sopenharmony_ci struct echoaudio *chip = dev_get_drvdata(dev); 218562306a36Sopenharmony_ci struct comm_page *commpage, *commpage_bak; 218662306a36Sopenharmony_ci u32 pipe_alloc_mask; 218762306a36Sopenharmony_ci int err; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci commpage = chip->comm_page; 219062306a36Sopenharmony_ci commpage_bak = kmemdup(commpage, sizeof(*commpage), GFP_KERNEL); 219162306a36Sopenharmony_ci if (commpage_bak == NULL) 219262306a36Sopenharmony_ci return -ENOMEM; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); 219562306a36Sopenharmony_ci if (err < 0) { 219662306a36Sopenharmony_ci kfree(commpage_bak); 219762306a36Sopenharmony_ci dev_err(dev, "resume init_hw err=%d\n", err); 219862306a36Sopenharmony_ci return err; 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci /* Temporarily set chip->pipe_alloc_mask=0 otherwise 220262306a36Sopenharmony_ci * restore_dsp_settings() fails. 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ci pipe_alloc_mask = chip->pipe_alloc_mask; 220562306a36Sopenharmony_ci chip->pipe_alloc_mask = 0; 220662306a36Sopenharmony_ci err = restore_dsp_rettings(chip); 220762306a36Sopenharmony_ci chip->pipe_alloc_mask = pipe_alloc_mask; 220862306a36Sopenharmony_ci if (err < 0) { 220962306a36Sopenharmony_ci kfree(commpage_bak); 221062306a36Sopenharmony_ci return err; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci memcpy(&commpage->audio_format, &commpage_bak->audio_format, 221462306a36Sopenharmony_ci sizeof(commpage->audio_format)); 221562306a36Sopenharmony_ci memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, 221662306a36Sopenharmony_ci sizeof(commpage->sglist_addr)); 221762306a36Sopenharmony_ci memcpy(&commpage->midi_output, &commpage_bak->midi_output, 221862306a36Sopenharmony_ci sizeof(commpage->midi_output)); 221962306a36Sopenharmony_ci kfree(commpage_bak); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, 222262306a36Sopenharmony_ci KBUILD_MODNAME, chip)) { 222362306a36Sopenharmony_ci dev_err(chip->card->dev, "cannot grab irq\n"); 222462306a36Sopenharmony_ci return -EBUSY; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci chip->irq = pci->irq; 222762306a36Sopenharmony_ci chip->card->sync_irq = chip->irq; 222862306a36Sopenharmony_ci dev_dbg(dev, "resume irq=%d\n", chip->irq); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci#ifdef ECHOCARD_HAS_MIDI 223162306a36Sopenharmony_ci if (chip->midi_input_enabled) 223262306a36Sopenharmony_ci enable_midi_input(chip, true); 223362306a36Sopenharmony_ci if (chip->midi_out) 223462306a36Sopenharmony_ci snd_echo_midi_output_trigger(chip->midi_out, 1); 223562306a36Sopenharmony_ci#endif 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci return 0; 223862306a36Sopenharmony_ci} 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume); 224162306a36Sopenharmony_ci#define SND_ECHO_PM_OPS &snd_echo_pm 224262306a36Sopenharmony_ci#else 224362306a36Sopenharmony_ci#define SND_ECHO_PM_OPS NULL 224462306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci/****************************************************************************** 224762306a36Sopenharmony_ci Everything starts and ends here 224862306a36Sopenharmony_ci******************************************************************************/ 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci/* pci_driver definition */ 225162306a36Sopenharmony_cistatic struct pci_driver echo_driver = { 225262306a36Sopenharmony_ci .name = KBUILD_MODNAME, 225362306a36Sopenharmony_ci .id_table = snd_echo_ids, 225462306a36Sopenharmony_ci .probe = snd_echo_probe, 225562306a36Sopenharmony_ci .driver = { 225662306a36Sopenharmony_ci .pm = SND_ECHO_PM_OPS, 225762306a36Sopenharmony_ci }, 225862306a36Sopenharmony_ci}; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_cimodule_pci_driver(echo_driver); 2261