diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-01-28 22:32:10 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-01-28 22:32:10 +0100 |
commit | d832f3dcb6e2d153fbb69b91931058d138bc41cb (patch) | |
tree | b58210600b92bbe0c20c02724a47068682b99d5e /sound/i2c | |
parent | ALSA: usx2y: Move UAPI definition into include/uapi/sound/usb_stream.h (diff) | |
parent | ALSA: ak411x: Fix race of reinit() calls (diff) | |
download | linux-d832f3dcb6e2d153fbb69b91931058d138bc41cb.tar.xz linux-d832f3dcb6e2d153fbb69b91931058d138bc41cb.zip |
Merge branch 'topic/ak411x-fix' into for-next
Diffstat (limited to 'sound/i2c')
-rw-r--r-- | sound/i2c/other/ak4113.c | 36 | ||||
-rw-r--r-- | sound/i2c/other/ak4114.c | 46 |
2 files changed, 58 insertions, 24 deletions
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index 1a3a6fa27158..88844881cbff 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -56,8 +56,7 @@ static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) static void snd_ak4113_free(struct ak4113 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -89,6 +88,8 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4113_stats); + atomic_set(&chip->wq_processing, 0); + mutex_init(&chip->reinit_mutex); for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) chip->regmap[reg] = pgm[reg]; @@ -139,13 +140,13 @@ static void ak4113_init_regs(struct ak4113 *chip) void snd_ak4113_reinit(struct ak4113 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); + mutex_lock(&chip->reinit_mutex); ak4113_init_regs(chip); + mutex_unlock(&chip->reinit_mutex); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } EXPORT_SYMBOL_GPL(snd_ak4113_reinit); @@ -632,8 +633,25 @@ static void ak4113_stats(struct work_struct *work) { struct ak4113 *chip = container_of(work, struct ak4113, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4113_check_rate_and_errors(chip, chip->check_flags); - schedule_delayed_work(&chip->work, HZ / 10); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); +} + +#ifdef CONFIG_PM +void snd_ak4113_suspend(struct ak4113 *chip) +{ + atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); +} +EXPORT_SYMBOL(snd_ak4113_suspend); + +void snd_ak4113_resume(struct ak4113 *chip) +{ + atomic_dec(&chip->wq_processing); + snd_ak4113_reinit(chip); } +EXPORT_SYMBOL(snd_ak4113_resume); +#endif diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index c7f56339415d..5a4cf3fab4ae 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak4114) static void snd_ak4114_free(struct ak4114 *chip) { - chip->init = 1; /* don't schedule new work */ - mb(); + atomic_inc(&chip->wq_processing); /* don't schedule new work */ cancel_delayed_work_sync(&chip->work); kfree(chip); } @@ -100,6 +99,8 @@ int snd_ak4114_create(struct snd_card *card, chip->write = write; chip->private_data = private_data; INIT_DELAYED_WORK(&chip->work, ak4114_stats); + atomic_set(&chip->wq_processing, 0); + mutex_init(&chip->reinit_mutex); for (reg = 0; reg < 6; reg++) chip->regmap[reg] = pgm[reg]; @@ -122,6 +123,7 @@ int snd_ak4114_create(struct snd_card *card, snd_ak4114_free(chip); return err < 0 ? err : -EIO; } +EXPORT_SYMBOL(snd_ak4114_create); void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char mask, unsigned char val) { @@ -131,6 +133,7 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char reg_write(chip, reg, (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); } +EXPORT_SYMBOL(snd_ak4114_reg_write); static void ak4114_init_regs(struct ak4114 *chip) { @@ -152,15 +155,16 @@ static void ak4114_init_regs(struct ak4114 *chip) void snd_ak4114_reinit(struct ak4114 *chip) { - chip->init = 1; - mb(); - flush_delayed_work(&chip->work); + if (atomic_inc_return(&chip->wq_processing) == 1) + cancel_delayed_work_sync(&chip->work); + mutex_lock(&chip->reinit_mutex); ak4114_init_regs(chip); + mutex_unlock(&chip->reinit_mutex); /* bring up statistics / event queing */ - chip->init = 0; - if (chip->kctls[0]) + if (atomic_dec_and_test(&chip->wq_processing)) schedule_delayed_work(&chip->work, HZ / 10); } +EXPORT_SYMBOL(snd_ak4114_reinit); static unsigned int external_rate(unsigned char rcs1) { @@ -505,6 +509,7 @@ int snd_ak4114_build(struct ak4114 *ak4114, schedule_delayed_work(&ak4114->work, HZ / 10); return 0; } +EXPORT_SYMBOL(snd_ak4114_build); /* notify kcontrols if any parameters are changed */ static void ak4114_notify(struct ak4114 *ak4114, @@ -560,6 +565,7 @@ int snd_ak4114_external_rate(struct ak4114 *ak4114) rcs1 = reg_read(ak4114, AK4114_REG_RCS1); return external_rate(rcs1); } +EXPORT_SYMBOL(snd_ak4114_external_rate); int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) { @@ -607,20 +613,30 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) } return res; } +EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); static void ak4114_stats(struct work_struct *work) { struct ak4114 *chip = container_of(work, struct ak4114, work.work); - if (!chip->init) + if (atomic_inc_return(&chip->wq_processing) == 1) snd_ak4114_check_rate_and_errors(chip, chip->check_flags); + if (atomic_dec_and_test(&chip->wq_processing)) + schedule_delayed_work(&chip->work, HZ / 10); +} - schedule_delayed_work(&chip->work, HZ / 10); +#ifdef CONFIG_PM +void snd_ak4114_suspend(struct ak4114 *chip) +{ + atomic_inc(&chip->wq_processing); /* don't schedule new work */ + cancel_delayed_work_sync(&chip->work); } +EXPORT_SYMBOL(snd_ak4114_suspend); -EXPORT_SYMBOL(snd_ak4114_create); -EXPORT_SYMBOL(snd_ak4114_reg_write); -EXPORT_SYMBOL(snd_ak4114_reinit); -EXPORT_SYMBOL(snd_ak4114_build); -EXPORT_SYMBOL(snd_ak4114_external_rate); -EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); +void snd_ak4114_resume(struct ak4114 *chip) +{ + atomic_dec(&chip->wq_processing); + snd_ak4114_reinit(chip); +} +EXPORT_SYMBOL(snd_ak4114_resume); +#endif |