aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorHans-Christian Egtvedt <hcegtvedt@atmel.com>2007-12-17 11:30:06 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:39 -0500
commitf488d9fcc84692ca0060b4e16c1c61a8d514cea8 (patch)
tree701cfaeb3f883a6cc7cfc65356c03d7221e55237 /sound
parentac3e37412c195f1b48fe06327eb4ad0c072a1222 (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>
Diffstat (limited to 'sound')
-rw-r--r--sound/spi/at73c213.c34
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