Skip to content

Commit 578ccfe

Browse files
Ma Kebroonie
authored andcommitted
ASoC: codecs: wcd937x: Fix error handling in wcd937x codec driver
In wcd937x_bind(), the driver calls of_sdw_find_device_by_node() to obtain references to RX and TX SoundWire devices, which increment the device reference counts. However, the corresponding put_device() are missing in both the error paths and the normal unbind path in wcd937x_unbind(). Add proper error handling with put_device() calls in all error paths of wcd937x_bind() and ensure devices are released in wcd937x_unbind(). Found by code review. Cc: stable@vger.kernel.org Fixes: 772ed12 ("ASoC: codecs: wcdxxxx: use of_sdw_find_device_by_node helper") Signed-off-by: Ma Ke <make24@iscas.ac.cn> Reviewed-by: David Heidelberg <david@ixit.cz> Link: https://patch.msgid.link/20251116061623.11830-1-make24@iscas.ac.cn Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 6a23ae0 commit 578ccfe

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

sound/soc/codecs/wcd937x.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,7 +2748,8 @@ static int wcd937x_bind(struct device *dev)
27482748
wcd937x->rxdev = of_sdw_find_device_by_node(wcd937x->rxnode);
27492749
if (!wcd937x->rxdev) {
27502750
dev_err(dev, "could not find slave with matching of node\n");
2751-
return -EINVAL;
2751+
ret = -EINVAL;
2752+
goto err_component_unbind;
27522753
}
27532754

27542755
wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev);
@@ -2757,15 +2758,17 @@ static int wcd937x_bind(struct device *dev)
27572758
wcd937x->txdev = of_sdw_find_device_by_node(wcd937x->txnode);
27582759
if (!wcd937x->txdev) {
27592760
dev_err(dev, "could not find txslave with matching of node\n");
2760-
return -EINVAL;
2761+
ret = -EINVAL;
2762+
goto err_put_rxdev;
27612763
}
27622764

27632765
wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev);
27642766
wcd937x->sdw_priv[AIF1_CAP]->wcd937x = wcd937x;
27652767
wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev);
27662768
if (!wcd937x->tx_sdw_dev) {
27672769
dev_err(dev, "could not get txslave with matching of dev\n");
2768-
return -EINVAL;
2770+
ret = -EINVAL;
2771+
goto err_put_txdev;
27692772
}
27702773

27712774
/*
@@ -2775,31 +2778,35 @@ static int wcd937x_bind(struct device *dev)
27752778
if (!device_link_add(wcd937x->rxdev, wcd937x->txdev,
27762779
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
27772780
dev_err(dev, "Could not devlink TX and RX\n");
2778-
return -EINVAL;
2781+
ret = -EINVAL;
2782+
goto err_put_txdev;
27792783
}
27802784

27812785
if (!device_link_add(dev, wcd937x->txdev,
27822786
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
27832787
dev_err(dev, "Could not devlink WCD and TX\n");
2784-
return -EINVAL;
2788+
ret = -EINVAL;
2789+
goto err_remove_link1;
27852790
}
27862791

27872792
if (!device_link_add(dev, wcd937x->rxdev,
27882793
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
27892794
dev_err(dev, "Could not devlink WCD and RX\n");
2790-
return -EINVAL;
2795+
ret = -EINVAL;
2796+
goto err_remove_link2;
27912797
}
27922798

27932799
wcd937x->regmap = wcd937x->sdw_priv[AIF1_CAP]->regmap;
27942800
if (!wcd937x->regmap) {
27952801
dev_err(dev, "could not get TX device regmap\n");
2796-
return -EINVAL;
2802+
ret = -EINVAL;
2803+
goto err_remove_link3;
27972804
}
27982805

27992806
ret = wcd937x_irq_init(wcd937x, dev);
28002807
if (ret) {
28012808
dev_err(dev, "IRQ init failed: %d\n", ret);
2802-
return ret;
2809+
goto err_remove_link3;
28032810
}
28042811

28052812
wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq;
@@ -2809,10 +2816,26 @@ static int wcd937x_bind(struct device *dev)
28092816

28102817
ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x,
28112818
wcd937x_dais, ARRAY_SIZE(wcd937x_dais));
2812-
if (ret)
2819+
if (ret) {
28132820
dev_err(dev, "Codec registration failed\n");
2821+
goto err_remove_link3;
2822+
}
28142823

28152824
return ret;
2825+
2826+
err_remove_link3:
2827+
device_link_remove(dev, wcd937x->rxdev);
2828+
err_remove_link2:
2829+
device_link_remove(dev, wcd937x->txdev);
2830+
err_remove_link1:
2831+
device_link_remove(wcd937x->rxdev, wcd937x->txdev);
2832+
err_put_txdev:
2833+
put_device(wcd937x->txdev);
2834+
err_put_rxdev:
2835+
put_device(wcd937x->rxdev);
2836+
err_component_unbind:
2837+
component_unbind_all(dev, wcd937x);
2838+
return ret;
28162839
}
28172840

28182841
static void wcd937x_unbind(struct device *dev)
@@ -2825,6 +2848,8 @@ static void wcd937x_unbind(struct device *dev)
28252848
device_link_remove(wcd937x->rxdev, wcd937x->txdev);
28262849
component_unbind_all(dev, wcd937x);
28272850
mutex_destroy(&wcd937x->micb_lock);
2851+
put_device(wcd937x->txdev);
2852+
put_device(wcd937x->rxdev);
28282853
}
28292854

28302855
static const struct component_master_ops wcd937x_comp_ops = {

0 commit comments

Comments
 (0)