Path: blob/master/sound/firewire/fireworks/fireworks_pcm.c
29269 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* fireworks_pcm.c - a part of driver for Fireworks based devices3*4* Copyright (c) 2009-2010 Clemens Ladisch5* Copyright (c) 2013-2014 Takashi Sakamoto6*/7#include "./fireworks.h"89/*10* NOTE:11* Fireworks changes its AMDTP channels for PCM data according to its sampling12* rate. There are three modes. Here _XX is either _rx or _tx.13* 0: 32.0- 48.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels applied14* 1: 88.2- 96.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_2x applied15* 2: 176.4-192.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_4x applied16*17* The number of PCM channels for analog input and output are always fixed but18* the number of PCM channels for digital input and output are differed.19*20* Additionally, according to "AudioFire Owner's Manual Version 2.2", in some21* model, the number of PCM channels for digital input has more restriction22* depending on which digital interface is selected.23* - S/PDIF coaxial and optical : use input 1-224* - ADAT optical at 32.0-48.0 kHz : use input 1-825* - ADAT optical at 88.2-96.0 kHz : use input 1-4 (S/MUX format)26*27* The data in AMDTP channels for blank PCM channels are zero.28*/29static const unsigned int freq_table[] = {30/* multiplier mode 0 */31[0] = 32000,32[1] = 44100,33[2] = 48000,34/* multiplier mode 1 */35[3] = 88200,36[4] = 96000,37/* multiplier mode 2 */38[5] = 176400,39[6] = 192000,40};4142static inline unsigned int43get_multiplier_mode_with_index(unsigned int index)44{45return ((int)index - 1) / 2;46}4748int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode)49{50unsigned int i;5152for (i = 0; i < ARRAY_SIZE(freq_table); i++) {53if (freq_table[i] == sampling_rate) {54*mode = get_multiplier_mode_with_index(i);55return 0;56}57}5859return -EINVAL;60}6162static int63hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)64{65unsigned int *pcm_channels = rule->private;66struct snd_interval *r =67hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);68const struct snd_interval *c =69hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);70struct snd_interval t = {71.min = UINT_MAX, .max = 0, .integer = 172};73unsigned int i, mode;7475for (i = 0; i < ARRAY_SIZE(freq_table); i++) {76mode = get_multiplier_mode_with_index(i);77if (!snd_interval_test(c, pcm_channels[mode]))78continue;7980t.min = min(t.min, freq_table[i]);81t.max = max(t.max, freq_table[i]);82}8384return snd_interval_refine(r, &t);85}8687static int88hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)89{90unsigned int *pcm_channels = rule->private;91struct snd_interval *c =92hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);93const struct snd_interval *r =94hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);95struct snd_interval t = {96.min = UINT_MAX, .max = 0, .integer = 197};98unsigned int i, mode;99100for (i = 0; i < ARRAY_SIZE(freq_table); i++) {101mode = get_multiplier_mode_with_index(i);102if (!snd_interval_test(r, freq_table[i]))103continue;104105t.min = min(t.min, pcm_channels[mode]);106t.max = max(t.max, pcm_channels[mode]);107}108109return snd_interval_refine(c, &t);110}111112static void113limit_channels(struct snd_pcm_hardware *hw, unsigned int *pcm_channels)114{115unsigned int i, mode;116117hw->channels_min = UINT_MAX;118hw->channels_max = 0;119120for (i = 0; i < ARRAY_SIZE(freq_table); i++) {121mode = get_multiplier_mode_with_index(i);122if (pcm_channels[mode] == 0)123continue;124125hw->channels_min = min(hw->channels_min, pcm_channels[mode]);126hw->channels_max = max(hw->channels_max, pcm_channels[mode]);127}128}129130static int131pcm_init_hw_params(struct snd_efw *efw,132struct snd_pcm_substream *substream)133{134struct snd_pcm_runtime *runtime = substream->runtime;135struct amdtp_stream *s;136unsigned int *pcm_channels;137int err;138139if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {140runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;141s = &efw->tx_stream;142pcm_channels = efw->pcm_capture_channels;143} else {144runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;145s = &efw->rx_stream;146pcm_channels = efw->pcm_playback_channels;147}148149/* limit rates */150runtime->hw.rates = efw->supported_sampling_rate;151snd_pcm_limit_hw_rates(runtime);152153limit_channels(&runtime->hw, pcm_channels);154155err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,156hw_rule_channels, pcm_channels,157SNDRV_PCM_HW_PARAM_RATE, -1);158if (err < 0)159goto end;160161err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,162hw_rule_rate, pcm_channels,163SNDRV_PCM_HW_PARAM_CHANNELS, -1);164if (err < 0)165goto end;166167err = amdtp_am824_add_pcm_hw_constraints(s, runtime);168end:169return err;170}171172static int pcm_open(struct snd_pcm_substream *substream)173{174struct snd_efw *efw = substream->private_data;175struct amdtp_domain *d = &efw->domain;176enum snd_efw_clock_source clock_source;177int err;178179err = snd_efw_stream_lock_try(efw);180if (err < 0)181return err;182183err = pcm_init_hw_params(efw, substream);184if (err < 0)185goto err_locked;186187err = snd_efw_command_get_clock_source(efw, &clock_source);188if (err < 0)189goto err_locked;190191scoped_guard(mutex, &efw->mutex) {192// When source of clock is not internal or any stream is reserved for193// transmission of PCM frames, the available sampling rate is limited194// at current one.195if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||196(efw->substreams_counter > 0 && d->events_per_period > 0)) {197unsigned int frames_per_period = d->events_per_period;198unsigned int frames_per_buffer = d->events_per_buffer;199unsigned int sampling_rate;200201err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);202if (err < 0)203goto err_locked;204substream->runtime->hw.rate_min = sampling_rate;205substream->runtime->hw.rate_max = sampling_rate;206207if (frames_per_period > 0) {208err = snd_pcm_hw_constraint_minmax(substream->runtime,209SNDRV_PCM_HW_PARAM_PERIOD_SIZE,210frames_per_period, frames_per_period);211if (err < 0)212goto err_locked;213214err = snd_pcm_hw_constraint_minmax(substream->runtime,215SNDRV_PCM_HW_PARAM_BUFFER_SIZE,216frames_per_buffer, frames_per_buffer);217if (err < 0)218goto err_locked;219}220}221}222223snd_pcm_set_sync(substream);224225return 0;226err_locked:227snd_efw_stream_lock_release(efw);228return err;229}230231static int pcm_close(struct snd_pcm_substream *substream)232{233struct snd_efw *efw = substream->private_data;234snd_efw_stream_lock_release(efw);235return 0;236}237238static int pcm_hw_params(struct snd_pcm_substream *substream,239struct snd_pcm_hw_params *hw_params)240{241struct snd_efw *efw = substream->private_data;242int err = 0;243244if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {245unsigned int rate = params_rate(hw_params);246unsigned int frames_per_period = params_period_size(hw_params);247unsigned int frames_per_buffer = params_buffer_size(hw_params);248249guard(mutex)(&efw->mutex);250err = snd_efw_stream_reserve_duplex(efw, rate,251frames_per_period, frames_per_buffer);252if (err >= 0)253++efw->substreams_counter;254}255256return err;257}258259static int pcm_hw_free(struct snd_pcm_substream *substream)260{261struct snd_efw *efw = substream->private_data;262263guard(mutex)(&efw->mutex);264265if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)266--efw->substreams_counter;267268snd_efw_stream_stop_duplex(efw);269270return 0;271}272273static int pcm_capture_prepare(struct snd_pcm_substream *substream)274{275struct snd_efw *efw = substream->private_data;276int err;277278err = snd_efw_stream_start_duplex(efw);279if (err >= 0)280amdtp_stream_pcm_prepare(&efw->tx_stream);281282return err;283}284static int pcm_playback_prepare(struct snd_pcm_substream *substream)285{286struct snd_efw *efw = substream->private_data;287int err;288289err = snd_efw_stream_start_duplex(efw);290if (err >= 0)291amdtp_stream_pcm_prepare(&efw->rx_stream);292293return err;294}295296static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)297{298struct snd_efw *efw = substream->private_data;299300switch (cmd) {301case SNDRV_PCM_TRIGGER_START:302amdtp_stream_pcm_trigger(&efw->tx_stream, substream);303break;304case SNDRV_PCM_TRIGGER_STOP:305amdtp_stream_pcm_trigger(&efw->tx_stream, NULL);306break;307default:308return -EINVAL;309}310311return 0;312}313static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)314{315struct snd_efw *efw = substream->private_data;316317switch (cmd) {318case SNDRV_PCM_TRIGGER_START:319amdtp_stream_pcm_trigger(&efw->rx_stream, substream);320break;321case SNDRV_PCM_TRIGGER_STOP:322amdtp_stream_pcm_trigger(&efw->rx_stream, NULL);323break;324default:325return -EINVAL;326}327328return 0;329}330331static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)332{333struct snd_efw *efw = sbstrm->private_data;334335return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream);336}337static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)338{339struct snd_efw *efw = sbstrm->private_data;340341return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream);342}343344static int pcm_capture_ack(struct snd_pcm_substream *substream)345{346struct snd_efw *efw = substream->private_data;347348return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream);349}350351static int pcm_playback_ack(struct snd_pcm_substream *substream)352{353struct snd_efw *efw = substream->private_data;354355return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream);356}357358int snd_efw_create_pcm_devices(struct snd_efw *efw)359{360static const struct snd_pcm_ops capture_ops = {361.open = pcm_open,362.close = pcm_close,363.hw_params = pcm_hw_params,364.hw_free = pcm_hw_free,365.prepare = pcm_capture_prepare,366.trigger = pcm_capture_trigger,367.pointer = pcm_capture_pointer,368.ack = pcm_capture_ack,369};370static const struct snd_pcm_ops playback_ops = {371.open = pcm_open,372.close = pcm_close,373.hw_params = pcm_hw_params,374.hw_free = pcm_hw_free,375.prepare = pcm_playback_prepare,376.trigger = pcm_playback_trigger,377.pointer = pcm_playback_pointer,378.ack = pcm_playback_ack,379};380struct snd_pcm *pcm;381int err;382383err = snd_pcm_new(efw->card, efw->card->driver, 0, 1, 1, &pcm);384if (err < 0)385goto end;386387pcm->private_data = efw;388pcm->nonatomic = true;389snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);390snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);391snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);392snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);393end:394return err;395}396397398399