asoc: msm-pcm: Added lock in controls _put() and _get() callback

There is race condition around private data used in put() and get()
of few mixer ctls with close() callback.Add global mutex lock and
code changes to protect such critical section by accessing such lock.

Change-Id: I276c2a234cfcbef88b4272b945e5c3f121e8eb32
Signed-off-by: Soumya Managoli <smanag@codeaurora.org>
This commit is contained in:
Soumya Managoli 2019-10-03 15:20:42 +05:30 committed by syphyr
parent a858116b07
commit 1fd85fc4b7
2 changed files with 77 additions and 7 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, 2019 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
@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -691,9 +692,18 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
uint32_t timeout;
int dir = 0;
int ret = 0;
struct msm_plat_data *pdata;
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
if (!pdata) {
pr_err("%s: platform data is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&pdata->lock);
if (prtd->audio_client) {
dir = IN;
@ -726,6 +736,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
kfree(prtd);
runtime->private_data = NULL;
mutex_unlock(&pdata->lock);
return 0;
}
@ -817,8 +828,18 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = runtime->private_data;
int dir = OUT;
struct msm_plat_data *pdata;
pr_debug("%s\n", __func__);
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
if (!pdata) {
pr_err("%s: platform data is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&pdata->lock);
if (prtd->audio_client) {
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@ -831,6 +852,7 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
kfree(prtd);
runtime->private_data = NULL;
mutex_unlock(&pdata->lock);
return 0;
}
@ -1002,21 +1024,36 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
struct snd_soc_pcm_runtime *soc_prtd = NULL;
struct msm_plat_data *pdata = NULL;
pr_debug("%s: volume : 0x%x\n", __func__, volume);
if (!substream) {
pr_err("%s substream not found\n", __func__);
pr_err("%s: substream not found\n", __func__);
return -ENODEV;
}
if (!substream->runtime) {
pr_err("%s substream runtime not found\n", __func__);
soc_prtd = substream->private_data;
if (!substream->runtime || !soc_prtd) {
pr_err("%s: substream runtime or private_data not found\n",
__func__);
return 0;
}
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = msm_pcm_set_volume(prtd, volume);
prtd->volume = volume;
}
mutex_unlock(&pdata->lock);
return rc;
}
@ -1050,14 +1087,28 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
struct msm_audio *prtd;
struct snd_soc_pcm_runtime *rtd = NULL;
struct msm_plat_data *pdata = NULL;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
if (!substream->runtime)
rtd = substream->private_data;
if (rtd) {
pdata = (struct msm_plat_data *)
dev_get_drvdata(rtd->platform->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
}
if (!substream->runtime || !rtd)
return 0;
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
@ -1065,6 +1116,7 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
prtd->channel_map[i] =
(char)(ucontrol->value.integer.value[i]);
}
mutex_unlock(&pdata->lock);
return 0;
}
@ -1076,16 +1128,30 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
struct msm_audio *prtd;
struct snd_soc_pcm_runtime *rtd = NULL;
struct msm_plat_data *pdata = NULL;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
rtd = substream->private_data;
if (rtd) {
pdata = (struct msm_plat_data *)
dev_get_drvdata(rtd->platform->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
}
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
if (!substream->runtime)
if (!substream->runtime || !rtd)
return 0; /* no channels set */
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
@ -1097,6 +1163,7 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[i] = 0;
}
mutex_unlock(&pdata->lock);
return 0;
}
@ -1296,6 +1363,7 @@ static int msm_pcm_probe(struct platform_device *pdev)
else
pdata->perf_mode = LEGACY_PCM_MODE;
mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
@ -1310,6 +1378,7 @@ static int msm_pcm_remove(struct platform_device *pdev)
struct msm_plat_data *pdata;
pdata = dev_get_drvdata(&pdev->dev);
mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_platform(&pdev->dev);
return 0;

View File

@ -1,7 +1,7 @@
/*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
* Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2015, 2019 The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@ -123,6 +123,7 @@ struct output_meta_data_st {
struct msm_plat_data {
int perf_mode;
struct mutex lock;
};
#endif /*_MSM_PCM_H*/