diff options
author | Hans-Christian Egtvedt <hcegtvedt@atmel.com> | 2007-12-17 11:30:06 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:39 -0500 |
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 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/mutex.h> | ||
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/io.h> | 23 | #include <linux/io.h> |
23 | 24 | ||
@@ -76,8 +77,10 @@ struct snd_at73c213 { | |||
76 | u8 spi_rbuffer[2]; | 77 | u8 spi_rbuffer[2]; |
77 | /* Image of the SPI registers in AT73C213. */ | 78 | /* Image of the SPI registers in AT73C213. */ |
78 | u8 reg_image[18]; | 79 | u8 reg_image[18]; |
79 | /* Protect registers against concurrent access. */ | 80 | /* Protect SSC registers against concurrent access. */ |
80 | spinlock_t lock; | 81 | spinlock_t lock; |
82 | /* Protect mixer registers against concurrent access. */ | ||
83 | struct mutex mixer_lock; | ||
81 | }; | 84 | }; |
82 | 85 | ||
83 | #define get_chip(card) ((struct snd_at73c213 *)card->private_data) | 86 | #define get_chip(card) ((struct snd_at73c213 *)card->private_data) |
@@ -398,7 +401,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, | |||
398 | int mask = (kcontrol->private_value >> 16) & 0xff; | 401 | int mask = (kcontrol->private_value >> 16) & 0xff; |
399 | int invert = (kcontrol->private_value >> 24) & 0xff; | 402 | int invert = (kcontrol->private_value >> 24) & 0xff; |
400 | 403 | ||
401 | spin_lock_irq(&chip->lock); | 404 | mutex_lock(&chip->mixer_lock); |
402 | 405 | ||
403 | ucontrol->value.integer.value[0] = | 406 | ucontrol->value.integer.value[0] = |
404 | (chip->reg_image[reg] >> shift) & mask; | 407 | (chip->reg_image[reg] >> shift) & mask; |
@@ -407,7 +410,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, | |||
407 | ucontrol->value.integer.value[0] = | 410 | ucontrol->value.integer.value[0] = |
408 | mask - ucontrol->value.integer.value[0]; | 411 | mask - ucontrol->value.integer.value[0]; |
409 | 412 | ||
410 | spin_unlock_irq(&chip->lock); | 413 | mutex_unlock(&chip->mixer_lock); |
411 | 414 | ||
412 | return 0; | 415 | return 0; |
413 | } | 416 | } |
@@ -428,13 +431,13 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, | |||
428 | val = mask - val; | 431 | val = mask - val; |
429 | val <<= shift; | 432 | val <<= shift; |
430 | 433 | ||
431 | spin_lock_irq(&chip->lock); | 434 | mutex_lock(&chip->mixer_lock); |
432 | 435 | ||
433 | val = (chip->reg_image[reg] & ~(mask << shift)) | val; | 436 | val = (chip->reg_image[reg] & ~(mask << shift)) | val; |
434 | change = val != chip->reg_image[reg]; | 437 | change = val != chip->reg_image[reg]; |
435 | retval = snd_at73c213_write_reg(chip, reg, val); | 438 | retval = snd_at73c213_write_reg(chip, reg, val); |
436 | 439 | ||
437 | spin_unlock_irq(&chip->lock); | 440 | mutex_unlock(&chip->mixer_lock); |
438 | 441 | ||
439 | if (retval) | 442 | if (retval) |
440 | return retval; | 443 | return retval; |
@@ -470,7 +473,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, | |||
470 | int mask = (kcontrol->private_value >> 24) & 0xff; | 473 | int mask = (kcontrol->private_value >> 24) & 0xff; |
471 | int invert = (kcontrol->private_value >> 22) & 1; | 474 | int invert = (kcontrol->private_value >> 22) & 1; |
472 | 475 | ||
473 | spin_lock_irq(&chip->lock); | 476 | mutex_lock(&chip->mixer_lock); |
474 | 477 | ||
475 | ucontrol->value.integer.value[0] = | 478 | ucontrol->value.integer.value[0] = |
476 | (chip->reg_image[left_reg] >> shift_left) & mask; | 479 | (chip->reg_image[left_reg] >> shift_left) & mask; |
@@ -484,7 +487,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, | |||
484 | mask - ucontrol->value.integer.value[1]; | 487 | mask - ucontrol->value.integer.value[1]; |
485 | } | 488 | } |
486 | 489 | ||
487 | spin_unlock_irq(&chip->lock); | 490 | mutex_unlock(&chip->mixer_lock); |
488 | 491 | ||
489 | return 0; | 492 | return 0; |
490 | } | 493 | } |
@@ -511,7 +514,7 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, | |||
511 | val1 <<= shift_left; | 514 | val1 <<= shift_left; |
512 | val2 <<= shift_right; | 515 | val2 <<= shift_right; |
513 | 516 | ||
514 | spin_lock_irq(&chip->lock); | 517 | mutex_lock(&chip->mixer_lock); |
515 | 518 | ||
516 | val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; | 519 | val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; |
517 | val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; | 520 | val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; |
@@ -519,16 +522,16 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, | |||
519 | || val2 != chip->reg_image[right_reg]; | 522 | || val2 != chip->reg_image[right_reg]; |
520 | retval = snd_at73c213_write_reg(chip, left_reg, val1); | 523 | retval = snd_at73c213_write_reg(chip, left_reg, val1); |
521 | if (retval) { | 524 | if (retval) { |
522 | spin_unlock_irq(&chip->lock); | 525 | mutex_unlock(&chip->mixer_lock); |
523 | goto out; | 526 | goto out; |
524 | } | 527 | } |
525 | retval = snd_at73c213_write_reg(chip, right_reg, val2); | 528 | retval = snd_at73c213_write_reg(chip, right_reg, val2); |
526 | if (retval) { | 529 | if (retval) { |
527 | spin_unlock_irq(&chip->lock); | 530 | mutex_unlock(&chip->mixer_lock); |
528 | goto out; | 531 | goto out; |
529 | } | 532 | } |
530 | 533 | ||
531 | spin_unlock_irq(&chip->lock); | 534 | mutex_unlock(&chip->mixer_lock); |
532 | 535 | ||
533 | return change; | 536 | return change; |
534 | 537 | ||
@@ -546,7 +549,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, | |||
546 | int shift = (kcontrol->private_value >> 8) & 0xff; | 549 | int shift = (kcontrol->private_value >> 8) & 0xff; |
547 | int invert = (kcontrol->private_value >> 24) & 0xff; | 550 | int invert = (kcontrol->private_value >> 24) & 0xff; |
548 | 551 | ||
549 | spin_lock_irq(&chip->lock); | 552 | mutex_lock(&chip->mixer_lock); |
550 | 553 | ||
551 | ucontrol->value.integer.value[0] = | 554 | ucontrol->value.integer.value[0] = |
552 | (chip->reg_image[reg] >> shift) & 0x01; | 555 | (chip->reg_image[reg] >> shift) & 0x01; |
@@ -555,7 +558,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, | |||
555 | ucontrol->value.integer.value[0] = | 558 | ucontrol->value.integer.value[0] = |
556 | 0x01 - ucontrol->value.integer.value[0]; | 559 | 0x01 - ucontrol->value.integer.value[0]; |
557 | 560 | ||
558 | spin_unlock_irq(&chip->lock); | 561 | mutex_unlock(&chip->mixer_lock); |
559 | 562 | ||
560 | return 0; | 563 | return 0; |
561 | } | 564 | } |
@@ -580,14 +583,14 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, | |||
580 | val = mask - val; | 583 | val = mask - val; |
581 | val <<= shift; | 584 | val <<= shift; |
582 | 585 | ||
583 | spin_lock_irq(&chip->lock); | 586 | mutex_lock(&chip->mixer_lock); |
584 | 587 | ||
585 | val |= (chip->reg_image[reg] & ~(mask << shift)); | 588 | val |= (chip->reg_image[reg] & ~(mask << shift)); |
586 | change = val != chip->reg_image[reg]; | 589 | change = val != chip->reg_image[reg]; |
587 | 590 | ||
588 | retval = snd_at73c213_write_reg(chip, reg, val); | 591 | retval = snd_at73c213_write_reg(chip, reg, val); |
589 | 592 | ||
590 | spin_unlock_irq(&chip->lock); | 593 | mutex_unlock(&chip->mixer_lock); |
591 | 594 | ||
592 | if (retval) | 595 | if (retval) |
593 | return retval; | 596 | return retval; |
@@ -884,6 +887,7 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card, | |||
884 | return irq; | 887 | return irq; |
885 | 888 | ||
886 | spin_lock_init(&chip->lock); | 889 | spin_lock_init(&chip->lock); |
890 | mutex_init(&chip->mixer_lock); | ||
887 | chip->card = card; | 891 | chip->card = card; |
888 | chip->irq = -1; | 892 | chip->irq = -1; |
889 | 893 | ||