diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-10-15 06:16:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-10-30 06:07:00 -0400 |
commit | 34f3c89fda4fba9fe689db22253ca8db2f5e6386 (patch) | |
tree | 213e1b6e6ceaee42dc4f9ec74307794dc7a83b20 /sound | |
parent | 978520b75f0a1ce82b17e1e8186417250de6d545 (diff) |
ALSA: usb-audio: Use rwsem for disconnect protection
Replace mutex with rwsem for codec->shutdown protection so that
concurrent accesses are allowed.
Also add the protection to snd_usb_autosuspend() and
snd_usb_autoresume(), too.
Reported-by: Matthieu CASTET <matthieu.castet@parrot.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/card.c | 12 | ||||
-rw-r--r-- | sound/usb/mixer.c | 12 | ||||
-rw-r--r-- | sound/usb/pcm.c | 12 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 2 |
4 files changed, 21 insertions, 17 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 561bb74fd364..282f0fc9fed1 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
339 | } | 339 | } |
340 | 340 | ||
341 | mutex_init(&chip->mutex); | 341 | mutex_init(&chip->mutex); |
342 | mutex_init(&chip->shutdown_mutex); | 342 | init_rwsem(&chip->shutdown_rwsem); |
343 | chip->index = idx; | 343 | chip->index = idx; |
344 | chip->dev = dev; | 344 | chip->dev = dev; |
345 | chip->card = card; | 345 | chip->card = card; |
@@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
560 | 560 | ||
561 | card = chip->card; | 561 | card = chip->card; |
562 | mutex_lock(®ister_mutex); | 562 | mutex_lock(®ister_mutex); |
563 | mutex_lock(&chip->shutdown_mutex); | 563 | down_write(&chip->shutdown_rwsem); |
564 | chip->shutdown = 1; | 564 | chip->shutdown = 1; |
565 | chip->num_interfaces--; | 565 | chip->num_interfaces--; |
566 | if (chip->num_interfaces <= 0) { | 566 | if (chip->num_interfaces <= 0) { |
@@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
582 | snd_usb_mixer_disconnect(p); | 582 | snd_usb_mixer_disconnect(p); |
583 | } | 583 | } |
584 | usb_chip[chip->index] = NULL; | 584 | usb_chip[chip->index] = NULL; |
585 | mutex_unlock(&chip->shutdown_mutex); | 585 | up_write(&chip->shutdown_rwsem); |
586 | mutex_unlock(®ister_mutex); | 586 | mutex_unlock(®ister_mutex); |
587 | snd_card_free_when_closed(card); | 587 | snd_card_free_when_closed(card); |
588 | } else { | 588 | } else { |
589 | mutex_unlock(&chip->shutdown_mutex); | 589 | up_write(&chip->shutdown_rwsem); |
590 | mutex_unlock(®ister_mutex); | 590 | mutex_unlock(®ister_mutex); |
591 | } | 591 | } |
592 | } | 592 | } |
@@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) | |||
618 | { | 618 | { |
619 | int err = -ENODEV; | 619 | int err = -ENODEV; |
620 | 620 | ||
621 | down_read(&chip->shutdown_rwsem); | ||
621 | if (!chip->shutdown && !chip->probing) | 622 | if (!chip->shutdown && !chip->probing) |
622 | err = usb_autopm_get_interface(chip->pm_intf); | 623 | err = usb_autopm_get_interface(chip->pm_intf); |
624 | up_read(&chip->shutdown_rwsem); | ||
623 | 625 | ||
624 | return err; | 626 | return err; |
625 | } | 627 | } |
626 | 628 | ||
627 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | 629 | void snd_usb_autosuspend(struct snd_usb_audio *chip) |
628 | { | 630 | { |
631 | down_read(&chip->shutdown_rwsem); | ||
629 | if (!chip->shutdown && !chip->probing) | 632 | if (!chip->shutdown && !chip->probing) |
630 | usb_autopm_put_interface(chip->pm_intf); | 633 | usb_autopm_put_interface(chip->pm_intf); |
634 | up_read(&chip->shutdown_rwsem); | ||
631 | } | 635 | } |
632 | 636 | ||
633 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 637 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c2ef11ccd66a..298070e8f2d4 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -292,7 +292,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v | |||
292 | err = snd_usb_autoresume(cval->mixer->chip); | 292 | err = snd_usb_autoresume(cval->mixer->chip); |
293 | if (err < 0) | 293 | if (err < 0) |
294 | return -EIO; | 294 | return -EIO; |
295 | mutex_lock(&chip->shutdown_mutex); | 295 | down_read(&chip->shutdown_rwsem); |
296 | while (timeout-- > 0) { | 296 | while (timeout-- > 0) { |
297 | if (chip->shutdown) | 297 | if (chip->shutdown) |
298 | break; | 298 | break; |
@@ -310,7 +310,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v | |||
310 | err = -EINVAL; | 310 | err = -EINVAL; |
311 | 311 | ||
312 | out: | 312 | out: |
313 | mutex_unlock(&chip->shutdown_mutex); | 313 | up_read(&chip->shutdown_rwsem); |
314 | snd_usb_autosuspend(cval->mixer->chip); | 314 | snd_usb_autosuspend(cval->mixer->chip); |
315 | return err; | 315 | return err; |
316 | } | 316 | } |
@@ -337,7 +337,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
337 | if (ret) | 337 | if (ret) |
338 | goto error; | 338 | goto error; |
339 | 339 | ||
340 | mutex_lock(&chip->shutdown_mutex); | 340 | down_read(&chip->shutdown_rwsem); |
341 | if (chip->shutdown) | 341 | if (chip->shutdown) |
342 | ret = -ENODEV; | 342 | ret = -ENODEV; |
343 | else { | 343 | else { |
@@ -346,7 +346,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
346 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 346 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
347 | validx, idx, buf, size); | 347 | validx, idx, buf, size); |
348 | } | 348 | } |
349 | mutex_unlock(&chip->shutdown_mutex); | 349 | up_read(&chip->shutdown_rwsem); |
350 | snd_usb_autosuspend(chip); | 350 | snd_usb_autosuspend(chip); |
351 | 351 | ||
352 | if (ret < 0) { | 352 | if (ret < 0) { |
@@ -453,7 +453,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
453 | err = snd_usb_autoresume(chip); | 453 | err = snd_usb_autoresume(chip); |
454 | if (err < 0) | 454 | if (err < 0) |
455 | return -EIO; | 455 | return -EIO; |
456 | mutex_lock(&chip->shutdown_mutex); | 456 | down_read(&chip->shutdown_rwsem); |
457 | while (timeout-- > 0) { | 457 | while (timeout-- > 0) { |
458 | if (chip->shutdown) | 458 | if (chip->shutdown) |
459 | break; | 459 | break; |
@@ -471,7 +471,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
471 | err = -EINVAL; | 471 | err = -EINVAL; |
472 | 472 | ||
473 | out: | 473 | out: |
474 | mutex_unlock(&chip->shutdown_mutex); | 474 | up_read(&chip->shutdown_rwsem); |
475 | snd_usb_autosuspend(chip); | 475 | snd_usb_autosuspend(chip); |
476 | return err; | 476 | return err; |
477 | } | 477 | } |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 55e741c5f231..37428f74dbb6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -503,12 +503,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
503 | return -EINVAL; | 503 | return -EINVAL; |
504 | } | 504 | } |
505 | 505 | ||
506 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 506 | down_read(&subs->stream->chip->shutdown_rwsem); |
507 | if (subs->stream->chip->shutdown) | 507 | if (subs->stream->chip->shutdown) |
508 | ret = -ENODEV; | 508 | ret = -ENODEV; |
509 | else | 509 | else |
510 | ret = set_format(subs, fmt); | 510 | ret = set_format(subs, fmt); |
511 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 511 | up_read(&subs->stream->chip->shutdown_rwsem); |
512 | if (ret < 0) | 512 | if (ret < 0) |
513 | return ret; | 513 | return ret; |
514 | 514 | ||
@@ -531,12 +531,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
531 | subs->cur_audiofmt = NULL; | 531 | subs->cur_audiofmt = NULL; |
532 | subs->cur_rate = 0; | 532 | subs->cur_rate = 0; |
533 | subs->period_bytes = 0; | 533 | subs->period_bytes = 0; |
534 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 534 | down_read(&subs->stream->chip->shutdown_rwsem); |
535 | if (!subs->stream->chip->shutdown) { | 535 | if (!subs->stream->chip->shutdown) { |
536 | stop_endpoints(subs, 0, 1, 1); | 536 | stop_endpoints(subs, 0, 1, 1); |
537 | deactivate_endpoints(subs); | 537 | deactivate_endpoints(subs); |
538 | } | 538 | } |
539 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 539 | up_read(&subs->stream->chip->shutdown_rwsem); |
540 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 540 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
541 | } | 541 | } |
542 | 542 | ||
@@ -558,7 +558,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
558 | return -ENXIO; | 558 | return -ENXIO; |
559 | } | 559 | } |
560 | 560 | ||
561 | mutex_lock(&subs->stream->chip->shutdown_mutex); | 561 | down_read(&subs->stream->chip->shutdown_rwsem); |
562 | if (subs->stream->chip->shutdown) { | 562 | if (subs->stream->chip->shutdown) { |
563 | ret = -ENODEV; | 563 | ret = -ENODEV; |
564 | goto unlock; | 564 | goto unlock; |
@@ -608,7 +608,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
608 | ret = start_endpoints(subs, 1); | 608 | ret = start_endpoints(subs, 1); |
609 | 609 | ||
610 | unlock: | 610 | unlock: |
611 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | 611 | up_read(&subs->stream->chip->shutdown_rwsem); |
612 | return ret; | 612 | return ret; |
613 | } | 613 | } |
614 | 614 | ||
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b8233ebe250f..ef42797f56fb 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -37,7 +37,7 @@ struct snd_usb_audio { | |||
37 | struct usb_interface *pm_intf; | 37 | struct usb_interface *pm_intf; |
38 | u32 usb_id; | 38 | u32 usb_id; |
39 | struct mutex mutex; | 39 | struct mutex mutex; |
40 | struct mutex shutdown_mutex; | 40 | struct rw_semaphore shutdown_rwsem; |
41 | unsigned int shutdown:1; | 41 | unsigned int shutdown:1; |
42 | unsigned int probing:1; | 42 | unsigned int probing:1; |
43 | unsigned int autosuspended:1; | 43 | unsigned int autosuspended:1; |