diff options
author | Hans-Christian Egtvedt | 2007-12-17 17:30:06 +0100 |
---|---|---|
committer | Jaroslav Kysela | 2008-01-31 17:29:39 +0100 |
commit | f488d9fcc84692ca0060b4e16c1c61a8d514cea8 (patch) | |
tree | 701cfaeb3f883a6cc7cfc65356c03d7221e55237 | |
parent | ac3e37412c195f1b48fe06327eb4ad0c072a1222 (diff) |
[ALSA] at73c213: replace spinlock in mixer functions with a mutex
This patch fixes the locking bug in the at73c213 SPI sound driver. This bug was
triggered because spinlocks were wrapped around the spi_sync call which might
sleep. The fix was to add a mutex to the sound driver and replace the spinlocks
in the mixer functions with mutex lock/unlock.
Tested on STK1000/STK1002.
Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | sound/spi/at73c213.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index bfe17b3ec8f4..5e8cf9f44ca3 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/io.h> @@ -76,8 +77,10 @@ struct snd_at73c213 { u8 spi_rbuffer[2]; /* Image of the SPI registers in AT73C213. */ u8 reg_image[18]; - /* Protect registers against concurrent access. */ + /* Protect SSC registers against concurrent access. */ spinlock_t lock; + /* Protect mixer registers against concurrent access. */ + struct mutex mixer_lock; }; #define get_chip(card) ((struct snd_at73c213 *)card->private_data) @@ -398,7 +401,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[reg] >> shift) & mask; @@ -407,7 +410,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); return 0; } @@ -428,13 +431,13 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, val = mask - val; val <<= shift; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); val = (chip->reg_image[reg] & ~(mask << shift)) | val; change = val != chip->reg_image[reg]; retval = snd_at73c213_write_reg(chip, reg, val); - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); if (retval) return retval; @@ -470,7 +473,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[left_reg] >> shift_left) & mask; @@ -484,7 +487,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, mask - ucontrol->value.integer.value[1]; } - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); return 0; } @@ -511,7 +514,7 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, val1 <<= shift_left; val2 <<= shift_right; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; @@ -519,16 +522,16 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, || val2 != chip->reg_image[right_reg]; retval = snd_at73c213_write_reg(chip, left_reg, val1); if (retval) { - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); goto out; } retval = snd_at73c213_write_reg(chip, right_reg, val2); if (retval) { - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); goto out; } - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); return change; @@ -546,7 +549,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); ucontrol->value.integer.value[0] = (chip->reg_image[reg] >> shift) & 0x01; @@ -555,7 +558,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = 0x01 - ucontrol->value.integer.value[0]; - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); return 0; } @@ -580,14 +583,14 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, val = mask - val; val <<= shift; - spin_lock_irq(&chip->lock); + mutex_lock(&chip->mixer_lock); val |= (chip->reg_image[reg] & ~(mask << shift)); change = val != chip->reg_image[reg]; retval = snd_at73c213_write_reg(chip, reg, val); - spin_unlock_irq(&chip->lock); + mutex_unlock(&chip->mixer_lock); if (retval) return retval; @@ -884,6 +887,7 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card, return irq; spin_lock_init(&chip->lock); + mutex_init(&chip->mixer_lock); chip->card = card; chip->irq = -1; |