Fix: close work_switch when codec removeing

This commit is contained in:
turmary 2018-04-24 04:28:14 +00:00
parent d0d9107c91
commit 0548a6d0a3

45
ac101.c
View file

@ -105,13 +105,6 @@ int ac101_update_bits(struct snd_soc_codec *codec, unsigned reg,
#define KEY_HEADSETHOOK 226 /* key define */ #define KEY_HEADSETHOOK 226 /* key define */
#define HEADSET_FILTER_CNT (10) #define HEADSET_FILTER_CNT (10)
#define _AC101_CREATE_QUEUE 0
#if _AC101_CREATE_QUEUE
static struct workqueue_struct *queue_switch_detect;
static struct workqueue_struct *queue_codec_irq;
#endif
/* /*
* switch_hw_config:config the 53 codec register * switch_hw_config:config the 53 codec register
*/ */
@ -199,11 +192,7 @@ static void work_cb_clear_irq(struct work_struct *work)
ac10x->irq_cntr--; ac10x->irq_cntr--;
} }
#if _AC101_CREATE_QUEUE
if (0 == queue_work(queue_switch_detect, &ac10x->work_switch)) {
#else
if (0 == schedule_work(&ac10x->work_switch)) { if (0 == schedule_work(&ac10x->work_switch)) {
#endif
ac10x->irq_cntr--; ac10x->irq_cntr--;
AC101_DBG("[work_cb_clear_irq] add work struct failed!\n"); AC101_DBG("[work_cb_clear_irq] add work struct failed!\n");
} }
@ -218,7 +207,9 @@ enum {
}; };
static int __ac101_get_hmic_data(struct snd_soc_codec *codec) { static int __ac101_get_hmic_data(struct snd_soc_codec *codec) {
#ifdef AC101_DEBG
static long counter; static long counter;
#endif
int r; int r;
int d; int d;
@ -315,7 +306,7 @@ static void work_cb_earphone_switch(struct work_struct *work)
} }
} }
} else { } else {
while (ac10x->irq_cntr == 0) { while (ac10x->irq_cntr == 0 && ac10x->irq != 0) {
msleep(20); msleep(20);
t = __ac101_get_hmic_data(codec); t = __ac101_get_hmic_data(codec);
@ -357,17 +348,7 @@ static irqreturn_t audio_hmic_irq(int irq, void *para)
return -EINVAL; return -EINVAL;
} }
#if _AC101_CREATE_QUEUE
if (queue_codec_irq == NULL) {
AC101_DBG("------------queue_codec_irq is null !!----------");
return IRQ_NONE;
}
if (0 == queue_work(queue_codec_irq, &ac10x->work_clear_irq)){
#else
if (0 == schedule_work(&ac10x->work_clear_irq)){ if (0 == schedule_work(&ac10x->work_clear_irq)){
#endif
AC101_DBG("[audio_hmic_irq] work already in queue_codec_irq, adding failed!\n"); AC101_DBG("[audio_hmic_irq] work already in queue_codec_irq, adding failed!\n");
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -437,27 +418,10 @@ static int ac101_switch_probe(struct ac10x_priv *ac10x) {
/* the first headset state checking */ /* the first headset state checking */
switch_hw_config(ac10x->codec); switch_hw_config(ac10x->codec);
ac10x->irq_cntr = 1; ac10x->irq_cntr = 1;
#if _AC101_CREATE_QUEUE
queue_codec_irq = create_singlethread_workqueue("codec_irq");
queue_switch_detect = create_singlethread_workqueue("codec_switch");
if (queue_switch_detect == NULL || queue_codec_irq == NULL) {
AC101_DBG("try to create workqueue for codec failed!\n");
ret = -ENOMEM;
goto _err_switch_work_queue;
}
queue_work(queue_switch_detect, &ac10x->work_switch);
#else
schedule_work(&ac10x->work_switch); schedule_work(&ac10x->work_switch);
#endif
return 0; return 0;
#if _AC101_CREATE_QUEUE
_err_switch_work_queue:
input_unregister_device(ac10x->inpdev);
#endif
_err_input_register_device: _err_input_register_device:
_err_input_allocate_device: _err_input_allocate_device:
@ -1479,6 +1443,9 @@ int ac101_codec_remove(struct snd_soc_codec *codec)
/* devm_free_irq(codec->dev, ac10x->irq, NULL); */ /* devm_free_irq(codec->dev, ac10x->irq, NULL); */
ac10x->irq = 0; ac10x->irq = 0;
} }
if (cancel_work_sync(&ac10x->work_switch) != 0) {
}
#endif #endif
return 0; return 0;