From b2cbb6e1c1544fc889ee7d6c6a6c229c20cd03cd Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Thu, 23 Jan 2014 13:02:47 +0800
Subject: [PATCH 01/16] ASoC: core: set_tdm_slot() will return -ENOTSUPP if no
operation provided
Make it easier for generic code to work with set_tdm_slot() by distinguishing
between the operation not being supported and an error as is done.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fe1df50805a3..393ff069af69 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3626,7 +3626,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
From 939d9f16994166156fa3d6dfece9c46b92e368e0 Mon Sep 17 00:00:00 2001
From: Nenghua Cao
Date: Mon, 3 Mar 2014 19:08:23 +0800
Subject: [PATCH 02/16] ASoC: core: fix coccinelle warnings
sound/soc/soc-core.c:2708:6-13: WARNING: Assignment of
bool to 0/1
sound/soc/soc-core.c:2726:3-10: WARNING: Assignment of
bool to 0/1
More information about semantic patching is available at
http://coccinelle.lip6.fr/
Signed-off-by: Nenghua Cao
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 393ff069af69..45a1fafdbd7b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2818,7 +2818,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
int err;
- bool type_2r = 0;
+ bool type_2r = false;
unsigned int val2 = 0;
unsigned int val, val_mask;
@@ -2836,7 +2836,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
val |= val2 << rshift;
} else {
val2 = val2 << shift;
- type_2r = 1;
+ type_2r = true;
}
}
err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
From 931f27c6e892fdfe98896055e0df7962e21969d9 Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Fri, 28 Feb 2014 10:48:19 +0800
Subject: [PATCH 03/16] ASoC: cache: Do the codec->reg_cache zero pionter check
For the snd_soc_cache_init(), the reg_size maybe zero and then the value
of codec->reg_cache, which is alloced via kzalloc, maybe equal to
ZERO_SIZE_PTR. If the reg parameter of snd_soc_cache_write() is large enough,
the cache[idx] = val maybe cause the kernel crash...
So this patch fix this via doing the zero pionter check of it.
Signed-off-by: Xiubo Li
Signed-off-by: Mark Brown
---
sound/soc/soc-cache.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 375dc6dfba4e..bfed3e4c45ff 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
{
dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n",
codec->name);
- if (!codec->reg_cache)
- return 0;
+
kfree(codec->reg_cache);
codec->reg_cache = NULL;
return 0;
@@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
return -EINVAL;
mutex_lock(&codec->cache_rw_mutex);
- *value = snd_soc_get_cache_val(codec->reg_cache, reg,
- codec->driver->reg_word_size);
+ if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+ *value = snd_soc_get_cache_val(codec->reg_cache, reg,
+ codec->driver->reg_word_size);
mutex_unlock(&codec->cache_rw_mutex);
return 0;
@@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
mutex_lock(&codec->cache_rw_mutex);
- snd_soc_set_cache_val(codec->reg_cache, reg, value,
- codec->driver->reg_word_size);
+ if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+ snd_soc_set_cache_val(codec->reg_cache, reg, value,
+ codec->driver->reg_word_size);
mutex_unlock(&codec->cache_rw_mutex);
return 0;
From 208a1589db3e30767223d97e39e13237328e8a6e Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:42 +0100
Subject: [PATCH 04/16] ASoC: Handle ignore_pmdown_time for CODEC to CODEC
links
For CODEC to CODEC links we should only immediately power down if both CODECs
are configured to ignore the power down delay. Factor the logic for this
into a helper function that can be used for both compressed and normal PCMs.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 2 ++
sound/soc/soc-compress.c | 3 +--
sound/soc/soc-pcm.c | 27 +++++++++++++++++++++++++--
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 9a001472b96a..93c31c70b90a 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -413,6 +413,8 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link);
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
+
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 5e9690c85d8f..ef585af4081b 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -235,8 +235,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
cpu_dai->runtime = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_STOP);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 47e1ce771e65..f098c8007cbe 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -34,6 +34,30 @@
#define DPCM_MAX_BE_USERS 8
+/**
+ * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
+ * @rtd: The ASoC PCM runtime that should be checked.
+ *
+ * This function checks whether the power down delay should be ignored for a
+ * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
+ * been configured to ignore the delay, or if none of the components benefits
+ * from having the delay.
+ */
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
+{
+ bool ignore = true;
+
+ if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
+ return true;
+
+ if (rtd->cpu_dai->codec)
+ ignore &= rtd->cpu_dai->codec->ignore_pmdown_time;
+
+ ignore &= rtd->codec_dai->codec->ignore_pmdown_time;
+
+ return ignore;
+}
+
/**
* snd_soc_set_runtime_hwparams - set the runtime hardware parameters
* @substream: the pcm substream
@@ -496,8 +520,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
/* powered down playback stream now */
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
From 24894b76468ed250d03f9718ddfe77b902995cbd Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:43 +0100
Subject: [PATCH 05/16] ASoC: Add helper functions for PCM runtime 'active'
management
We have the same code that increments and decrements the active field of the
various PCM runtime components (all with the same bugs). Factor this out into
common helper functions.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 2 +
sound/soc/soc-compress.c | 62 ++++++-----------------------
sound/soc/soc-pcm.c | 86 ++++++++++++++++++++++++++++++----------
3 files changed, 78 insertions(+), 72 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 93c31c70b90a..53d15e0e6e89 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -414,6 +414,8 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link);
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index ef585af4081b..91083e6a6b38 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
}
}
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+ snd_soc_runtime_activate(rtd, cstream->direction);
mutex_unlock(&rtd->pcm_mutex);
@@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream;
@@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- fe->codec->active++;
+ snd_soc_runtime_activate(fe, stream);
mutex_unlock(&fe->card->mutex);
@@ -202,24 +178,19 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_codec *codec = rtd->codec;
+ int stream;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+
+ snd_soc_runtime_deactivate(rtd, stream);
snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
-
if (!cpu_dai->active)
cpu_dai->rate = 0;
@@ -260,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
int stream, ret;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
stream = SNDRV_PCM_STREAM_PLAYBACK;
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
+ else
stream = SNDRV_PCM_STREAM_CAPTURE;
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
- cpu_dai->active--;
- codec_dai->active--;
- fe->codec->active--;
+ snd_soc_runtime_deactivate(fe, stream);
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index f098c8007cbe..1a9857519d65 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -34,6 +34,66 @@
#define DPCM_MAX_BE_USERS 8
+/**
+ * snd_soc_runtime_activate() - Increment active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is activated
+ * @stream: Direction of the PCM stream
+ *
+ * Increments the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is opened.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
+ } else {
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
+ }
+
+ cpu_dai->active++;
+ codec_dai->active++;
+ rtd->codec->active++;
+}
+
+/**
+ * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is deactivated
+ * @stream: Direction of the PCM stream
+ *
+ * Decrements the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is closed.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
+ } else {
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
+ }
+
+ cpu_dai->active--;
+ codec_dai->active--;
+ rtd->codec->active--;
+}
+
/**
* snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
* @rtd: The ASoC PCM runtime that should be checked.
@@ -402,16 +462,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rate_max);
dynamic:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+
+ snd_soc_runtime_activate(rtd, substream->stream);
+
mutex_unlock(&rtd->pcm_mutex);
return 0;
@@ -483,21 +536,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_codec *codec = rtd->codec;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
-
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
+ snd_soc_runtime_deactivate(rtd, substream->stream);
/* clear the corresponding DAIs rate when inactive */
if (!cpu_dai->active)
From a1a0cc0646e38b41bfaac94f2b84422bb1df40e0 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:44 +0100
Subject: [PATCH 06/16] ASoC: Fix active count tracking for CODEC to CODEC
links
For CODEC to CODEC links we need to make sure to also manage the 'active' field
of the cpu_dai CODEC.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
sound/soc/soc-pcm.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 1a9857519d65..71a01dda1867 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -61,7 +61,9 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
cpu_dai->active++;
codec_dai->active++;
- rtd->codec->active++;
+ if (cpu_dai->codec)
+ cpu_dai->codec->active++;
+ codec_dai->codec->active++;
}
/**
@@ -91,7 +93,9 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
cpu_dai->active--;
codec_dai->active--;
- rtd->codec->active--;
+ if (cpu_dai->codec)
+ cpu_dai->codec->active--;
+ codec_dai->codec->active--;
}
/**
From 5c898e74d135a23ce12e0263c1a3c78eeae1b52b Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:45 +0100
Subject: [PATCH 07/16] ASoC: Add helper function to check whether a CODEC is
active
Instead of directly checking the 'active' field of the CODEC struct add a new
helper function that will return either true or false depending on whether the
CODEC is active. This will make the migration to the component level easier.
The patch also updates all CODEC drivers that check the active attribute to use
the new helper function.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 5 +++++
sound/soc/codecs/adav80x.c | 4 ++--
sound/soc/codecs/tlv320aic23.c | 2 +-
sound/soc/codecs/tlv320dac33.c | 2 +-
sound/soc/codecs/uda1380.c | 2 +-
sound/soc/codecs/wl1273.c | 2 +-
sound/soc/codecs/wm8711.c | 2 +-
sound/soc/codecs/wm8753.c | 4 ++--
8 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 53d15e0e6e89..5c2b4f4b5cfa 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1172,6 +1172,11 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
return 1;
}
+static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
+{
+ return codec->active != 0;
+}
+
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index f78b27a7c461..d50cf5b29a27 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -722,7 +722,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active || !adav80x->rate)
+ if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
return 0;
return snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -735,7 +735,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
adav80x->rate = 0;
}
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 5d430cc56f51..458a6aed203e 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
}
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4f358393d6d6..35b2d244e42e 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
if (dac33->fifo_mode == ucontrol->value.integer.value[0])
return 0;
/* Do not allow changes while stream is running*/
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 726df6d43c2b..8e3940dcff20 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
/* the interpolator & decimator regs must only be written when the
* codec DAI is active.
*/
- if (!codec->active && (reg >= UDA1380_MVOL))
+ if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
return 0;
pr_debug("uda1380: hw write %x val %x\n", reg, value);
if (codec->hw_write(codec->control_data, data, 3) == 3) {
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index b7ab2ef567c8..47e96ff30064 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
return 0;
/* Do not allow changes while stream is running */
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index d99f948c513c..6efcc40a7cb3 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, WM8711_ACTIVE, 0x0);
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index be85da93a268..5cf4bebc5d89 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
if (wm8753->dai_func == ucontrol->value.integer.value[0])
return 0;
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EBUSY;
ioctl = snd_soc_read(codec, WM8753_IOCTL);
@@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
if (mute && wm8753->dai_func == 1) {
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
From 6106d12947d1b05dc15ca3933eb514347d6ed726 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:46 +0100
Subject: [PATCH 08/16] ASoC: Add component pointer to the DAI struct
Keep track of which component registered a DAI. We'll need this as
componentization progresses.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc-dai.h | 1 +
sound/soc/soc-core.c | 18 ++++++++++++------
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 71f27c403194..8763e539c487 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -270,6 +270,7 @@ struct snd_soc_dai {
/* parent platform/codec */
struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct snd_soc_card *card;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fe1df50805a3..6401e97b2e68 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3884,11 +3884,13 @@ static inline char *fmt_multiple_name(struct device *dev,
/**
* snd_soc_register_dai - Register a DAI with the ASoC core
*
- * @dai: DAI to register
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAIs
*/
-static int snd_soc_register_dai(struct device *dev,
+static int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv)
{
+ struct device *dev = component->dev;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
@@ -3905,6 +3907,7 @@ static int snd_soc_register_dai(struct device *dev,
return -ENOMEM;
}
+ dai->component = component;
dai->dev = dev;
dai->driver = dai_drv;
dai->dapm.dev = dev;
@@ -3962,12 +3965,14 @@ found:
/**
* snd_soc_register_dais - Register multiple DAIs with the ASoC core
*
- * @dai: Array of DAIs to register
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
*/
-static int snd_soc_register_dais(struct device *dev,
+static int snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count)
{
+ struct device *dev = component->dev;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
int i, ret = 0;
@@ -3990,6 +3995,7 @@ static int snd_soc_register_dais(struct device *dev,
goto err;
}
+ dai->component = component;
dai->dev = dev;
dai->driver = &dai_drv[i];
if (dai->driver->id)
@@ -4086,9 +4092,9 @@ __snd_soc_register_component(struct device *dev,
* since it had been used snd_soc_register_dais(),
*/
if ((1 == num_dai) && allow_single_dai)
- ret = snd_soc_register_dai(dev, dai_drv);
+ ret = snd_soc_register_dai(cmpnt, dai_drv);
else
- ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
From cdde4ccb14b4959bd1c96a07367bf02b746328d3 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:47 +0100
Subject: [PATCH 09/16] ASoC: Move active count from CODEC to component
There is no reason why active count tracking should only be done for CODECs but
not for other components. Moving the active count from the snd_soc_codec struct
to the snd_soc_component struct reduces the differences between CODECs and other
components and will eventually allow component to component DAI links (Which is
a prerequisite for converting CODECs to components).
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 12 ++++++++++--
sound/soc/soc-pcm.c | 10 ++++------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 5c2b4f4b5cfa..0495b4aaeb70 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -660,6 +660,9 @@ struct snd_soc_component {
const char *name;
int id;
struct device *dev;
+
+ unsigned int active;
+
struct list_head list;
struct snd_soc_dai_driver *dai_drv;
@@ -687,7 +690,6 @@ struct snd_soc_codec {
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
- unsigned int active;
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int probed:1; /* Codec has been probed */
@@ -1172,9 +1174,15 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
return 1;
}
+static inline bool snd_soc_component_is_active(
+ struct snd_soc_component *component)
+{
+ return component->active != 0;
+}
+
static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
{
- return codec->active != 0;
+ return snd_soc_component_is_active(&codec->component);
}
int snd_soc_util_init(void);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 71a01dda1867..98b46295785d 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -61,9 +61,8 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
cpu_dai->active++;
codec_dai->active++;
- if (cpu_dai->codec)
- cpu_dai->codec->active++;
- codec_dai->codec->active++;
+ cpu_dai->component->active++;
+ codec_dai->component->active++;
}
/**
@@ -93,9 +92,8 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
cpu_dai->active--;
codec_dai->active--;
- if (cpu_dai->codec)
- cpu_dai->codec->active--;
- codec_dai->codec->active--;
+ cpu_dai->component->active--;
+ codec_dai->component->active--;
}
/**
From 3d59400fe47e7e8bfb024cd1651433bef42e268e Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 5 Mar 2014 13:17:48 +0100
Subject: [PATCH 10/16] ASoC: Move ignore_pmdown_time from CODEC to component
In preparation for componentization move the ignore_pmdown_time field from the
snd_soc_codec struct to the snd_soc_component struct. Set it to true for non
CODEC components for now.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 3 ++-
sound/soc/soc-core.c | 4 +++-
sound/soc/soc-pcm.c | 10 ++--------
3 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 0495b4aaeb70..b14acd8228ab 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -663,6 +663,8 @@ struct snd_soc_component {
unsigned int active;
+ unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
+
struct list_head list;
struct snd_soc_dai_driver *dai_drv;
@@ -715,7 +717,6 @@ struct snd_soc_codec {
/* dapm */
struct snd_soc_dapm_context dapm;
- unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 6401e97b2e68..18aecd2841a8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -4127,6 +4127,8 @@ int snd_soc_register_component(struct device *dev,
return -ENOMEM;
}
+ cmpnt->ignore_pmdown_time = true;
+
return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
dai_drv, num_dai, true);
}
@@ -4325,7 +4327,7 @@ int snd_soc_register_codec(struct device *dev,
codec->volatile_register = codec_drv->volatile_register;
codec->readable_register = codec_drv->readable_register;
codec->writable_register = codec_drv->writable_register;
- codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
+ codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 98b46295785d..2cedf09f6d96 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -107,17 +107,11 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
*/
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
{
- bool ignore = true;
-
if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
return true;
- if (rtd->cpu_dai->codec)
- ignore &= rtd->cpu_dai->codec->ignore_pmdown_time;
-
- ignore &= rtd->codec_dai->codec->ignore_pmdown_time;
-
- return ignore;
+ return rtd->cpu_dai->component->ignore_pmdown_time &&
+ rtd->codec_dai->component->ignore_pmdown_time;
}
/**
From 13ff50c85846338bb9820abd3933227b678dc086 Mon Sep 17 00:00:00 2001
From: Nenghua Cao
Date: Wed, 19 Feb 2014 18:44:13 +0800
Subject: [PATCH 11/16] regmap: add regmap_parse_val api
In some cases, we need regmap's format parse_val function
to do be/le translation according to the bus configuration.
For example, snd_soc_bytes_put() uses regmap to write/read values,
and use cpu_to_be() directly to covert MASK into big endian. This
is a defect, and should use regmap's format function to do it according
to bus configuration.
Signed-off-by: Nenghua Cao
Signed-off-by: Mark Brown
---
drivers/base/regmap/regmap.c | 12 ++++++++++++
include/linux/regmap.h | 9 +++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6a19515f8a45..4b2ed0c9e80d 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2240,6 +2240,18 @@ int regmap_get_val_bytes(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val)
+{
+ if (!map->format.parse_val)
+ return -EINVAL;
+
+ *val = map->format.parse_val(buf);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_parse_val);
+
static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4149f1a9b003..3e1a2e4a92ad 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -423,6 +423,8 @@ bool regmap_check_range_table(struct regmap *map, unsigned int reg,
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs);
+int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val);
static inline bool regmap_reg_in_range(unsigned int reg,
const struct regmap_range *range)
@@ -695,6 +697,13 @@ static inline int regmap_register_patch(struct regmap *map,
return -EINVAL;
}
+static inline int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline struct regmap *dev_get_regmap(struct device *dev,
const char *name)
{
From a1a564ed6abf62e05fcffa9ed3f46a826400df3a Mon Sep 17 00:00:00 2001
From: Nenghua Cao
Date: Wed, 19 Feb 2014 18:44:58 +0800
Subject: [PATCH 12/16] ASoC: core: use regmap's parse_val to do endian
translation
In snd_soc_bytes_put function, it forces cpu to do cpu_to_be translation,
but for mmio bus which uses REGMAP_ENDIAN_NATIVE, it doesn't need to do
endian translation. So it is better to use regmap's api which can decide
if this translation is needed according to bus configuration.
Signed-off-by: Nenghua Cao
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 45a1fafdbd7b..9d25c2e0fb92 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3234,7 +3234,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
struct soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int ret, len;
- unsigned int val;
+ unsigned int val, mask;
void *data;
if (!codec->using_regmap)
@@ -3264,12 +3264,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
((u8 *)data)[0] |= val;
break;
case 2:
- ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
- ((u16 *)data)[0] |= cpu_to_be16(val);
+ mask = ~params->mask;
+ ret = regmap_parse_val(codec->control_data,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(codec->control_data,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] |= val;
break;
case 4:
- ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
- ((u32 *)data)[0] |= cpu_to_be32(val);
+ mask = ~params->mask;
+ ret = regmap_parse_val(codec->control_data,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(codec->control_data,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] |= val;
break;
default:
ret = -EINVAL;
From 32c9ba544b65991b14ede102928c552ed24d4827 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Sun, 9 Mar 2014 17:41:45 +0100
Subject: [PATCH 13/16] ASoC: Consolidate snd_soc_register_dai() and
snd_soc_register_dais()
snd_soc_register_dais() has basically the same code as snd_soc_register_dai(),
but running in a loop. The only difference is that snd_soc_register_dai() calls
fmt_single_name() to generate the DAIs name and snd_soc_register_dais() calls
fmt_multiple_name(). This patch pushes the check in __snd_soc_register_component()
which decides whether to call snd_soc_register_dai() or snd_soc_register_dais()
to snd_soc_register_dais() to decide which naming scheme to use. This allows us
to remove snd_soc_register_dai().
The patch also updates snd_soc_register_dais() to unregister every DAI it finds
for the component rather than trying to unregister one DAI for each DAI that was
registered. Both have the same result since there won't be more DAIs than what
have been registered, but the former is easier to implement.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 154 ++++++++++++-------------------------------
1 file changed, 42 insertions(+), 112 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 255eca9afc9b..c365be98b0c3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3906,100 +3906,47 @@ static inline char *fmt_multiple_name(struct device *dev,
}
/**
- * snd_soc_register_dai - Register a DAI with the ASoC core
+ * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
*
- * @component: The component the DAIs are registered for
- * @dai_drv: DAI driver to use for the DAIs
+ * @component: The component for which the DAIs should be unregistered
*/
-static int snd_soc_register_dai(struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv)
+static void snd_soc_unregister_dais(struct snd_soc_component *component)
{
- struct device *dev = component->dev;
- struct snd_soc_codec *codec;
- struct snd_soc_dai *dai;
+ struct snd_soc_dai *dai, *_dai;
- dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev));
+ mutex_lock(&client_mutex);
+ list_for_each_entry_safe(dai, _dai, &dai_list, list) {
+ if (dai->dev != component->dev)
+ continue;
- dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
- if (dai == NULL)
- return -ENOMEM;
+ list_del(&dai->list);
- /* create DAI component name */
- dai->name = fmt_single_name(dev, &dai->id);
- if (dai->name == NULL) {
+ dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
+ dai->name);
+ kfree(dai->name);
kfree(dai);
- return -ENOMEM;
}
-
- dai->component = component;
- dai->dev = dev;
- dai->driver = dai_drv;
- dai->dapm.dev = dev;
- if (!dai->driver->ops)
- dai->driver->ops = &null_dai_ops;
-
- mutex_lock(&client_mutex);
-
- list_for_each_entry(codec, &codec_list, list) {
- if (codec->dev == dev) {
- dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n",
- dai->name, codec->name);
- dai->codec = codec;
- break;
- }
- }
-
- if (!dai->codec)
- dai->dapm.idle_bias_off = 1;
-
- list_add(&dai->list, &dai_list);
-
mutex_unlock(&client_mutex);
-
- dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
-
- return 0;
}
/**
- * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
- *
- * @dai: DAI to unregister
- */
-static void snd_soc_unregister_dai(struct device *dev)
-{
- struct snd_soc_dai *dai;
-
- list_for_each_entry(dai, &dai_list, list) {
- if (dev == dai->dev)
- goto found;
- }
- return;
-
-found:
- mutex_lock(&client_mutex);
- list_del(&dai->list);
- mutex_unlock(&client_mutex);
-
- dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
- kfree(dai->name);
- kfree(dai);
-}
-
-/**
- * snd_soc_register_dais - Register multiple DAIs with the ASoC core
+ * snd_soc_register_dais - Register a DAI with the ASoC core
*
* @component: The component the DAIs are registered for
* @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
+ * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
+ * parent's name.
*/
static int snd_soc_register_dais(struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv, size_t count)
+ struct snd_soc_dai_driver *dai_drv, size_t count,
+ bool legacy_dai_naming)
{
struct device *dev = component->dev;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
- int i, ret = 0;
+ unsigned int i;
+ int ret;
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
@@ -4011,21 +3958,32 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
goto err;
}
- /* create DAI component name */
- dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ /*
+ * Back in the old days when we still had component-less DAIs,
+ * instead of having a static name, component-less DAIs would
+ * inherit the name of the parent device so it is possible to
+ * register multiple instances of the DAI. We still need to keep
+ * the same naming style even though those DAIs are not
+ * component-less anymore.
+ */
+ if (count == 1 && legacy_dai_naming) {
+ dai->name = fmt_single_name(dev, &dai->id);
+ } else {
+ dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ if (dai_drv[i].id)
+ dai->id = dai_drv[i].id;
+ else
+ dai->id = i;
+ }
if (dai->name == NULL) {
kfree(dai);
- ret = -EINVAL;
+ ret = -ENOMEM;
goto err;
}
dai->component = component;
dai->dev = dev;
dai->driver = &dai_drv[i];
- if (dai->driver->id)
- dai->id = dai->driver->id;
- else
- dai->id = i;
dai->dapm.dev = dev;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
@@ -4034,8 +3992,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
list_for_each_entry(codec, &codec_list, list) {
if (codec->dev == dev) {
- dev_dbg(dev,
- "ASoC: Mapped DAI %s to CODEC %s\n",
+ dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n",
dai->name, codec->name);
dai->codec = codec;
break;
@@ -4049,32 +4006,17 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
mutex_unlock(&client_mutex);
- dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name);
+ dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
}
return 0;
err:
- for (i--; i >= 0; i--)
- snd_soc_unregister_dai(dev);
+ snd_soc_unregister_dais(component);
return ret;
}
-/**
- * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
- *
- * @dai: Array of DAIs to unregister
- * @count: Number of DAIs
- */
-static void snd_soc_unregister_dais(struct device *dev, size_t count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- snd_soc_unregister_dai(dev);
-}
-
/**
* snd_soc_register_component - Register a component with the ASoC core
*
@@ -4106,19 +4048,7 @@ __snd_soc_register_component(struct device *dev,
cmpnt->dai_drv = dai_drv;
cmpnt->num_dai = num_dai;
- /*
- * snd_soc_register_dai() uses fmt_single_name(), and
- * snd_soc_register_dais() uses fmt_multiple_name()
- * for dai->name which is used for name based matching
- *
- * this function is used from cpu/codec.
- * allow_single_dai flag can ignore "codec" driver reworking
- * since it had been used snd_soc_register_dais(),
- */
- if ((1 == num_dai) && allow_single_dai)
- ret = snd_soc_register_dai(cmpnt, dai_drv);
- else
- ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai);
+ ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, allow_single_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
@@ -4173,7 +4103,7 @@ void snd_soc_unregister_component(struct device *dev)
return;
found:
- snd_soc_unregister_dais(dev, cmpnt->num_dai);
+ snd_soc_unregister_dais(cmpnt);
mutex_lock(&client_mutex);
list_del(&cmpnt->list);
From 6cc240f39d393c5878bc6cf053aa0fe8e3fe4260 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Sun, 9 Mar 2014 17:41:46 +0100
Subject: [PATCH 14/16] ASoC: Pass CODEC to snd_soc_register_dais()
snd_soc_register_dais() looks up the CODEC that is registering the DAIs by
looping over all registered CODECs. This patch updates the code to
simply pass the CODEC that registers the DAIs to snd_soc_register_dais() thus
avoiding the lookup.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c365be98b0c3..cc522418e9c4 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3933,17 +3933,18 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component)
* snd_soc_register_dais - Register a DAI with the ASoC core
*
* @component: The component the DAIs are registered for
+ * @codec: The CODEC that the DAIs are registered for, NULL if the component is
+ * not a CODEC.
* @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
* @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
* parent's name.
*/
static int snd_soc_register_dais(struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv, size_t count,
- bool legacy_dai_naming)
+ struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv,
+ size_t count, bool legacy_dai_naming)
{
struct device *dev = component->dev;
- struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
unsigned int i;
int ret;
@@ -3982,28 +3983,19 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
}
dai->component = component;
+ dai->codec = codec;
dai->dev = dev;
dai->driver = &dai_drv[i];
dai->dapm.dev = dev;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
- mutex_lock(&client_mutex);
-
- list_for_each_entry(codec, &codec_list, list) {
- if (codec->dev == dev) {
- dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n",
- dai->name, codec->name);
- dai->codec = codec;
- break;
- }
- }
if (!dai->codec)
dai->dapm.idle_bias_off = 1;
+ mutex_lock(&client_mutex);
list_add(&dai->list, &dai_list);
-
mutex_unlock(&client_mutex);
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
@@ -4025,6 +4017,7 @@ static int
__snd_soc_register_component(struct device *dev,
struct snd_soc_component *cmpnt,
const struct snd_soc_component_driver *cmpnt_drv,
+ struct snd_soc_codec *codec,
struct snd_soc_dai_driver *dai_drv,
int num_dai, bool allow_single_dai)
{
@@ -4048,7 +4041,8 @@ __snd_soc_register_component(struct device *dev,
cmpnt->dai_drv = dai_drv;
cmpnt->num_dai = num_dai;
- ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, allow_single_dai);
+ ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai,
+ allow_single_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
@@ -4083,7 +4077,7 @@ int snd_soc_register_component(struct device *dev,
cmpnt->ignore_pmdown_time = true;
- return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
+ return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
dai_drv, num_dai, true);
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
@@ -4304,7 +4298,7 @@ int snd_soc_register_codec(struct device *dev,
/* register component */
ret = __snd_soc_register_component(dev, &codec->component,
&codec_drv->component_driver,
- dai_drv, num_dai, false);
+ codec, dai_drv, num_dai, false);
if (ret < 0) {
dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
goto fail_codec_name;
From 1438c2f60ba955114cff3717f1a334878c7886a9 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Sun, 9 Mar 2014 17:41:47 +0100
Subject: [PATCH 15/16] ASoC: Add a per component dai list
Now that every DAI has a component we can track the DAIs on a per component
basis. This simplifies the DAI lookup when we are only interested in DAIs of a
specific component and also makes it possible to have multiple components with
the same parent device and also register DAIs.
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
include/sound/soc.h | 2 ++
sound/soc/soc-core.c | 76 ++++++++++++++++++++------------------------
2 files changed, 36 insertions(+), 42 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index b14acd8228ab..37b470c1e127 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -671,6 +671,8 @@ struct snd_soc_component {
int num_dai;
const struct snd_soc_component_driver *driver;
+
+ struct list_head dai_list;
};
/* SoC Audio Codec device */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index cc522418e9c4..f34f1a01fce1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
#endif
static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);
static LIST_HEAD(component_list);
@@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
ssize_t len, ret = 0;
+ struct snd_soc_component *component;
struct snd_soc_dai *dai;
if (!buf)
return -ENOMEM;
- list_for_each_entry(dai, &dai_list, list) {
- len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
- if (len >= 0)
- ret += len;
- if (ret > PAGE_SIZE) {
- ret = PAGE_SIZE;
- break;
+ list_for_each_entry(component, &component_list, list) {
+ list_for_each_entry(dai, &component->dai_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ dai->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
}
}
@@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_component *component;
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
struct snd_soc_dai *codec_dai, *cpu_dai;
@@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
/* Find CPU DAI from registered DAIs*/
- list_for_each_entry(cpu_dai, &dai_list, list) {
+ list_for_each_entry(component, &component_list, list) {
if (dai_link->cpu_of_node &&
- (cpu_dai->dev->of_node != dai_link->cpu_of_node))
+ component->dev->of_node != dai_link->cpu_of_node)
continue;
if (dai_link->cpu_name &&
- strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
- continue;
- if (dai_link->cpu_dai_name &&
- strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+ strcmp(dev_name(component->dev), dai_link->cpu_name))
continue;
+ list_for_each_entry(cpu_dai, &component->dai_list, list) {
+ if (dai_link->cpu_dai_name &&
+ strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+ continue;
- rtd->cpu_dai = cpu_dai;
+ rtd->cpu_dai = cpu_dai;
+ }
}
if (!rtd->cpu_dai) {
@@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
* CODEC found, so find CODEC DAI from registered DAIs from
* this CODEC
*/
- list_for_each_entry(codec_dai, &dai_list, list) {
- if (codec->dev == codec_dai->dev &&
- !strcmp(codec_dai->name,
- dai_link->codec_dai_name)) {
-
+ list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
+ if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
rtd->codec_dai = codec_dai;
+ break;
}
}
@@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card,
driver->num_dapm_widgets);
/* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &dai_list, list) {
- if (dai->dev != codec->dev)
- continue;
-
+ list_for_each_entry(dai, &codec->component.dai_list, list)
snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
- }
codec->dapm.idle_bias_off = driver->idle_bias_off;
@@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
{
int ret = 0;
const struct snd_soc_platform_driver *driver = platform->driver;
+ struct snd_soc_component *component;
struct snd_soc_dai *dai;
platform->card = card;
@@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_card *card,
driver->dapm_widgets, driver->num_dapm_widgets);
/* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &dai_list, list) {
- if (dai->dev != platform->dev)
+ list_for_each_entry(component, &component_list, list) {
+ if (component->dev != platform->dev)
continue;
-
- snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+ list_for_each_entry(dai, &component->dai_list, list)
+ snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
}
platform->dapm.idle_bias_off = 1;
@@ -3912,21 +3913,14 @@ static inline char *fmt_multiple_name(struct device *dev,
*/
static void snd_soc_unregister_dais(struct snd_soc_component *component)
{
- struct snd_soc_dai *dai, *_dai;
-
- mutex_lock(&client_mutex);
- list_for_each_entry_safe(dai, _dai, &dai_list, list) {
- if (dai->dev != component->dev)
- continue;
-
- list_del(&dai->list);
+ struct snd_soc_dai *dai;
+ list_for_each_entry(dai, &component->dai_list, list) {
dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
dai->name);
kfree(dai->name);
kfree(dai);
}
- mutex_unlock(&client_mutex);
}
/**
@@ -3990,13 +3984,10 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
-
if (!dai->codec)
dai->dapm.idle_bias_off = 1;
- mutex_lock(&client_mutex);
- list_add(&dai->list, &dai_list);
- mutex_unlock(&client_mutex);
+ list_add(&dai->list, &component->dai_list);
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
}
@@ -4040,6 +4031,7 @@ __snd_soc_register_component(struct device *dev,
cmpnt->driver = cmpnt_drv;
cmpnt->dai_drv = dai_drv;
cmpnt->num_dai = num_dai;
+ INIT_LIST_HEAD(&cmpnt->dai_list);
ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai,
allow_single_dai);
From 5c1d5f091dc39eecf9a34a8be01492d14c23ad91 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen
Date: Wed, 12 Mar 2014 08:34:39 +0100
Subject: [PATCH 16/16] ASoC: Fix use after free
Freeing the current list element while iterating over the list will cause a use
after free since the iterator function will still use the current element to
look up the next. Use list_for_each_safe() and remove the element from the list
before freeing it to avoid this.
Fixes: 1438c2f60b ("ASoC: Add a per component dai list")
Reported-by: Dan Carpenter
Signed-off-by: Lars-Peter Clausen
Signed-off-by: Mark Brown
---
sound/soc/soc-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index f34f1a01fce1..a78bba4d52fb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3913,11 +3913,12 @@ static inline char *fmt_multiple_name(struct device *dev,
*/
static void snd_soc_unregister_dais(struct snd_soc_component *component)
{
- struct snd_soc_dai *dai;
+ struct snd_soc_dai *dai, *_dai;
- list_for_each_entry(dai, &component->dai_list, list) {
+ list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
dai->name);
+ list_del(&dai->list);
kfree(dai->name);
kfree(dai);
}