]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
ASoC: codecs: wcd-mbhc-v2: fix resource leaks on component remove
authorJohan Hovold <johan+linaro@kernel.org>
Wed, 5 Jul 2023 12:30:16 +0000 (14:30 +0200)
committerRoxana Nicolescu <roxana.nicolescu@canonical.com>
Mon, 2 Oct 2023 15:20:33 +0000 (17:20 +0200)
BugLink: https://bugs.launchpad.net/bugs/2037005
commit a5475829adcc600bc69ee9ff7c9e3e43fb4f8d30 upstream.

The MBHC resources must be released on component probe failure and
removal so can not be tied to the lifetime of the component device.

This is specifically needed to allow probe deferrals of the sound card
which otherwise fails when reprobing the codec component:

    snd-sc8280xp sound: ASoC: failed to instantiate card -517
    genirq: Flags mismatch irq 299. 00002001 (mbhc sw intr) vs. 00002001 (mbhc sw intr)
    wcd938x_codec audio-codec: Failed to request mbhc interrupts -16
    wcd938x_codec audio-codec: mbhc initialization failed
    wcd938x_codec audio-codec: ASoC: error at snd_soc_component_probe on audio-codec: -16
    snd-sc8280xp sound: ASoC: failed to instantiate card -16

Fixes: 0e5c9e7ff899 ("ASoC: codecs: wcd: add multi button Headset detection support")
Cc: stable@vger.kernel.org # 5.14
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20230705123018.30903-7-johan+linaro@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
sound/soc/codecs/wcd-mbhc-v2.c

index 1911750f7445c8fb50ba3c39dd8877ee7c0e6475..5da1934527f347019bdc71bff8f00ea7e93307ca 100644 (file)
@@ -1454,7 +1454,7 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
                return ERR_PTR(-EINVAL);
        }
 
-       mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
+       mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL);
        if (!mbhc)
                return ERR_PTR(-ENOMEM);
 
@@ -1474,61 +1474,76 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
 
        INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL,
                                        wcd_mbhc_mech_plug_detect_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "mbhc sw intr", mbhc);
        if (ret)
-               goto err;
+               goto err_free_mbhc;
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL,
                                        wcd_mbhc_btn_press_handler,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "Button Press detect", mbhc);
        if (ret)
-               goto err;
+               goto err_free_sw_intr;
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL,
                                        wcd_mbhc_btn_release_handler,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "Button Release detect", mbhc);
        if (ret)
-               goto err;
+               goto err_free_btn_press_intr;
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
                                        wcd_mbhc_adc_hs_ins_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "Elect Insert", mbhc);
        if (ret)
-               goto err;
+               goto err_free_btn_release_intr;
 
        disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
                                        wcd_mbhc_adc_hs_rem_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "Elect Remove", mbhc);
        if (ret)
-               goto err;
+               goto err_free_hs_ins_intr;
 
        disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL,
                                        wcd_mbhc_hphl_ocp_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "HPH_L OCP detect", mbhc);
        if (ret)
-               goto err;
+               goto err_free_hs_rem_intr;
 
-       ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL,
+       ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL,
                                        wcd_mbhc_hphr_ocp_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_RISING,
                                        "HPH_R OCP detect", mbhc);
        if (ret)
-               goto err;
+               goto err_free_hph_left_ocp;
 
        return mbhc;
-err:
+
+err_free_hph_left_ocp:
+       free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
+err_free_hs_rem_intr:
+       free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+err_free_hs_ins_intr:
+       free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+err_free_btn_release_intr:
+       free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
+err_free_btn_press_intr:
+       free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
+err_free_sw_intr:
+       free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
+err_free_mbhc:
+       kfree(mbhc);
+
        dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
 
        return ERR_PTR(ret);
@@ -1537,9 +1552,19 @@ EXPORT_SYMBOL(wcd_mbhc_init);
 
 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
 {
+       free_irq(mbhc->intr_ids->hph_right_ocp, mbhc);
+       free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
+       free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+       free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+       free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
+       free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
+       free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
+
        mutex_lock(&mbhc->lock);
        wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
        mutex_unlock(&mbhc->lock);
+
+       kfree(mbhc);
 }
 EXPORT_SYMBOL(wcd_mbhc_deinit);