Path: blob/master/sound/firewire/fireworks/fireworks_pcm.c
26424 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;190191mutex_lock(&efw->mutex);192193// When source of clock is not internal or any stream is reserved for194// transmission of PCM frames, the available sampling rate is limited195// at current one.196if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||197(efw->substreams_counter > 0 && d->events_per_period > 0)) {198unsigned int frames_per_period = d->events_per_period;199unsigned int frames_per_buffer = d->events_per_buffer;200unsigned int sampling_rate;201202err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);203if (err < 0) {204mutex_unlock(&efw->mutex);205goto err_locked;206}207substream->runtime->hw.rate_min = sampling_rate;208substream->runtime->hw.rate_max = sampling_rate;209210if (frames_per_period > 0) {211err = snd_pcm_hw_constraint_minmax(substream->runtime,212SNDRV_PCM_HW_PARAM_PERIOD_SIZE,213frames_per_period, frames_per_period);214if (err < 0) {215mutex_unlock(&efw->mutex);216goto err_locked;217}218219err = snd_pcm_hw_constraint_minmax(substream->runtime,220SNDRV_PCM_HW_PARAM_BUFFER_SIZE,221frames_per_buffer, frames_per_buffer);222if (err < 0) {223mutex_unlock(&efw->mutex);224goto err_locked;225}226}227}228229mutex_unlock(&efw->mutex);230231snd_pcm_set_sync(substream);232233return 0;234err_locked:235snd_efw_stream_lock_release(efw);236return err;237}238239static int pcm_close(struct snd_pcm_substream *substream)240{241struct snd_efw *efw = substream->private_data;242snd_efw_stream_lock_release(efw);243return 0;244}245246static int pcm_hw_params(struct snd_pcm_substream *substream,247struct snd_pcm_hw_params *hw_params)248{249struct snd_efw *efw = substream->private_data;250int err = 0;251252if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {253unsigned int rate = params_rate(hw_params);254unsigned int frames_per_period = params_period_size(hw_params);255unsigned int frames_per_buffer = params_buffer_size(hw_params);256257mutex_lock(&efw->mutex);258err = snd_efw_stream_reserve_duplex(efw, rate,259frames_per_period, frames_per_buffer);260if (err >= 0)261++efw->substreams_counter;262mutex_unlock(&efw->mutex);263}264265return err;266}267268static int pcm_hw_free(struct snd_pcm_substream *substream)269{270struct snd_efw *efw = substream->private_data;271272mutex_lock(&efw->mutex);273274if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)275--efw->substreams_counter;276277snd_efw_stream_stop_duplex(efw);278279mutex_unlock(&efw->mutex);280281return 0;282}283284static int pcm_capture_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->tx_stream);292293return err;294}295static int pcm_playback_prepare(struct snd_pcm_substream *substream)296{297struct snd_efw *efw = substream->private_data;298int err;299300err = snd_efw_stream_start_duplex(efw);301if (err >= 0)302amdtp_stream_pcm_prepare(&efw->rx_stream);303304return err;305}306307static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)308{309struct snd_efw *efw = substream->private_data;310311switch (cmd) {312case SNDRV_PCM_TRIGGER_START:313amdtp_stream_pcm_trigger(&efw->tx_stream, substream);314break;315case SNDRV_PCM_TRIGGER_STOP:316amdtp_stream_pcm_trigger(&efw->tx_stream, NULL);317break;318default:319return -EINVAL;320}321322return 0;323}324static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)325{326struct snd_efw *efw = substream->private_data;327328switch (cmd) {329case SNDRV_PCM_TRIGGER_START:330amdtp_stream_pcm_trigger(&efw->rx_stream, substream);331break;332case SNDRV_PCM_TRIGGER_STOP:333amdtp_stream_pcm_trigger(&efw->rx_stream, NULL);334break;335default:336return -EINVAL;337}338339return 0;340}341342static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)343{344struct snd_efw *efw = sbstrm->private_data;345346return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream);347}348static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)349{350struct snd_efw *efw = sbstrm->private_data;351352return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream);353}354355static int pcm_capture_ack(struct snd_pcm_substream *substream)356{357struct snd_efw *efw = substream->private_data;358359return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream);360}361362static int pcm_playback_ack(struct snd_pcm_substream *substream)363{364struct snd_efw *efw = substream->private_data;365366return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream);367}368369int snd_efw_create_pcm_devices(struct snd_efw *efw)370{371static const struct snd_pcm_ops capture_ops = {372.open = pcm_open,373.close = pcm_close,374.hw_params = pcm_hw_params,375.hw_free = pcm_hw_free,376.prepare = pcm_capture_prepare,377.trigger = pcm_capture_trigger,378.pointer = pcm_capture_pointer,379.ack = pcm_capture_ack,380};381static const struct snd_pcm_ops playback_ops = {382.open = pcm_open,383.close = pcm_close,384.hw_params = pcm_hw_params,385.hw_free = pcm_hw_free,386.prepare = pcm_playback_prepare,387.trigger = pcm_playback_trigger,388.pointer = pcm_playback_pointer,389.ack = pcm_playback_ack,390};391struct snd_pcm *pcm;392int err;393394err = snd_pcm_new(efw->card, efw->card->driver, 0, 1, 1, &pcm);395if (err < 0)396goto end;397398pcm->private_data = efw;399pcm->nonatomic = true;400snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);401snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);402snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);403snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);404end:405return err;406}407408409410