[PATCH] ASoC: rt5663: Cancel jack detect work on unbind

Myeonghun Pak posted 1 patch 2 days, 14 hours ago
sound/soc/codecs/rt5663.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
[PATCH] ASoC: rt5663: Cancel jack detect work on unbind
Posted by Myeonghun Pak 2 days, 14 hours ago
ASoC: rt5663: Cancel jack detect work on unbind

jack_detect_work and jd_unplug_work live in struct rt5663_priv, which
devres frees after rt5663_i2c_remove() returns.  The IRQ queues the
first work, a button press queues the second, and jd_unplug_work
rearms itself while the jack stays inserted.  Both callbacks load
rt5663->component before checking it, and nothing clears that pointer.
rt5663_suspend() cancels the works; unbind does not.

rt5663_remove() alone does not cover unbind.
snd_soc_del_component_unlocked() skips it when component->card is
NULL, which is true if the codec was never bound or the card was
already unbound.  The jack IRQ is requested before the component is
registered, so it can arm the work with no card, and it stays live
across a card unbind.

rt5663_i2c_remove() alone is not enough either.
rt5663_set_jack_detect() queues jack_detect_work even when clearing
the jack.  On a bound I2C unbind that call comes from
snd_soc_link_exit() after rt5663_i2c_remove() has returned.

Cancel both works after free_irq() in rt5663_i2c_remove(), and again
in rt5663_remove().  Cancel jack_detect_work first; it can queue
jd_unplug_work.

This issue was identified during our ongoing static-analysis research
while reviewing kernel code.

Fixes: df7c52168ee1 ("ASoC: add rt5663 codec driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
Found by inspection; not runtime tested.

 sound/soc/codecs/rt5663.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 262d3bba1f3d..2430bce31b3b 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -3179,6 +3179,13 @@ static void rt5663_remove(struct snd_soc_component *component)
 {
 	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
+	/*
+	 * Bound teardown runs this after snd_soc_link_exit().  set_jack()
+	 * there can queue jack_detect_work, which can queue jd_unplug_work.
+	 */
+	cancel_delayed_work_sync(&rt5663->jack_detect_work);
+	cancel_delayed_work_sync(&rt5663->jd_unplug_work);
+
 	regmap_write(rt5663->regmap, RT5663_RESET, 0);
 }
 
@@ -3728,6 +3735,13 @@ static void rt5663_i2c_remove(struct i2c_client *i2c)
 	if (i2c->irq)
 		free_irq(i2c->irq, rt5663);
 
+	/*
+	 * component .remove is skipped when component->card is NULL.
+	 * jack_detect_work can queue jd_unplug_work, so cancel it first.
+	 */
+	cancel_delayed_work_sync(&rt5663->jack_detect_work);
+	cancel_delayed_work_sync(&rt5663->jd_unplug_work);
+
 	regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
 }
 

base-commit: 238650ef6c7c7cca08e032527329424c9fbd70e5
-- 
2.53.0
Re: [PATCH] ASoC: rt5663: Cancel jack detect work on unbind
Posted by Mark Brown 2 days, 3 hours ago
On Mon, Sep 21, 2026 at 09:53:27PM -0400, Myeonghun Pak wrote:
> ASoC: rt5663: Cancel jack detect work on unbind

This is an extra copy.

> 
> jack_detect_work and jd_unplug_work live in struct rt5663_priv, which
> devres frees after rt5663_i2c_remove() returns.  The IRQ queues the
> first work, a button press queues the second, and jd_unplug_work
> rearms itself while the jack stays inserted.  Both callbacks load
> rt5663->component before checking it, and nothing clears that pointer.
> rt5663_suspend() cancels the works; unbind does not.

The same is true for the probe error handling, if we fail component
registration the same situation can happen.