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 | |
| 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>
| -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; |
