cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ff-pcm.c (9820B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ff-pcm.c - a part of driver for RME Fireface series
      4 *
      5 * Copyright (c) 2015-2017 Takashi Sakamoto
      6 */
      7
      8#include "ff.h"
      9
     10static int hw_rule_rate(struct snd_pcm_hw_params *params,
     11			struct snd_pcm_hw_rule *rule)
     12{
     13	const unsigned int *pcm_channels = rule->private;
     14	struct snd_interval *r =
     15		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
     16	const struct snd_interval *c =
     17		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
     18	struct snd_interval t = {
     19		.min = UINT_MAX, .max = 0, .integer = 1
     20	};
     21	unsigned int i;
     22
     23	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
     24		enum snd_ff_stream_mode mode;
     25		int err;
     26
     27		err = snd_ff_stream_get_multiplier_mode(i, &mode);
     28		if (err < 0)
     29			continue;
     30
     31		if (!snd_interval_test(c, pcm_channels[mode]))
     32			continue;
     33
     34		t.min = min(t.min, amdtp_rate_table[i]);
     35		t.max = max(t.max, amdtp_rate_table[i]);
     36	}
     37
     38	return snd_interval_refine(r, &t);
     39}
     40
     41static int hw_rule_channels(struct snd_pcm_hw_params *params,
     42			    struct snd_pcm_hw_rule *rule)
     43{
     44	const unsigned int *pcm_channels = rule->private;
     45	struct snd_interval *c =
     46		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
     47	const struct snd_interval *r =
     48		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
     49	struct snd_interval t = {
     50		.min = UINT_MAX, .max = 0, .integer = 1
     51	};
     52	unsigned int i;
     53
     54	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
     55		enum snd_ff_stream_mode mode;
     56		int err;
     57
     58		err = snd_ff_stream_get_multiplier_mode(i, &mode);
     59		if (err < 0)
     60			continue;
     61
     62		if (!snd_interval_test(r, amdtp_rate_table[i]))
     63			continue;
     64
     65		t.min = min(t.min, pcm_channels[mode]);
     66		t.max = max(t.max, pcm_channels[mode]);
     67	}
     68
     69	return snd_interval_refine(c, &t);
     70}
     71
     72static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
     73				     const unsigned int *pcm_channels)
     74{
     75	unsigned int rate, channels;
     76	int i;
     77
     78	hw->channels_min = UINT_MAX;
     79	hw->channels_max = 0;
     80	hw->rate_min = UINT_MAX;
     81	hw->rate_max = 0;
     82
     83	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
     84		enum snd_ff_stream_mode mode;
     85		int err;
     86
     87		err = snd_ff_stream_get_multiplier_mode(i, &mode);
     88		if (err < 0)
     89			continue;
     90
     91		channels = pcm_channels[mode];
     92		if (pcm_channels[mode] == 0)
     93			continue;
     94		hw->channels_min = min(hw->channels_min, channels);
     95		hw->channels_max = max(hw->channels_max, channels);
     96
     97		rate = amdtp_rate_table[i];
     98		hw->rates |= snd_pcm_rate_to_rate_bit(rate);
     99		hw->rate_min = min(hw->rate_min, rate);
    100		hw->rate_max = max(hw->rate_max, rate);
    101	}
    102}
    103
    104static int pcm_init_hw_params(struct snd_ff *ff,
    105			      struct snd_pcm_substream *substream)
    106{
    107	struct snd_pcm_runtime *runtime = substream->runtime;
    108	struct amdtp_stream *s;
    109	const unsigned int *pcm_channels;
    110	int err;
    111
    112	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
    113		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
    114		s = &ff->tx_stream;
    115		pcm_channels = ff->spec->pcm_capture_channels;
    116	} else {
    117		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
    118		s = &ff->rx_stream;
    119		pcm_channels = ff->spec->pcm_playback_channels;
    120	}
    121
    122	limit_channels_and_rates(&runtime->hw, pcm_channels);
    123
    124	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
    125				  hw_rule_channels, (void *)pcm_channels,
    126				  SNDRV_PCM_HW_PARAM_RATE, -1);
    127	if (err < 0)
    128		return err;
    129
    130	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    131				  hw_rule_rate, (void *)pcm_channels,
    132				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
    133	if (err < 0)
    134		return err;
    135
    136	return amdtp_ff_add_pcm_hw_constraints(s, runtime);
    137}
    138
    139static int pcm_open(struct snd_pcm_substream *substream)
    140{
    141	struct snd_ff *ff = substream->private_data;
    142	struct amdtp_domain *d = &ff->domain;
    143	unsigned int rate;
    144	enum snd_ff_clock_src src;
    145	int i, err;
    146
    147	err = snd_ff_stream_lock_try(ff);
    148	if (err < 0)
    149		return err;
    150
    151	err = pcm_init_hw_params(ff, substream);
    152	if (err < 0)
    153		goto release_lock;
    154
    155	err = ff->spec->protocol->get_clock(ff, &rate, &src);
    156	if (err < 0)
    157		goto release_lock;
    158
    159	mutex_lock(&ff->mutex);
    160
    161	// When source of clock is not internal or any stream is reserved for
    162	// transmission of PCM frames, the available sampling rate is limited
    163	// at current one.
    164	if (src != SND_FF_CLOCK_SRC_INTERNAL) {
    165		for (i = 0; i < CIP_SFC_COUNT; ++i) {
    166			if (amdtp_rate_table[i] == rate)
    167				break;
    168		}
    169
    170		// The unit is configured at sampling frequency which packet
    171		// streaming engine can't support.
    172		if (i >= CIP_SFC_COUNT) {
    173			mutex_unlock(&ff->mutex);
    174			err = -EIO;
    175			goto release_lock;
    176		}
    177
    178		substream->runtime->hw.rate_min = rate;
    179		substream->runtime->hw.rate_max = rate;
    180	} else {
    181		if (ff->substreams_counter > 0) {
    182			unsigned int frames_per_period = d->events_per_period;
    183			unsigned int frames_per_buffer = d->events_per_buffer;
    184
    185			rate = amdtp_rate_table[ff->rx_stream.sfc];
    186			substream->runtime->hw.rate_min = rate;
    187			substream->runtime->hw.rate_max = rate;
    188
    189			err = snd_pcm_hw_constraint_minmax(substream->runtime,
    190					SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
    191					frames_per_period, frames_per_period);
    192			if (err < 0) {
    193				mutex_unlock(&ff->mutex);
    194				goto release_lock;
    195			}
    196
    197			err = snd_pcm_hw_constraint_minmax(substream->runtime,
    198					SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
    199					frames_per_buffer, frames_per_buffer);
    200			if (err < 0) {
    201				mutex_unlock(&ff->mutex);
    202				goto release_lock;
    203			}
    204		}
    205	}
    206
    207	mutex_unlock(&ff->mutex);
    208
    209	snd_pcm_set_sync(substream);
    210
    211	return 0;
    212
    213release_lock:
    214	snd_ff_stream_lock_release(ff);
    215	return err;
    216}
    217
    218static int pcm_close(struct snd_pcm_substream *substream)
    219{
    220	struct snd_ff *ff = substream->private_data;
    221
    222	snd_ff_stream_lock_release(ff);
    223
    224	return 0;
    225}
    226
    227static int pcm_hw_params(struct snd_pcm_substream *substream,
    228			 struct snd_pcm_hw_params *hw_params)
    229{
    230	struct snd_ff *ff = substream->private_data;
    231	int err = 0;
    232
    233	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
    234		unsigned int rate = params_rate(hw_params);
    235		unsigned int frames_per_period = params_period_size(hw_params);
    236		unsigned int frames_per_buffer = params_buffer_size(hw_params);
    237
    238		mutex_lock(&ff->mutex);
    239		err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
    240						   frames_per_buffer);
    241		if (err >= 0)
    242			++ff->substreams_counter;
    243		mutex_unlock(&ff->mutex);
    244	}
    245
    246	return err;
    247}
    248
    249static int pcm_hw_free(struct snd_pcm_substream *substream)
    250{
    251	struct snd_ff *ff = substream->private_data;
    252
    253	mutex_lock(&ff->mutex);
    254
    255	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
    256		--ff->substreams_counter;
    257
    258	snd_ff_stream_stop_duplex(ff);
    259
    260	mutex_unlock(&ff->mutex);
    261
    262	return 0;
    263}
    264
    265static int pcm_capture_prepare(struct snd_pcm_substream *substream)
    266{
    267	struct snd_ff *ff = substream->private_data;
    268	struct snd_pcm_runtime *runtime = substream->runtime;
    269	int err;
    270
    271	mutex_lock(&ff->mutex);
    272
    273	err = snd_ff_stream_start_duplex(ff, runtime->rate);
    274	if (err >= 0)
    275		amdtp_stream_pcm_prepare(&ff->tx_stream);
    276
    277	mutex_unlock(&ff->mutex);
    278
    279	return err;
    280}
    281
    282static int pcm_playback_prepare(struct snd_pcm_substream *substream)
    283{
    284	struct snd_ff *ff = substream->private_data;
    285	struct snd_pcm_runtime *runtime = substream->runtime;
    286	int err;
    287
    288	mutex_lock(&ff->mutex);
    289
    290	err = snd_ff_stream_start_duplex(ff, runtime->rate);
    291	if (err >= 0)
    292		amdtp_stream_pcm_prepare(&ff->rx_stream);
    293
    294	mutex_unlock(&ff->mutex);
    295
    296	return err;
    297}
    298
    299static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
    300{
    301	struct snd_ff *ff = substream->private_data;
    302
    303	switch (cmd) {
    304	case SNDRV_PCM_TRIGGER_START:
    305		amdtp_stream_pcm_trigger(&ff->tx_stream, substream);
    306		break;
    307	case SNDRV_PCM_TRIGGER_STOP:
    308		amdtp_stream_pcm_trigger(&ff->tx_stream, NULL);
    309		break;
    310	default:
    311		return -EINVAL;
    312	}
    313
    314	return 0;
    315}
    316
    317static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
    318{
    319	struct snd_ff *ff = substream->private_data;
    320
    321	switch (cmd) {
    322	case SNDRV_PCM_TRIGGER_START:
    323		amdtp_stream_pcm_trigger(&ff->rx_stream, substream);
    324		break;
    325	case SNDRV_PCM_TRIGGER_STOP:
    326		amdtp_stream_pcm_trigger(&ff->rx_stream, NULL);
    327		break;
    328	default:
    329		return -EINVAL;
    330	}
    331
    332	return 0;
    333}
    334
    335static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
    336{
    337	struct snd_ff *ff = sbstrm->private_data;
    338
    339	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream);
    340}
    341
    342static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
    343{
    344	struct snd_ff *ff = sbstrm->private_data;
    345
    346	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream);
    347}
    348
    349static int pcm_capture_ack(struct snd_pcm_substream *substream)
    350{
    351	struct snd_ff *ff = substream->private_data;
    352
    353	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream);
    354}
    355
    356static int pcm_playback_ack(struct snd_pcm_substream *substream)
    357{
    358	struct snd_ff *ff = substream->private_data;
    359
    360	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream);
    361}
    362
    363int snd_ff_create_pcm_devices(struct snd_ff *ff)
    364{
    365	static const struct snd_pcm_ops pcm_capture_ops = {
    366		.open		= pcm_open,
    367		.close		= pcm_close,
    368		.hw_params	= pcm_hw_params,
    369		.hw_free	= pcm_hw_free,
    370		.prepare	= pcm_capture_prepare,
    371		.trigger	= pcm_capture_trigger,
    372		.pointer	= pcm_capture_pointer,
    373		.ack		= pcm_capture_ack,
    374	};
    375	static const struct snd_pcm_ops pcm_playback_ops = {
    376		.open		= pcm_open,
    377		.close		= pcm_close,
    378		.hw_params	= pcm_hw_params,
    379		.hw_free	= pcm_hw_free,
    380		.prepare	= pcm_playback_prepare,
    381		.trigger	= pcm_playback_trigger,
    382		.pointer	= pcm_playback_pointer,
    383		.ack		= pcm_playback_ack,
    384	};
    385	struct snd_pcm *pcm;
    386	int err;
    387
    388	err = snd_pcm_new(ff->card, ff->card->driver, 0, 1, 1, &pcm);
    389	if (err < 0)
    390		return err;
    391
    392	pcm->private_data = ff;
    393	snprintf(pcm->name, sizeof(pcm->name),
    394		 "%s PCM", ff->card->shortname);
    395	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
    396	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
    397	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
    398
    399	return 0;
    400}