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

soc-compress.c (18366B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// soc-compress.c  --  ALSA SoC Compress
      4//
      5// Copyright (C) 2012 Intel Corp.
      6//
      7// Authors: Namarta Kohli <namartax.kohli@intel.com>
      8//          Ramesh Babu K V <ramesh.babu@linux.intel.com>
      9//          Vinod Koul <vinod.koul@linux.intel.com>
     10
     11#include <linux/kernel.h>
     12#include <linux/init.h>
     13#include <linux/delay.h>
     14#include <linux/slab.h>
     15#include <linux/workqueue.h>
     16#include <sound/core.h>
     17#include <sound/compress_params.h>
     18#include <sound/compress_driver.h>
     19#include <sound/soc.h>
     20#include <sound/initval.h>
     21#include <sound/soc-dpcm.h>
     22#include <sound/soc-link.h>
     23#include <linux/pm_runtime.h>
     24
     25static int snd_soc_compr_components_open(struct snd_compr_stream *cstream)
     26{
     27	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
     28	struct snd_soc_component *component;
     29	int ret = 0;
     30	int i;
     31
     32	for_each_rtd_components(rtd, i, component) {
     33		ret = snd_soc_component_module_get_when_open(component, cstream);
     34		if (ret < 0)
     35			break;
     36
     37		ret = snd_soc_component_compr_open(component, cstream);
     38		if (ret < 0)
     39			break;
     40	}
     41
     42	return ret;
     43}
     44
     45static void snd_soc_compr_components_free(struct snd_compr_stream *cstream,
     46					  int rollback)
     47{
     48	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
     49	struct snd_soc_component *component;
     50	int i;
     51
     52	for_each_rtd_components(rtd, i, component) {
     53		snd_soc_component_compr_free(component, cstream, rollback);
     54		snd_soc_component_module_put_when_close(component, cstream, rollback);
     55	}
     56}
     57
     58static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
     59{
     60	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
     61	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     62	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     63	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
     64
     65	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
     66
     67	if (!rollback)
     68		snd_soc_runtime_deactivate(rtd, stream);
     69
     70	snd_soc_dai_digital_mute(codec_dai, 1, stream);
     71
     72	if (!snd_soc_dai_active(cpu_dai))
     73		cpu_dai->rate = 0;
     74
     75	if (!snd_soc_dai_active(codec_dai))
     76		codec_dai->rate = 0;
     77
     78	snd_soc_link_compr_shutdown(cstream, rollback);
     79
     80	snd_soc_compr_components_free(cstream, rollback);
     81
     82	snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback);
     83
     84	if (!rollback)
     85		snd_soc_dapm_stream_stop(rtd, stream);
     86
     87	mutex_unlock(&rtd->card->pcm_mutex);
     88
     89	snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback);
     90
     91	return 0;
     92}
     93
     94static int soc_compr_free(struct snd_compr_stream *cstream)
     95{
     96	return soc_compr_clean(cstream, 0);
     97}
     98
     99static int soc_compr_open(struct snd_compr_stream *cstream)
    100{
    101	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    102	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    103	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    104	int ret;
    105
    106	ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream);
    107	if (ret < 0)
    108		goto err_no_lock;
    109
    110	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    111
    112	ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
    113	if (ret < 0)
    114		goto err;
    115
    116	ret = snd_soc_compr_components_open(cstream);
    117	if (ret < 0)
    118		goto err;
    119
    120	ret = snd_soc_link_compr_startup(cstream);
    121	if (ret < 0)
    122		goto err;
    123
    124	snd_soc_runtime_activate(rtd, stream);
    125err:
    126	mutex_unlock(&rtd->card->pcm_mutex);
    127err_no_lock:
    128	if (ret < 0)
    129		soc_compr_clean(cstream, 1);
    130
    131	return ret;
    132}
    133
    134static int soc_compr_open_fe(struct snd_compr_stream *cstream)
    135{
    136	struct snd_soc_pcm_runtime *fe = cstream->private_data;
    137	struct snd_pcm_substream *fe_substream =
    138		 fe->pcm->streams[cstream->direction].substream;
    139	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
    140	struct snd_soc_dpcm *dpcm;
    141	struct snd_soc_dapm_widget_list *list;
    142	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    143	int ret;
    144
    145	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
    146	fe->dpcm[stream].runtime = fe_substream->runtime;
    147
    148	ret = dpcm_path_get(fe, stream, &list);
    149	if (ret < 0)
    150		goto be_err;
    151
    152	/* calculate valid and active FE <-> BE dpcms */
    153	dpcm_process_paths(fe, stream, &list, 1);
    154	fe->dpcm[stream].runtime = fe_substream->runtime;
    155
    156	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
    157
    158	ret = dpcm_be_dai_startup(fe, stream);
    159	if (ret < 0) {
    160		/* clean up all links */
    161		for_each_dpcm_be(fe, stream, dpcm)
    162			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
    163
    164		dpcm_be_disconnect(fe, stream);
    165		fe->dpcm[stream].runtime = NULL;
    166		goto out;
    167	}
    168
    169	ret = snd_soc_dai_compr_startup(cpu_dai, cstream);
    170	if (ret < 0)
    171		goto out;
    172
    173	ret = snd_soc_compr_components_open(cstream);
    174	if (ret < 0)
    175		goto open_err;
    176
    177	ret = snd_soc_link_compr_startup(cstream);
    178	if (ret < 0)
    179		goto machine_err;
    180
    181	dpcm_clear_pending_state(fe, stream);
    182	dpcm_path_put(&list);
    183
    184	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
    185	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
    186
    187	mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass);
    188	snd_soc_runtime_activate(fe, stream);
    189	mutex_unlock(&fe->card->pcm_mutex);
    190
    191	mutex_unlock(&fe->card->mutex);
    192
    193	return 0;
    194
    195machine_err:
    196	snd_soc_compr_components_free(cstream, 1);
    197open_err:
    198	snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);
    199out:
    200	dpcm_path_put(&list);
    201be_err:
    202	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
    203	mutex_unlock(&fe->card->mutex);
    204	return ret;
    205}
    206
    207static int soc_compr_free_fe(struct snd_compr_stream *cstream)
    208{
    209	struct snd_soc_pcm_runtime *fe = cstream->private_data;
    210	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
    211	struct snd_soc_dpcm *dpcm;
    212	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    213
    214	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
    215
    216	mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass);
    217	snd_soc_runtime_deactivate(fe, stream);
    218	mutex_unlock(&fe->card->pcm_mutex);
    219
    220	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
    221
    222	dpcm_be_dai_hw_free(fe, stream);
    223
    224	dpcm_be_dai_shutdown(fe, stream);
    225
    226	/* mark FE's links ready to prune */
    227	for_each_dpcm_be(fe, stream, dpcm)
    228		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
    229
    230	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
    231
    232	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
    233	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
    234
    235	dpcm_be_disconnect(fe, stream);
    236
    237	fe->dpcm[stream].runtime = NULL;
    238
    239	snd_soc_link_compr_shutdown(cstream, 0);
    240
    241	snd_soc_compr_components_free(cstream, 0);
    242
    243	snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);
    244
    245	mutex_unlock(&fe->card->mutex);
    246	return 0;
    247}
    248
    249static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
    250{
    251	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    252	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    253	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    254	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    255	int ret;
    256
    257	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    258
    259	ret = snd_soc_component_compr_trigger(cstream, cmd);
    260	if (ret < 0)
    261		goto out;
    262
    263	ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
    264	if (ret < 0)
    265		goto out;
    266
    267	switch (cmd) {
    268	case SNDRV_PCM_TRIGGER_START:
    269		snd_soc_dai_digital_mute(codec_dai, 0, stream);
    270		break;
    271	case SNDRV_PCM_TRIGGER_STOP:
    272		snd_soc_dai_digital_mute(codec_dai, 1, stream);
    273		break;
    274	}
    275
    276out:
    277	mutex_unlock(&rtd->card->pcm_mutex);
    278	return ret;
    279}
    280
    281static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
    282{
    283	struct snd_soc_pcm_runtime *fe = cstream->private_data;
    284	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
    285	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    286	int ret;
    287
    288	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
    289	    cmd == SND_COMPR_TRIGGER_DRAIN)
    290		return snd_soc_component_compr_trigger(cstream, cmd);
    291
    292	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
    293
    294	ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd);
    295	if (ret < 0)
    296		goto out;
    297
    298	ret = snd_soc_component_compr_trigger(cstream, cmd);
    299	if (ret < 0)
    300		goto out;
    301
    302	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
    303
    304	ret = dpcm_be_dai_trigger(fe, stream, cmd);
    305
    306	switch (cmd) {
    307	case SNDRV_PCM_TRIGGER_START:
    308	case SNDRV_PCM_TRIGGER_RESUME:
    309	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    310		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
    311		break;
    312	case SNDRV_PCM_TRIGGER_STOP:
    313	case SNDRV_PCM_TRIGGER_SUSPEND:
    314		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
    315		break;
    316	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    317		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
    318		break;
    319	}
    320
    321out:
    322	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
    323	mutex_unlock(&fe->card->mutex);
    324	return ret;
    325}
    326
    327static int soc_compr_set_params(struct snd_compr_stream *cstream,
    328				struct snd_compr_params *params)
    329{
    330	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    331	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    332	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    333	int ret;
    334
    335	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    336
    337	/*
    338	 * First we call set_params for the CPU DAI, then the component
    339	 * driver this should configure the SoC side. If the machine has
    340	 * compressed ops then we call that as well. The expectation is
    341	 * that these callbacks will configure everything for this compress
    342	 * path, like configuring a PCM port for a CODEC.
    343	 */
    344	ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
    345	if (ret < 0)
    346		goto err;
    347
    348	ret = snd_soc_component_compr_set_params(cstream, params);
    349	if (ret < 0)
    350		goto err;
    351
    352	ret = snd_soc_link_compr_set_params(cstream);
    353	if (ret < 0)
    354		goto err;
    355
    356	snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START);
    357
    358	/* cancel any delayed stream shutdown that is pending */
    359	rtd->pop_wait = 0;
    360	mutex_unlock(&rtd->card->pcm_mutex);
    361
    362	cancel_delayed_work_sync(&rtd->delayed_work);
    363
    364	return 0;
    365
    366err:
    367	mutex_unlock(&rtd->card->pcm_mutex);
    368	return ret;
    369}
    370
    371static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
    372				   struct snd_compr_params *params)
    373{
    374	struct snd_soc_pcm_runtime *fe = cstream->private_data;
    375	struct snd_pcm_substream *fe_substream =
    376		 fe->pcm->streams[cstream->direction].substream;
    377	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
    378	int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
    379	int ret;
    380
    381	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
    382
    383	/*
    384	 * Create an empty hw_params for the BE as the machine driver must
    385	 * fix this up to match DSP decoder and ASRC configuration.
    386	 * I.e. machine driver fixup for compressed BE is mandatory.
    387	 */
    388	memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
    389		sizeof(struct snd_pcm_hw_params));
    390
    391	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
    392
    393	ret = dpcm_be_dai_hw_params(fe, stream);
    394	if (ret < 0)
    395		goto out;
    396
    397	ret = dpcm_be_dai_prepare(fe, stream);
    398	if (ret < 0)
    399		goto out;
    400
    401	ret = snd_soc_dai_compr_set_params(cpu_dai, cstream, params);
    402	if (ret < 0)
    403		goto out;
    404
    405	ret = snd_soc_component_compr_set_params(cstream, params);
    406	if (ret < 0)
    407		goto out;
    408
    409	ret = snd_soc_link_compr_set_params(cstream);
    410	if (ret < 0)
    411		goto out;
    412
    413	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
    414	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
    415
    416out:
    417	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
    418	mutex_unlock(&fe->card->mutex);
    419	return ret;
    420}
    421
    422static int soc_compr_get_params(struct snd_compr_stream *cstream,
    423				struct snd_codec *params)
    424{
    425	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    426	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    427	int ret = 0;
    428
    429	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    430
    431	ret = snd_soc_dai_compr_get_params(cpu_dai, cstream, params);
    432	if (ret < 0)
    433		goto err;
    434
    435	ret = snd_soc_component_compr_get_params(cstream, params);
    436err:
    437	mutex_unlock(&rtd->card->pcm_mutex);
    438	return ret;
    439}
    440
    441static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
    442{
    443	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    444	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    445	int ret;
    446
    447	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    448
    449	ret = snd_soc_dai_compr_ack(cpu_dai, cstream, bytes);
    450	if (ret < 0)
    451		goto err;
    452
    453	ret = snd_soc_component_compr_ack(cstream, bytes);
    454err:
    455	mutex_unlock(&rtd->card->pcm_mutex);
    456	return ret;
    457}
    458
    459static int soc_compr_pointer(struct snd_compr_stream *cstream,
    460			     struct snd_compr_tstamp *tstamp)
    461{
    462	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    463	int ret;
    464	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    465
    466	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
    467
    468	ret = snd_soc_dai_compr_pointer(cpu_dai, cstream, tstamp);
    469	if (ret < 0)
    470		goto out;
    471
    472	ret = snd_soc_component_compr_pointer(cstream, tstamp);
    473out:
    474	mutex_unlock(&rtd->card->pcm_mutex);
    475	return ret;
    476}
    477
    478static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
    479				  struct snd_compr_metadata *metadata)
    480{
    481	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    482	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    483	int ret;
    484
    485	ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
    486	if (ret < 0)
    487		return ret;
    488
    489	return snd_soc_component_compr_set_metadata(cstream, metadata);
    490}
    491
    492static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
    493				  struct snd_compr_metadata *metadata)
    494{
    495	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
    496	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    497	int ret;
    498
    499	ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
    500	if (ret < 0)
    501		return ret;
    502
    503	return snd_soc_component_compr_get_metadata(cstream, metadata);
    504}
    505
    506/* ASoC Compress operations */
    507static struct snd_compr_ops soc_compr_ops = {
    508	.open		= soc_compr_open,
    509	.free		= soc_compr_free,
    510	.set_params	= soc_compr_set_params,
    511	.set_metadata   = soc_compr_set_metadata,
    512	.get_metadata	= soc_compr_get_metadata,
    513	.get_params	= soc_compr_get_params,
    514	.trigger	= soc_compr_trigger,
    515	.pointer	= soc_compr_pointer,
    516	.ack		= soc_compr_ack,
    517	.get_caps	= snd_soc_component_compr_get_caps,
    518	.get_codec_caps = snd_soc_component_compr_get_codec_caps,
    519};
    520
    521/* ASoC Dynamic Compress operations */
    522static struct snd_compr_ops soc_compr_dyn_ops = {
    523	.open		= soc_compr_open_fe,
    524	.free		= soc_compr_free_fe,
    525	.set_params	= soc_compr_set_params_fe,
    526	.get_params	= soc_compr_get_params,
    527	.set_metadata   = soc_compr_set_metadata,
    528	.get_metadata	= soc_compr_get_metadata,
    529	.trigger	= soc_compr_trigger_fe,
    530	.pointer	= soc_compr_pointer,
    531	.ack		= soc_compr_ack,
    532	.get_caps	= snd_soc_component_compr_get_caps,
    533	.get_codec_caps = snd_soc_component_compr_get_codec_caps,
    534};
    535
    536/**
    537 * snd_soc_new_compress - create a new compress.
    538 *
    539 * @rtd: The runtime for which we will create compress
    540 * @num: the device index number (zero based - shared with normal PCMs)
    541 *
    542 * Return: 0 for success, else error.
    543 */
    544int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
    545{
    546	struct snd_soc_component *component;
    547	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    548	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    549	struct snd_compr *compr;
    550	struct snd_pcm *be_pcm;
    551	char new_name[64];
    552	int ret = 0, direction = 0;
    553	int playback = 0, capture = 0;
    554	int i;
    555
    556	/*
    557	 * make sure these are same value,
    558	 * and then use these as equally
    559	 */
    560	BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK);
    561	BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE  != (int)SND_COMPRESS_CAPTURE);
    562
    563	if (rtd->num_cpus > 1 ||
    564	    rtd->num_codecs > 1) {
    565		dev_err(rtd->card->dev,
    566			"Compress ASoC: Multi CPU/Codec not supported\n");
    567		return -EINVAL;
    568	}
    569
    570	if (!codec_dai) {
    571		dev_err(rtd->card->dev, "Missing codec\n");
    572		return -EINVAL;
    573	}
    574
    575	/* check client and interface hw capabilities */
    576	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
    577	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_PLAYBACK))
    578		playback = 1;
    579	if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
    580	    snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_CAPTURE))
    581		capture = 1;
    582
    583	/*
    584	 * Compress devices are unidirectional so only one of the directions
    585	 * should be set, check for that (xor)
    586	 */
    587	if (playback + capture != 1) {
    588		dev_err(rtd->card->dev,
    589			"Compress ASoC: Invalid direction for P %d, C %d\n",
    590			playback, capture);
    591		return -EINVAL;
    592	}
    593
    594	if (playback)
    595		direction = SND_COMPRESS_PLAYBACK;
    596	else
    597		direction = SND_COMPRESS_CAPTURE;
    598
    599	compr = devm_kzalloc(rtd->card->dev, sizeof(*compr), GFP_KERNEL);
    600	if (!compr)
    601		return -ENOMEM;
    602
    603	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
    604				  GFP_KERNEL);
    605	if (!compr->ops)
    606		return -ENOMEM;
    607
    608	if (rtd->dai_link->dynamic) {
    609		snprintf(new_name, sizeof(new_name), "(%s)",
    610			rtd->dai_link->stream_name);
    611
    612		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
    613				rtd->dai_link->dpcm_playback,
    614				rtd->dai_link->dpcm_capture, &be_pcm);
    615		if (ret < 0) {
    616			dev_err(rtd->card->dev,
    617				"Compress ASoC: can't create compressed for %s: %d\n",
    618				rtd->dai_link->name, ret);
    619			return ret;
    620		}
    621
    622		rtd->pcm = be_pcm;
    623		rtd->fe_compr = 1;
    624		if (rtd->dai_link->dpcm_playback)
    625			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
    626		else if (rtd->dai_link->dpcm_capture)
    627			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
    628		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
    629	} else {
    630		snprintf(new_name, sizeof(new_name), "%s %s-%d",
    631			rtd->dai_link->stream_name, codec_dai->name, num);
    632
    633		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
    634	}
    635
    636	for_each_rtd_components(rtd, i, component) {
    637		if (!component->driver->compress_ops ||
    638		    !component->driver->compress_ops->copy)
    639			continue;
    640
    641		compr->ops->copy = snd_soc_component_compr_copy;
    642		break;
    643	}
    644
    645	ret = snd_compress_new(rtd->card->snd_card, num, direction,
    646				new_name, compr);
    647	if (ret < 0) {
    648		component = asoc_rtd_to_codec(rtd, 0)->component;
    649		dev_err(component->dev,
    650			"Compress ASoC: can't create compress for codec %s: %d\n",
    651			component->name, ret);
    652		return ret;
    653	}
    654
    655	/* DAPM dai link stream work */
    656	rtd->close_delayed_work_func = snd_soc_close_delayed_work;
    657
    658	rtd->compr = compr;
    659	compr->private_data = rtd;
    660
    661	dev_dbg(rtd->card->dev, "Compress ASoC: %s <-> %s mapping ok\n",
    662		codec_dai->name, cpu_dai->name);
    663
    664	return 0;
    665}
    666EXPORT_SYMBOL_GPL(snd_soc_new_compress);