If the card registration fails, typically because of deferred probes, the device properties added for headset codecs are not removed, which leads to kernel oopses in driver bind/unbind tests. We already clean-up the device properties when the card is removed, this code can be moved as a helper and called upon card registration errors.
Unified · Split
| @@ -1398,6 +1398,33 @@ static struct snd_soc_card card_sof_sdw = { · 1397 unmodified lines | |||
| 1398 | .late_probe = sof_sdw_card_late_probe, | 1398 | .late_probe = sof_sdw_card_late_probe, |
| 1399 | }; | 1399 | }; |
| 1400 | 1400 | ||
| 1401 | static void mc_dailink_exit_loop(struct snd_soc_card *card) | ||
| 1402 | { | ||
| 1403 | struct snd_soc_dai_link *link; | ||
| 1404 | int ret; | ||
| 1405 | int i, j; | ||
| 1406 | |||
| 1407 | for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { | ||
| 1408 | if (!codec_info_list[i].exit) | ||
| 1409 | continue; | ||
| 1410 | /* | ||
| 1411 | * We don't need to call .exit function if there is no matched | ||
| 1412 | * dai link found. | ||
| 1413 | */ | ||
| 1414 | for_each_card_prelinks(card, j, link) { | ||
| 1415 | if (!strcmp(link->codecs[0].dai_name, | ||
| 1416 | codec_info_list[i].dai_name)) { | ||
| 1417 | ret = codec_info_list[i].exit(card, link); | ||
| 1418 | if (ret) | ||
| 1419 | dev_warn(card->dev, | ||
| 1420 | "codec exit failed %d\n", | ||
| 1421 | ret); | ||
| 1422 | break; | ||
| 1423 | } | ||
| 1424 | } | ||
| 1425 | } | ||
| 1426 | } | ||
| 1427 | |||
| 1401 | static int mc_probe(struct platform_device *pdev) | 1428 | static int mc_probe(struct platform_device *pdev) |
| 1402 | { | 1429 | { |
| 1403 | struct snd_soc_card *card = &card_sof_sdw; | 1430 | struct snd_soc_card *card = &card_sof_sdw; |
| @@ -1462,6 +1489,7 @@ static int mc_probe(struct platform_device *pdev) · 58 unmodified lines | |||
| 1462 | ret = devm_snd_soc_register_card(&pdev->dev, card); | 1489 | ret = devm_snd_soc_register_card(&pdev->dev, card); |
| 1463 | if (ret) { | 1490 | if (ret) { |
| 1464 | dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); | 1491 | dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); |
| 1492 | mc_dailink_exit_loop(card); | ||
| 1465 | return ret; | 1493 | return ret; |
| 1466 | } | 1494 | } |
| 1467 | 1495 | ||
| @@ -1473,29 +1501,8 @@ static int mc_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 1473 | static int mc_remove(struct platform_device *pdev) | 1501 | static int mc_remove(struct platform_device *pdev) |
| 1474 | { | 1502 | { |
| 1475 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1503 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
| 1476 | struct snd_soc_dai_link *link; | ||
| 1477 | int ret; | ||
| 1478 | int i, j; | ||
| 1479 | 1504 | ||
| 1480 | for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { | 1505 | mc_dailink_exit_loop(card); |
| 1481 | if (!codec_info_list[i].exit) | ||
| 1482 | continue; | ||
| 1483 | /* | ||
| 1484 | * We don't need to call .exit function if there is no matched | ||
| 1485 | * dai link found. | ||
| 1486 | */ | ||
| 1487 | for_each_card_prelinks(card, j, link) { | ||
| 1488 | if (!strcmp(link->codecs[0].dai_name, | ||
| 1489 | codec_info_list[i].dai_name)) { | ||
| 1490 | ret = codec_info_list[i].exit(card, link); | ||
| 1491 | if (ret) | ||
| 1492 | dev_warn(&pdev->dev, | ||
| 1493 | "codec exit failed %d\n", | ||
| 1494 | ret); | ||
| 1495 | break; | ||
| 1496 | } | ||
| 1497 | } | ||
| 1498 | } | ||
| 1499 | 1506 | ||
| 1500 | return 0; | 1507 | return 0; |
| 1501 | } | 1508 | } |