diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-06-08 14:34:23 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-06-13 08:18:05 -0400 |
commit | 62ae68fa5d6d6f93d8ca8d00e21ad7ac410f9d58 (patch) | |
tree | 510b2f60d738bb2706dbf22e2930ca26de17cac9 /sound/soc/soc-core.c | |
parent | d12cd198cba7949c70f596296297b772063175c0 (diff) |
ASoC: probe CODECs and platforms before DAIs and links
soc_probe_dai_link() currently inter-mixes the probing of CODECs,
platforms, and DAIs. This can lead to problems such as a CODEC's DAI
being probed before the CODEC, if that DAI is used as the CPU-side of
a DAI link without any other of the CODEC's DAIs having been used as
the CODEC-side of any DAI link that was probed earlier.
To solve this, split soc_probe_dai_link() into soc_probe_link_components()
and soc_probe_link_dais(). The former is used to probe all CODECs and
platforms used by a card first, and then the latter is used to probe all
the DAIs and links later.
A similar change is made to soc_remove_dai_links().
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 129 |
1 files changed, 95 insertions, 34 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a539ade477af..fe16135250f8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -941,11 +941,9 @@ static void soc_remove_codec(struct snd_soc_codec *codec) | |||
941 | module_put(codec->dev->driver->owner); | 941 | module_put(codec->dev->driver->owner); |
942 | } | 942 | } |
943 | 943 | ||
944 | static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | 944 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) |
945 | { | 945 | { |
946 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 946 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
947 | struct snd_soc_codec *codec = rtd->codec; | ||
948 | struct snd_soc_platform *platform = rtd->platform; | ||
949 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 947 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; |
950 | int err; | 948 | int err; |
951 | 949 | ||
@@ -970,16 +968,6 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | |||
970 | list_del(&codec_dai->card_list); | 968 | list_del(&codec_dai->card_list); |
971 | } | 969 | } |
972 | 970 | ||
973 | /* remove the platform */ | ||
974 | if (platform && platform->probed && | ||
975 | platform->driver->remove_order == order) | ||
976 | soc_remove_platform(platform); | ||
977 | |||
978 | /* remove the CODEC */ | ||
979 | if (codec && codec->probed && | ||
980 | codec->driver->remove_order == order) | ||
981 | soc_remove_codec(codec); | ||
982 | |||
983 | /* remove the cpu_dai */ | 971 | /* remove the cpu_dai */ |
984 | if (cpu_dai && cpu_dai->probed && | 972 | if (cpu_dai && cpu_dai->probed && |
985 | cpu_dai->driver->remove_order == order) { | 973 | cpu_dai->driver->remove_order == order) { |
@@ -999,6 +987,38 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | |||
999 | } | 987 | } |
1000 | } | 988 | } |
1001 | 989 | ||
990 | static void soc_remove_link_components(struct snd_soc_card *card, int num, | ||
991 | int order) | ||
992 | { | ||
993 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | ||
994 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
995 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
996 | struct snd_soc_platform *platform = rtd->platform; | ||
997 | struct snd_soc_codec *codec; | ||
998 | |||
999 | /* remove the platform */ | ||
1000 | if (platform && platform->probed && | ||
1001 | platform->driver->remove_order == order) { | ||
1002 | soc_remove_platform(platform); | ||
1003 | } | ||
1004 | |||
1005 | /* remove the CODEC-side CODEC */ | ||
1006 | if (codec_dai) { | ||
1007 | codec = codec_dai->codec; | ||
1008 | if (codec && codec->probed && | ||
1009 | codec->driver->remove_order == order) | ||
1010 | soc_remove_codec(codec); | ||
1011 | } | ||
1012 | |||
1013 | /* remove any CPU-side CODEC */ | ||
1014 | if (cpu_dai) { | ||
1015 | codec = cpu_dai->codec; | ||
1016 | if (codec && codec->probed && | ||
1017 | codec->driver->remove_order == order) | ||
1018 | soc_remove_codec(codec); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1002 | static void soc_remove_dai_links(struct snd_soc_card *card) | 1022 | static void soc_remove_dai_links(struct snd_soc_card *card) |
1003 | { | 1023 | { |
1004 | int dai, order; | 1024 | int dai, order; |
@@ -1006,8 +1026,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card) | |||
1006 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | 1026 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; |
1007 | order++) { | 1027 | order++) { |
1008 | for (dai = 0; dai < card->num_rtd; dai++) | 1028 | for (dai = 0; dai < card->num_rtd; dai++) |
1009 | soc_remove_dai_link(card, dai, order); | 1029 | soc_remove_link_dais(card, dai, order); |
1030 | } | ||
1031 | |||
1032 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | ||
1033 | order++) { | ||
1034 | for (dai = 0; dai < card->num_rtd; dai++) | ||
1035 | soc_remove_link_components(card, dai, order); | ||
1010 | } | 1036 | } |
1037 | |||
1011 | card->num_rtd = 0; | 1038 | card->num_rtd = 0; |
1012 | } | 1039 | } |
1013 | 1040 | ||
@@ -1244,7 +1271,44 @@ out: | |||
1244 | return 0; | 1271 | return 0; |
1245 | } | 1272 | } |
1246 | 1273 | ||
1247 | static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | 1274 | static int soc_probe_link_components(struct snd_soc_card *card, int num, |
1275 | int order) | ||
1276 | { | ||
1277 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | ||
1278 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1279 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1280 | struct snd_soc_platform *platform = rtd->platform; | ||
1281 | int ret; | ||
1282 | |||
1283 | /* probe the CPU-side component, if it is a CODEC */ | ||
1284 | if (cpu_dai->codec && | ||
1285 | !cpu_dai->codec->probed && | ||
1286 | cpu_dai->codec->driver->probe_order == order) { | ||
1287 | ret = soc_probe_codec(card, cpu_dai->codec); | ||
1288 | if (ret < 0) | ||
1289 | return ret; | ||
1290 | } | ||
1291 | |||
1292 | /* probe the CODEC-side component */ | ||
1293 | if (!codec_dai->codec->probed && | ||
1294 | codec_dai->codec->driver->probe_order == order) { | ||
1295 | ret = soc_probe_codec(card, codec_dai->codec); | ||
1296 | if (ret < 0) | ||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | /* probe the platform */ | ||
1301 | if (!platform->probed && | ||
1302 | platform->driver->probe_order == order) { | ||
1303 | ret = soc_probe_platform(card, platform); | ||
1304 | if (ret < 0) | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | return 0; | ||
1309 | } | ||
1310 | |||
1311 | static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | ||
1248 | { | 1312 | { |
1249 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1313 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1250 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1314 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
@@ -1292,22 +1356,6 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | |||
1292 | list_add(&cpu_dai->card_list, &card->dai_dev_list); | 1356 | list_add(&cpu_dai->card_list, &card->dai_dev_list); |
1293 | } | 1357 | } |
1294 | 1358 | ||
1295 | /* probe the CODEC */ | ||
1296 | if (!codec->probed && | ||
1297 | codec->driver->probe_order == order) { | ||
1298 | ret = soc_probe_codec(card, codec); | ||
1299 | if (ret < 0) | ||
1300 | return ret; | ||
1301 | } | ||
1302 | |||
1303 | /* probe the platform */ | ||
1304 | if (!platform->probed && | ||
1305 | platform->driver->probe_order == order) { | ||
1306 | ret = soc_probe_platform(card, platform); | ||
1307 | if (ret < 0) | ||
1308 | return ret; | ||
1309 | } | ||
1310 | |||
1311 | /* probe the CODEC DAI */ | 1359 | /* probe the CODEC DAI */ |
1312 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { | 1360 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { |
1313 | if (codec_dai->driver->probe) { | 1361 | if (codec_dai->driver->probe) { |
@@ -1582,14 +1630,27 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1582 | goto card_probe_error; | 1630 | goto card_probe_error; |
1583 | } | 1631 | } |
1584 | 1632 | ||
1585 | /* early DAI link probe */ | 1633 | /* probe all components used by DAI links on this card */ |
1586 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | 1634 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; |
1587 | order++) { | 1635 | order++) { |
1588 | for (i = 0; i < card->num_links; i++) { | 1636 | for (i = 0; i < card->num_links; i++) { |
1589 | ret = soc_probe_dai_link(card, i, order); | 1637 | ret = soc_probe_link_components(card, i, order); |
1590 | if (ret < 0) { | 1638 | if (ret < 0) { |
1591 | pr_err("asoc: failed to instantiate card %s: %d\n", | 1639 | pr_err("asoc: failed to instantiate card %s: %d\n", |
1592 | card->name, ret); | 1640 | card->name, ret); |
1641 | goto probe_dai_err; | ||
1642 | } | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | /* probe all DAI links on this card */ | ||
1647 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | ||
1648 | order++) { | ||
1649 | for (i = 0; i < card->num_links; i++) { | ||
1650 | ret = soc_probe_link_dais(card, i, order); | ||
1651 | if (ret < 0) { | ||
1652 | pr_err("asoc: failed to instantiate card %s: %d\n", | ||
1653 | card->name, ret); | ||
1593 | goto probe_dai_err; | 1654 | goto probe_dai_err; |
1594 | } | 1655 | } |
1595 | } | 1656 | } |