diff options
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4132522ac90f..b8dcbf407bbb 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "helper.h" | 32 | #include "helper.h" |
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "clock.h" | 34 | #include "clock.h" |
35 | #include "power.h" | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * return the current pcm pointer. just based on the hwptr_done value. | 38 | * return the current pcm pointer. just based on the hwptr_done value. |
@@ -361,6 +362,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
361 | } | 362 | } |
362 | 363 | ||
363 | if (changed) { | 364 | if (changed) { |
365 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
364 | /* format changed */ | 366 | /* format changed */ |
365 | snd_usb_release_substream_urbs(subs, 0); | 367 | snd_usb_release_substream_urbs(subs, 0); |
366 | /* influenced: period_bytes, channels, rate, format, */ | 368 | /* influenced: period_bytes, channels, rate, format, */ |
@@ -368,6 +370,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
368 | params_rate(hw_params), | 370 | params_rate(hw_params), |
369 | snd_pcm_format_physical_width(params_format(hw_params)) * | 371 | snd_pcm_format_physical_width(params_format(hw_params)) * |
370 | params_channels(hw_params)); | 372 | params_channels(hw_params)); |
373 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
371 | } | 374 | } |
372 | 375 | ||
373 | return ret; | 376 | return ret; |
@@ -385,8 +388,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
385 | subs->cur_audiofmt = NULL; | 388 | subs->cur_audiofmt = NULL; |
386 | subs->cur_rate = 0; | 389 | subs->cur_rate = 0; |
387 | subs->period_bytes = 0; | 390 | subs->period_bytes = 0; |
388 | if (!subs->stream->chip->shutdown) | 391 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
389 | snd_usb_release_substream_urbs(subs, 0); | 392 | snd_usb_release_substream_urbs(subs, 0); |
393 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
390 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 394 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
391 | } | 395 | } |
392 | 396 | ||
@@ -736,6 +740,9 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
736 | pt = 125 * (1 << fp->datainterval); | 740 | pt = 125 * (1 << fp->datainterval); |
737 | ptmin = min(ptmin, pt); | 741 | ptmin = min(ptmin, pt); |
738 | } | 742 | } |
743 | err = snd_usb_autoresume(subs->stream->chip); | ||
744 | if (err < 0) | ||
745 | return err; | ||
739 | 746 | ||
740 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 747 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
741 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) | 748 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
@@ -753,21 +760,21 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
753 | SNDRV_PCM_HW_PARAM_CHANNELS, | 760 | SNDRV_PCM_HW_PARAM_CHANNELS, |
754 | param_period_time_if_needed, | 761 | param_period_time_if_needed, |
755 | -1)) < 0) | 762 | -1)) < 0) |
756 | return err; | 763 | goto rep_err; |
757 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 764 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
758 | hw_rule_channels, subs, | 765 | hw_rule_channels, subs, |
759 | SNDRV_PCM_HW_PARAM_FORMAT, | 766 | SNDRV_PCM_HW_PARAM_FORMAT, |
760 | SNDRV_PCM_HW_PARAM_RATE, | 767 | SNDRV_PCM_HW_PARAM_RATE, |
761 | param_period_time_if_needed, | 768 | param_period_time_if_needed, |
762 | -1)) < 0) | 769 | -1)) < 0) |
763 | return err; | 770 | goto rep_err; |
764 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | 771 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, |
765 | hw_rule_format, subs, | 772 | hw_rule_format, subs, |
766 | SNDRV_PCM_HW_PARAM_RATE, | 773 | SNDRV_PCM_HW_PARAM_RATE, |
767 | SNDRV_PCM_HW_PARAM_CHANNELS, | 774 | SNDRV_PCM_HW_PARAM_CHANNELS, |
768 | param_period_time_if_needed, | 775 | param_period_time_if_needed, |
769 | -1)) < 0) | 776 | -1)) < 0) |
770 | return err; | 777 | goto rep_err; |
771 | if (param_period_time_if_needed >= 0) { | 778 | if (param_period_time_if_needed >= 0) { |
772 | err = snd_pcm_hw_rule_add(runtime, 0, | 779 | err = snd_pcm_hw_rule_add(runtime, 0, |
773 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | 780 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, |
@@ -777,11 +784,15 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
777 | SNDRV_PCM_HW_PARAM_RATE, | 784 | SNDRV_PCM_HW_PARAM_RATE, |
778 | -1); | 785 | -1); |
779 | if (err < 0) | 786 | if (err < 0) |
780 | return err; | 787 | goto rep_err; |
781 | } | 788 | } |
782 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | 789 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) |
783 | return err; | 790 | goto rep_err; |
784 | return 0; | 791 | return 0; |
792 | |||
793 | rep_err: | ||
794 | snd_usb_autosuspend(subs->stream->chip); | ||
795 | return err; | ||
785 | } | 796 | } |
786 | 797 | ||
787 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | 798 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) |
@@ -795,6 +806,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
795 | runtime->hw = snd_usb_hardware; | 806 | runtime->hw = snd_usb_hardware; |
796 | runtime->private_data = subs; | 807 | runtime->private_data = subs; |
797 | subs->pcm_substream = substream; | 808 | subs->pcm_substream = substream; |
809 | /* runtime PM is also done there */ | ||
798 | return setup_hw_info(runtime, subs); | 810 | return setup_hw_info(runtime, subs); |
799 | } | 811 | } |
800 | 812 | ||
@@ -808,6 +820,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | |||
808 | subs->interface = -1; | 820 | subs->interface = -1; |
809 | } | 821 | } |
810 | subs->pcm_substream = NULL; | 822 | subs->pcm_substream = NULL; |
823 | snd_usb_autosuspend(subs->stream->chip); | ||
811 | return 0; | 824 | return 0; |
812 | } | 825 | } |
813 | 826 | ||