diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/usb/pcm.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3b5135c93062..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. |
@@ -237,6 +238,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
237 | subs->datainterval = fmt->datainterval; | 238 | subs->datainterval = fmt->datainterval; |
238 | subs->syncpipe = subs->syncinterval = 0; | 239 | subs->syncpipe = subs->syncinterval = 0; |
239 | subs->maxpacksize = fmt->maxpacksize; | 240 | subs->maxpacksize = fmt->maxpacksize; |
241 | subs->syncmaxsize = 0; | ||
240 | subs->fill_max = 0; | 242 | subs->fill_max = 0; |
241 | 243 | ||
242 | /* we need a sync pipe in async OUT or adaptive IN mode */ | 244 | /* we need a sync pipe in async OUT or adaptive IN mode */ |
@@ -283,6 +285,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
283 | subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; | 285 | subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; |
284 | else | 286 | else |
285 | subs->syncinterval = 3; | 287 | subs->syncinterval = 3; |
288 | subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); | ||
286 | } | 289 | } |
287 | 290 | ||
288 | /* always fill max packet size */ | 291 | /* always fill max packet size */ |
@@ -359,6 +362,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
359 | } | 362 | } |
360 | 363 | ||
361 | if (changed) { | 364 | if (changed) { |
365 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
362 | /* format changed */ | 366 | /* format changed */ |
363 | snd_usb_release_substream_urbs(subs, 0); | 367 | snd_usb_release_substream_urbs(subs, 0); |
364 | /* influenced: period_bytes, channels, rate, format, */ | 368 | /* influenced: period_bytes, channels, rate, format, */ |
@@ -366,6 +370,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
366 | params_rate(hw_params), | 370 | params_rate(hw_params), |
367 | snd_pcm_format_physical_width(params_format(hw_params)) * | 371 | snd_pcm_format_physical_width(params_format(hw_params)) * |
368 | params_channels(hw_params)); | 372 | params_channels(hw_params)); |
373 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
369 | } | 374 | } |
370 | 375 | ||
371 | return ret; | 376 | return ret; |
@@ -383,8 +388,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
383 | subs->cur_audiofmt = NULL; | 388 | subs->cur_audiofmt = NULL; |
384 | subs->cur_rate = 0; | 389 | subs->cur_rate = 0; |
385 | subs->period_bytes = 0; | 390 | subs->period_bytes = 0; |
386 | if (!subs->stream->chip->shutdown) | 391 | mutex_lock(&subs->stream->chip->shutdown_mutex); |
387 | snd_usb_release_substream_urbs(subs, 0); | 392 | snd_usb_release_substream_urbs(subs, 0); |
393 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
388 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 394 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
389 | } | 395 | } |
390 | 396 | ||
@@ -466,7 +472,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
466 | return 0; | 472 | return 0; |
467 | } | 473 | } |
468 | /* check whether the period time is >= the data packet interval */ | 474 | /* check whether the period time is >= the data packet interval */ |
469 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { | 475 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { |
470 | ptime = 125 * (1 << fp->datainterval); | 476 | ptime = 125 * (1 << fp->datainterval); |
471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 477 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 478 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
@@ -674,8 +680,10 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | |||
674 | if (!needs_knot) | 680 | if (!needs_knot) |
675 | return 0; | 681 | return 0; |
676 | 682 | ||
677 | subs->rate_list.count = count; | ||
678 | subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); | 683 | subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); |
684 | if (!subs->rate_list.list) | ||
685 | return -ENOMEM; | ||
686 | subs->rate_list.count = count; | ||
679 | subs->rate_list.mask = 0; | 687 | subs->rate_list.mask = 0; |
680 | count = 0; | 688 | count = 0; |
681 | list_for_each_entry(fp, &subs->fmt_list, list) { | 689 | list_for_each_entry(fp, &subs->fmt_list, list) { |
@@ -732,9 +740,12 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
732 | pt = 125 * (1 << fp->datainterval); | 740 | pt = 125 * (1 << fp->datainterval); |
733 | ptmin = min(ptmin, pt); | 741 | ptmin = min(ptmin, pt); |
734 | } | 742 | } |
743 | err = snd_usb_autoresume(subs->stream->chip); | ||
744 | if (err < 0) | ||
745 | return err; | ||
735 | 746 | ||
736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 747 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
737 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) | 748 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
738 | /* full speed devices have fixed data packet interval */ | 749 | /* full speed devices have fixed data packet interval */ |
739 | ptmin = 1000; | 750 | ptmin = 1000; |
740 | if (ptmin == 1000) | 751 | if (ptmin == 1000) |
@@ -749,21 +760,21 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
749 | SNDRV_PCM_HW_PARAM_CHANNELS, | 760 | SNDRV_PCM_HW_PARAM_CHANNELS, |
750 | param_period_time_if_needed, | 761 | param_period_time_if_needed, |
751 | -1)) < 0) | 762 | -1)) < 0) |
752 | return err; | 763 | goto rep_err; |
753 | 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, |
754 | hw_rule_channels, subs, | 765 | hw_rule_channels, subs, |
755 | SNDRV_PCM_HW_PARAM_FORMAT, | 766 | SNDRV_PCM_HW_PARAM_FORMAT, |
756 | SNDRV_PCM_HW_PARAM_RATE, | 767 | SNDRV_PCM_HW_PARAM_RATE, |
757 | param_period_time_if_needed, | 768 | param_period_time_if_needed, |
758 | -1)) < 0) | 769 | -1)) < 0) |
759 | return err; | 770 | goto rep_err; |
760 | 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, |
761 | hw_rule_format, subs, | 772 | hw_rule_format, subs, |
762 | SNDRV_PCM_HW_PARAM_RATE, | 773 | SNDRV_PCM_HW_PARAM_RATE, |
763 | SNDRV_PCM_HW_PARAM_CHANNELS, | 774 | SNDRV_PCM_HW_PARAM_CHANNELS, |
764 | param_period_time_if_needed, | 775 | param_period_time_if_needed, |
765 | -1)) < 0) | 776 | -1)) < 0) |
766 | return err; | 777 | goto rep_err; |
767 | if (param_period_time_if_needed >= 0) { | 778 | if (param_period_time_if_needed >= 0) { |
768 | err = snd_pcm_hw_rule_add(runtime, 0, | 779 | err = snd_pcm_hw_rule_add(runtime, 0, |
769 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | 780 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, |
@@ -773,11 +784,15 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
773 | SNDRV_PCM_HW_PARAM_RATE, | 784 | SNDRV_PCM_HW_PARAM_RATE, |
774 | -1); | 785 | -1); |
775 | if (err < 0) | 786 | if (err < 0) |
776 | return err; | 787 | goto rep_err; |
777 | } | 788 | } |
778 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | 789 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) |
779 | return err; | 790 | goto rep_err; |
780 | return 0; | 791 | return 0; |
792 | |||
793 | rep_err: | ||
794 | snd_usb_autosuspend(subs->stream->chip); | ||
795 | return err; | ||
781 | } | 796 | } |
782 | 797 | ||
783 | 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) |
@@ -791,6 +806,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
791 | runtime->hw = snd_usb_hardware; | 806 | runtime->hw = snd_usb_hardware; |
792 | runtime->private_data = subs; | 807 | runtime->private_data = subs; |
793 | subs->pcm_substream = substream; | 808 | subs->pcm_substream = substream; |
809 | /* runtime PM is also done there */ | ||
794 | return setup_hw_info(runtime, subs); | 810 | return setup_hw_info(runtime, subs); |
795 | } | 811 | } |
796 | 812 | ||
@@ -804,6 +820,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | |||
804 | subs->interface = -1; | 820 | subs->interface = -1; |
805 | } | 821 | } |
806 | subs->pcm_substream = NULL; | 822 | subs->pcm_substream = NULL; |
823 | snd_usb_autosuspend(subs->stream->chip); | ||
807 | return 0; | 824 | return 0; |
808 | } | 825 | } |
809 | 826 | ||