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

dice-pcm.c (11848B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * dice_pcm.c - a part of driver for DICE based devices
      4 *
      5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
      6 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
      7 */
      8
      9#include "dice.h"
     10
     11static int dice_rate_constraint(struct snd_pcm_hw_params *params,
     12				struct snd_pcm_hw_rule *rule)
     13{
     14	struct snd_pcm_substream *substream = rule->private;
     15	struct snd_dice *dice = substream->private_data;
     16	unsigned int index = substream->pcm->device;
     17
     18	const struct snd_interval *c =
     19		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
     20	struct snd_interval *r =
     21		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
     22	struct snd_interval rates = {
     23		.min = UINT_MAX, .max = 0, .integer = 1
     24	};
     25	unsigned int *pcm_channels;
     26	enum snd_dice_rate_mode mode;
     27	unsigned int i, rate;
     28
     29	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
     30		pcm_channels = dice->tx_pcm_chs[index];
     31	else
     32		pcm_channels = dice->rx_pcm_chs[index];
     33
     34	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
     35		rate = snd_dice_rates[i];
     36		if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
     37			continue;
     38
     39		if (!snd_interval_test(c, pcm_channels[mode]))
     40			continue;
     41
     42		rates.min = min(rates.min, rate);
     43		rates.max = max(rates.max, rate);
     44	}
     45
     46	return snd_interval_refine(r, &rates);
     47}
     48
     49static int dice_channels_constraint(struct snd_pcm_hw_params *params,
     50				    struct snd_pcm_hw_rule *rule)
     51{
     52	struct snd_pcm_substream *substream = rule->private;
     53	struct snd_dice *dice = substream->private_data;
     54	unsigned int index = substream->pcm->device;
     55
     56	const struct snd_interval *r =
     57		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
     58	struct snd_interval *c =
     59		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
     60	struct snd_interval channels = {
     61		.min = UINT_MAX, .max = 0, .integer = 1
     62	};
     63	unsigned int *pcm_channels;
     64	enum snd_dice_rate_mode mode;
     65	unsigned int i, rate;
     66
     67	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
     68		pcm_channels = dice->tx_pcm_chs[index];
     69	else
     70		pcm_channels = dice->rx_pcm_chs[index];
     71
     72	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
     73		rate = snd_dice_rates[i];
     74		if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
     75			continue;
     76
     77		if (!snd_interval_test(r, rate))
     78			continue;
     79
     80		channels.min = min(channels.min, pcm_channels[mode]);
     81		channels.max = max(channels.max, pcm_channels[mode]);
     82	}
     83
     84	return snd_interval_refine(c, &channels);
     85}
     86
     87static int limit_channels_and_rates(struct snd_dice *dice,
     88				    struct snd_pcm_runtime *runtime,
     89				    enum amdtp_stream_direction dir,
     90				    unsigned int index)
     91{
     92	struct snd_pcm_hardware *hw = &runtime->hw;
     93	unsigned int *pcm_channels;
     94	unsigned int i;
     95
     96	if (dir == AMDTP_IN_STREAM)
     97		pcm_channels = dice->tx_pcm_chs[index];
     98	else
     99		pcm_channels = dice->rx_pcm_chs[index];
    100
    101	hw->channels_min = UINT_MAX;
    102	hw->channels_max = 0;
    103
    104	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
    105		enum snd_dice_rate_mode mode;
    106		unsigned int rate, channels;
    107
    108		rate = snd_dice_rates[i];
    109		if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
    110			continue;
    111		hw->rates |= snd_pcm_rate_to_rate_bit(rate);
    112
    113		channels = pcm_channels[mode];
    114		if (channels == 0)
    115			continue;
    116		hw->channels_min = min(hw->channels_min, channels);
    117		hw->channels_max = max(hw->channels_max, channels);
    118	}
    119
    120	snd_pcm_limit_hw_rates(runtime);
    121
    122	return 0;
    123}
    124
    125static int init_hw_info(struct snd_dice *dice,
    126			struct snd_pcm_substream *substream)
    127{
    128	struct snd_pcm_runtime *runtime = substream->runtime;
    129	struct snd_pcm_hardware *hw = &runtime->hw;
    130	unsigned int index = substream->pcm->device;
    131	enum amdtp_stream_direction dir;
    132	struct amdtp_stream *stream;
    133	int err;
    134
    135	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
    136		hw->formats = AM824_IN_PCM_FORMAT_BITS;
    137		dir = AMDTP_IN_STREAM;
    138		stream = &dice->tx_stream[index];
    139	} else {
    140		hw->formats = AM824_OUT_PCM_FORMAT_BITS;
    141		dir = AMDTP_OUT_STREAM;
    142		stream = &dice->rx_stream[index];
    143	}
    144
    145	err = limit_channels_and_rates(dice, substream->runtime, dir,
    146				       index);
    147	if (err < 0)
    148		return err;
    149
    150	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    151				  dice_rate_constraint, substream,
    152				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
    153	if (err < 0)
    154		return err;
    155	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
    156				  dice_channels_constraint, substream,
    157				  SNDRV_PCM_HW_PARAM_RATE, -1);
    158	if (err < 0)
    159		return err;
    160
    161	return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
    162}
    163
    164static int pcm_open(struct snd_pcm_substream *substream)
    165{
    166	struct snd_dice *dice = substream->private_data;
    167	struct amdtp_domain *d = &dice->domain;
    168	unsigned int source;
    169	bool internal;
    170	int err;
    171
    172	err = snd_dice_stream_lock_try(dice);
    173	if (err < 0)
    174		return err;
    175
    176	err = init_hw_info(dice, substream);
    177	if (err < 0)
    178		goto err_locked;
    179
    180	err = snd_dice_transaction_get_clock_source(dice, &source);
    181	if (err < 0)
    182		goto err_locked;
    183	switch (source) {
    184	case CLOCK_SOURCE_AES1:
    185	case CLOCK_SOURCE_AES2:
    186	case CLOCK_SOURCE_AES3:
    187	case CLOCK_SOURCE_AES4:
    188	case CLOCK_SOURCE_AES_ANY:
    189	case CLOCK_SOURCE_ADAT:
    190	case CLOCK_SOURCE_TDIF:
    191	case CLOCK_SOURCE_WC:
    192		internal = false;
    193		break;
    194	default:
    195		internal = true;
    196		break;
    197	}
    198
    199	mutex_lock(&dice->mutex);
    200
    201	// When source of clock is not internal or any stream is reserved for
    202	// transmission of PCM frames, the available sampling rate is limited
    203	// at current one.
    204	if (!internal ||
    205	    (dice->substreams_counter > 0 && d->events_per_period > 0)) {
    206		unsigned int frames_per_period = d->events_per_period;
    207		unsigned int frames_per_buffer = d->events_per_buffer;
    208		unsigned int rate;
    209
    210		err = snd_dice_transaction_get_rate(dice, &rate);
    211		if (err < 0) {
    212			mutex_unlock(&dice->mutex);
    213			goto err_locked;
    214		}
    215
    216		substream->runtime->hw.rate_min = rate;
    217		substream->runtime->hw.rate_max = rate;
    218
    219		if (frames_per_period > 0) {
    220			// For double_pcm_frame quirk.
    221			if (rate > 96000 && !dice->disable_double_pcm_frames) {
    222				frames_per_period *= 2;
    223				frames_per_buffer *= 2;
    224			}
    225
    226			err = snd_pcm_hw_constraint_minmax(substream->runtime,
    227					SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
    228					frames_per_period, frames_per_period);
    229			if (err < 0) {
    230				mutex_unlock(&dice->mutex);
    231				goto err_locked;
    232			}
    233
    234			err = snd_pcm_hw_constraint_minmax(substream->runtime,
    235					SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
    236					frames_per_buffer, frames_per_buffer);
    237			if (err < 0) {
    238				mutex_unlock(&dice->mutex);
    239				goto err_locked;
    240			}
    241		}
    242	}
    243
    244	mutex_unlock(&dice->mutex);
    245
    246	snd_pcm_set_sync(substream);
    247
    248	return 0;
    249err_locked:
    250	snd_dice_stream_lock_release(dice);
    251	return err;
    252}
    253
    254static int pcm_close(struct snd_pcm_substream *substream)
    255{
    256	struct snd_dice *dice = substream->private_data;
    257
    258	snd_dice_stream_lock_release(dice);
    259
    260	return 0;
    261}
    262
    263static int pcm_hw_params(struct snd_pcm_substream *substream,
    264			 struct snd_pcm_hw_params *hw_params)
    265{
    266	struct snd_dice *dice = substream->private_data;
    267	int err = 0;
    268
    269	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
    270		unsigned int rate = params_rate(hw_params);
    271		unsigned int events_per_period = params_period_size(hw_params);
    272		unsigned int events_per_buffer = params_buffer_size(hw_params);
    273
    274		mutex_lock(&dice->mutex);
    275		// For double_pcm_frame quirk.
    276		if (rate > 96000 && !dice->disable_double_pcm_frames) {
    277			events_per_period /= 2;
    278			events_per_buffer /= 2;
    279		}
    280		err = snd_dice_stream_reserve_duplex(dice, rate,
    281					events_per_period, events_per_buffer);
    282		if (err >= 0)
    283			++dice->substreams_counter;
    284		mutex_unlock(&dice->mutex);
    285	}
    286
    287	return err;
    288}
    289
    290static int pcm_hw_free(struct snd_pcm_substream *substream)
    291{
    292	struct snd_dice *dice = substream->private_data;
    293
    294	mutex_lock(&dice->mutex);
    295
    296	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
    297		--dice->substreams_counter;
    298
    299	snd_dice_stream_stop_duplex(dice);
    300
    301	mutex_unlock(&dice->mutex);
    302
    303	return 0;
    304}
    305
    306static int capture_prepare(struct snd_pcm_substream *substream)
    307{
    308	struct snd_dice *dice = substream->private_data;
    309	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
    310	int err;
    311
    312	mutex_lock(&dice->mutex);
    313	err = snd_dice_stream_start_duplex(dice);
    314	mutex_unlock(&dice->mutex);
    315	if (err >= 0)
    316		amdtp_stream_pcm_prepare(stream);
    317
    318	return 0;
    319}
    320static int playback_prepare(struct snd_pcm_substream *substream)
    321{
    322	struct snd_dice *dice = substream->private_data;
    323	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
    324	int err;
    325
    326	mutex_lock(&dice->mutex);
    327	err = snd_dice_stream_start_duplex(dice);
    328	mutex_unlock(&dice->mutex);
    329	if (err >= 0)
    330		amdtp_stream_pcm_prepare(stream);
    331
    332	return err;
    333}
    334
    335static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
    336{
    337	struct snd_dice *dice = substream->private_data;
    338	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
    339
    340	switch (cmd) {
    341	case SNDRV_PCM_TRIGGER_START:
    342		amdtp_stream_pcm_trigger(stream, substream);
    343		break;
    344	case SNDRV_PCM_TRIGGER_STOP:
    345		amdtp_stream_pcm_trigger(stream, NULL);
    346		break;
    347	default:
    348		return -EINVAL;
    349	}
    350
    351	return 0;
    352}
    353static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
    354{
    355	struct snd_dice *dice = substream->private_data;
    356	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
    357
    358	switch (cmd) {
    359	case SNDRV_PCM_TRIGGER_START:
    360		amdtp_stream_pcm_trigger(stream, substream);
    361		break;
    362	case SNDRV_PCM_TRIGGER_STOP:
    363		amdtp_stream_pcm_trigger(stream, NULL);
    364		break;
    365	default:
    366		return -EINVAL;
    367	}
    368
    369	return 0;
    370}
    371
    372static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
    373{
    374	struct snd_dice *dice = substream->private_data;
    375	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
    376
    377	return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
    378}
    379static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
    380{
    381	struct snd_dice *dice = substream->private_data;
    382	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
    383
    384	return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
    385}
    386
    387static int capture_ack(struct snd_pcm_substream *substream)
    388{
    389	struct snd_dice *dice = substream->private_data;
    390	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
    391
    392	return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
    393}
    394
    395static int playback_ack(struct snd_pcm_substream *substream)
    396{
    397	struct snd_dice *dice = substream->private_data;
    398	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
    399
    400	return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
    401}
    402
    403int snd_dice_create_pcm(struct snd_dice *dice)
    404{
    405	static const struct snd_pcm_ops capture_ops = {
    406		.open      = pcm_open,
    407		.close     = pcm_close,
    408		.hw_params = pcm_hw_params,
    409		.hw_free   = pcm_hw_free,
    410		.prepare   = capture_prepare,
    411		.trigger   = capture_trigger,
    412		.pointer   = capture_pointer,
    413		.ack       = capture_ack,
    414	};
    415	static const struct snd_pcm_ops playback_ops = {
    416		.open      = pcm_open,
    417		.close     = pcm_close,
    418		.hw_params = pcm_hw_params,
    419		.hw_free   = pcm_hw_free,
    420		.prepare   = playback_prepare,
    421		.trigger   = playback_trigger,
    422		.pointer   = playback_pointer,
    423		.ack       = playback_ack,
    424	};
    425	struct snd_pcm *pcm;
    426	unsigned int capture, playback;
    427	int i, j;
    428	int err;
    429
    430	for (i = 0; i < MAX_STREAMS; i++) {
    431		capture = playback = 0;
    432		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) {
    433			if (dice->tx_pcm_chs[i][j] > 0)
    434				capture = 1;
    435			if (dice->rx_pcm_chs[i][j] > 0)
    436				playback = 1;
    437		}
    438
    439		err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
    440				  &pcm);
    441		if (err < 0)
    442			return err;
    443		pcm->private_data = dice;
    444		strcpy(pcm->name, dice->card->shortname);
    445
    446		if (capture > 0)
    447			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
    448					&capture_ops);
    449
    450		if (playback > 0)
    451			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
    452					&playback_ops);
    453
    454		snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
    455					       NULL, 0, 0);
    456	}
    457
    458	return 0;
    459}