diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c index 9b2ef351e4f2..30cdda80019c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,7 +29,9 @@ #include "msm-pcm-routing-v2.h" #define LOOPBACK_VOL_MAX_STEPS 0x2000 +#define LOOPBACK_SESSION_MAX 4 +static DEFINE_MUTEX(loopback_session_lock); static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0, LOOPBACK_VOL_MAX_STEPS); @@ -51,7 +53,21 @@ struct msm_pcm_loopback { int volume; }; +struct fe_dai_session_map { + char stream_name[32]; + struct msm_pcm_loopback *loopback_priv; +}; + +static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = { + { {}, NULL}, + { {}, NULL}, + { {}, NULL}, + { {}, NULL}, +}; + static void stop_pcm(struct msm_pcm_loopback *pcm); +static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd, + struct msm_pcm_loopback **pcm); static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event, void *priv_data) @@ -111,18 +127,76 @@ static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume) return rc; } +static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd, + struct msm_pcm_loopback **pcm) +{ + int ret = 0; + int n, index = -1; + + dev_dbg(rtd->platform->dev, "%s: stream %s\n", __func__, + rtd->dai_link->stream_name); + + mutex_lock(&loopback_session_lock); + for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { + if (!strcmp(rtd->dai_link->stream_name, + session_map[n].stream_name)) { + *pcm = session_map[n].loopback_priv; + goto exit; + } + /* + * Store the min index value for allocating a new session. + * Here, if session stream name is not found in the + * existing entries after the loop iteration, then this + * index will be used to allocate the new session. + * This index variable is expected to point to the topmost + * available free session. + */ + if (!(session_map[n].stream_name[0]) && (index < 0)) + index = n; + } + + if (index < 0) { + dev_err(rtd->platform->dev, "%s: Max Sessions allocated\n", + __func__); + ret = -EAGAIN; + goto exit; + } + + session_map[index].loopback_priv = kzalloc( + sizeof(struct msm_pcm_loopback), GFP_KERNEL); + if (!session_map[index].loopback_priv) { + ret = -ENOMEM; + goto exit; + } + + strlcpy(session_map[index].stream_name, + rtd->dai_link->stream_name, + sizeof(session_map[index].stream_name)); + dev_dbg(rtd->platform->dev, "%s: stream %s index %d\n", + __func__, session_map[index].stream_name, index); + + mutex_init(&session_map[index].loopback_priv->lock); + *pcm = session_map[index].loopback_priv; +exit: + mutex_unlock(&loopback_session_lock); + return ret; +} + static int msm_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct msm_pcm_loopback *pcm; + struct msm_pcm_loopback *pcm = NULL; int ret = 0; uint16_t bits_per_sample = 16; struct msm_pcm_routing_evt event; struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; uint32_t param_id; - pcm = dev_get_drvdata(rtd->platform->dev); + ret = msm_pcm_loopback_get_session(rtd, &pcm); + if (ret) + return ret; + mutex_lock(&pcm->lock); pcm->volume = 0x2000; @@ -230,7 +304,8 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct msm_pcm_loopback *pcm = runtime->private_data; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - int ret = 0; + int ret = 0, n; + bool found = false; mutex_lock(&pcm->lock); @@ -247,6 +322,29 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) stop_pcm(pcm); } + if (!pcm->instance) { + mutex_lock(&loopback_session_lock); + for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { + if (!strcmp(rtd->dai_link->stream_name, + session_map[n].stream_name)) { + found = true; + break; + } + } + if (found) { + memset(session_map[n].stream_name, 0, + sizeof(session_map[n].stream_name)); + mutex_unlock(&pcm->lock); + mutex_destroy(&session_map[n].loopback_priv->lock); + session_map[n].loopback_priv = NULL; + kfree(pcm); + dev_dbg(rtd->platform->dev, "%s: stream freed %s\n", + __func__, rtd->dai_link->stream_name); + mutex_unlock(&loopback_session_lock); + return 0; + } + mutex_unlock(&loopback_session_lock); + } mutex_unlock(&pcm->lock); return ret; } @@ -368,33 +466,15 @@ static struct snd_soc_platform_driver msm_soc_platform = { static int msm_pcm_probe(struct platform_device *pdev) { - struct msm_pcm_loopback *pcm; - - dev_dbg(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev)); - pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL); - if (!pcm) { - dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n", - __func__); - return -ENOMEM; - } else { - mutex_init(&pcm->lock); - dev_set_drvdata(&pdev->dev, pcm); - } return snd_soc_register_platform(&pdev->dev, &msm_soc_platform); } static int msm_pcm_remove(struct platform_device *pdev) { - struct msm_pcm_loopback *pcm; - - pcm = dev_get_drvdata(&pdev->dev); - mutex_destroy(&pcm->lock); - kfree(pcm); - snd_soc_unregister_platform(&pdev->dev); return 0; } |