diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2018-01-27 09:35:29 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-01-27 09:35:29 -0500 |
commit | 303c146df1c4574db3495d9acc5c440dd46c6b0f (patch) | |
tree | fbcea289aea24da8a44c7677a776988bb3c8bcbe /sound/drivers | |
parent | b1a31a5f5f27ff8aba42b545a1c721941f735107 (diff) | |
parent | d5421ea43d30701e03cadc56a38854c36a8b4433 (diff) |
Merge branch 'timers/urgent' into timers/core
Pick up urgent bug fix and resolve the conflict.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/aloop.c | 98 |
1 files changed, 50 insertions, 48 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index afac886ffa28..0333143a1fa7 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <sound/core.h> | 39 | #include <sound/core.h> |
40 | #include <sound/control.h> | 40 | #include <sound/control.h> |
41 | #include <sound/pcm.h> | 41 | #include <sound/pcm.h> |
42 | #include <sound/pcm_params.h> | ||
42 | #include <sound/info.h> | 43 | #include <sound/info.h> |
43 | #include <sound/initval.h> | 44 | #include <sound/initval.h> |
44 | 45 | ||
@@ -305,19 +306,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
305 | return 0; | 306 | return 0; |
306 | } | 307 | } |
307 | 308 | ||
308 | static void params_change_substream(struct loopback_pcm *dpcm, | ||
309 | struct snd_pcm_runtime *runtime) | ||
310 | { | ||
311 | struct snd_pcm_runtime *dst_runtime; | ||
312 | |||
313 | if (dpcm == NULL || dpcm->substream == NULL) | ||
314 | return; | ||
315 | dst_runtime = dpcm->substream->runtime; | ||
316 | if (dst_runtime == NULL) | ||
317 | return; | ||
318 | dst_runtime->hw = dpcm->cable->hw; | ||
319 | } | ||
320 | |||
321 | static void params_change(struct snd_pcm_substream *substream) | 309 | static void params_change(struct snd_pcm_substream *substream) |
322 | { | 310 | { |
323 | struct snd_pcm_runtime *runtime = substream->runtime; | 311 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -329,10 +317,6 @@ static void params_change(struct snd_pcm_substream *substream) | |||
329 | cable->hw.rate_max = runtime->rate; | 317 | cable->hw.rate_max = runtime->rate; |
330 | cable->hw.channels_min = runtime->channels; | 318 | cable->hw.channels_min = runtime->channels; |
331 | cable->hw.channels_max = runtime->channels; | 319 | cable->hw.channels_max = runtime->channels; |
332 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
333 | runtime); | ||
334 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
335 | runtime); | ||
336 | } | 320 | } |
337 | 321 | ||
338 | static int loopback_prepare(struct snd_pcm_substream *substream) | 322 | static int loopback_prepare(struct snd_pcm_substream *substream) |
@@ -620,26 +604,29 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream) | |||
620 | static int rule_format(struct snd_pcm_hw_params *params, | 604 | static int rule_format(struct snd_pcm_hw_params *params, |
621 | struct snd_pcm_hw_rule *rule) | 605 | struct snd_pcm_hw_rule *rule) |
622 | { | 606 | { |
607 | struct loopback_pcm *dpcm = rule->private; | ||
608 | struct loopback_cable *cable = dpcm->cable; | ||
609 | struct snd_mask m; | ||
623 | 610 | ||
624 | struct snd_pcm_hardware *hw = rule->private; | 611 | snd_mask_none(&m); |
625 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | 612 | mutex_lock(&dpcm->loopback->cable_lock); |
626 | 613 | m.bits[0] = (u_int32_t)cable->hw.formats; | |
627 | maskp->bits[0] &= (u_int32_t)hw->formats; | 614 | m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); |
628 | maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); | 615 | mutex_unlock(&dpcm->loopback->cable_lock); |
629 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ | 616 | return snd_mask_refine(hw_param_mask(params, rule->var), &m); |
630 | if (! maskp->bits[0] && ! maskp->bits[1]) | ||
631 | return -EINVAL; | ||
632 | return 0; | ||
633 | } | 617 | } |
634 | 618 | ||
635 | static int rule_rate(struct snd_pcm_hw_params *params, | 619 | static int rule_rate(struct snd_pcm_hw_params *params, |
636 | struct snd_pcm_hw_rule *rule) | 620 | struct snd_pcm_hw_rule *rule) |
637 | { | 621 | { |
638 | struct snd_pcm_hardware *hw = rule->private; | 622 | struct loopback_pcm *dpcm = rule->private; |
623 | struct loopback_cable *cable = dpcm->cable; | ||
639 | struct snd_interval t; | 624 | struct snd_interval t; |
640 | 625 | ||
641 | t.min = hw->rate_min; | 626 | mutex_lock(&dpcm->loopback->cable_lock); |
642 | t.max = hw->rate_max; | 627 | t.min = cable->hw.rate_min; |
628 | t.max = cable->hw.rate_max; | ||
629 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
643 | t.openmin = t.openmax = 0; | 630 | t.openmin = t.openmax = 0; |
644 | t.integer = 0; | 631 | t.integer = 0; |
645 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | 632 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); |
@@ -648,22 +635,44 @@ static int rule_rate(struct snd_pcm_hw_params *params, | |||
648 | static int rule_channels(struct snd_pcm_hw_params *params, | 635 | static int rule_channels(struct snd_pcm_hw_params *params, |
649 | struct snd_pcm_hw_rule *rule) | 636 | struct snd_pcm_hw_rule *rule) |
650 | { | 637 | { |
651 | struct snd_pcm_hardware *hw = rule->private; | 638 | struct loopback_pcm *dpcm = rule->private; |
639 | struct loopback_cable *cable = dpcm->cable; | ||
652 | struct snd_interval t; | 640 | struct snd_interval t; |
653 | 641 | ||
654 | t.min = hw->channels_min; | 642 | mutex_lock(&dpcm->loopback->cable_lock); |
655 | t.max = hw->channels_max; | 643 | t.min = cable->hw.channels_min; |
644 | t.max = cable->hw.channels_max; | ||
645 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
656 | t.openmin = t.openmax = 0; | 646 | t.openmin = t.openmax = 0; |
657 | t.integer = 0; | 647 | t.integer = 0; |
658 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | 648 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); |
659 | } | 649 | } |
660 | 650 | ||
651 | static void free_cable(struct snd_pcm_substream *substream) | ||
652 | { | ||
653 | struct loopback *loopback = substream->private_data; | ||
654 | int dev = get_cable_index(substream); | ||
655 | struct loopback_cable *cable; | ||
656 | |||
657 | cable = loopback->cables[substream->number][dev]; | ||
658 | if (!cable) | ||
659 | return; | ||
660 | if (cable->streams[!substream->stream]) { | ||
661 | /* other stream is still alive */ | ||
662 | cable->streams[substream->stream] = NULL; | ||
663 | } else { | ||
664 | /* free the cable */ | ||
665 | loopback->cables[substream->number][dev] = NULL; | ||
666 | kfree(cable); | ||
667 | } | ||
668 | } | ||
669 | |||
661 | static int loopback_open(struct snd_pcm_substream *substream) | 670 | static int loopback_open(struct snd_pcm_substream *substream) |
662 | { | 671 | { |
663 | struct snd_pcm_runtime *runtime = substream->runtime; | 672 | struct snd_pcm_runtime *runtime = substream->runtime; |
664 | struct loopback *loopback = substream->private_data; | 673 | struct loopback *loopback = substream->private_data; |
665 | struct loopback_pcm *dpcm; | 674 | struct loopback_pcm *dpcm; |
666 | struct loopback_cable *cable; | 675 | struct loopback_cable *cable = NULL; |
667 | int err = 0; | 676 | int err = 0; |
668 | int dev = get_cable_index(substream); | 677 | int dev = get_cable_index(substream); |
669 | 678 | ||
@@ -681,7 +690,6 @@ static int loopback_open(struct snd_pcm_substream *substream) | |||
681 | if (!cable) { | 690 | if (!cable) { |
682 | cable = kzalloc(sizeof(*cable), GFP_KERNEL); | 691 | cable = kzalloc(sizeof(*cable), GFP_KERNEL); |
683 | if (!cable) { | 692 | if (!cable) { |
684 | kfree(dpcm); | ||
685 | err = -ENOMEM; | 693 | err = -ENOMEM; |
686 | goto unlock; | 694 | goto unlock; |
687 | } | 695 | } |
@@ -699,19 +707,19 @@ static int loopback_open(struct snd_pcm_substream *substream) | |||
699 | /* are cached -> they do not reflect the actual state */ | 707 | /* are cached -> they do not reflect the actual state */ |
700 | err = snd_pcm_hw_rule_add(runtime, 0, | 708 | err = snd_pcm_hw_rule_add(runtime, 0, |
701 | SNDRV_PCM_HW_PARAM_FORMAT, | 709 | SNDRV_PCM_HW_PARAM_FORMAT, |
702 | rule_format, &runtime->hw, | 710 | rule_format, dpcm, |
703 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | 711 | SNDRV_PCM_HW_PARAM_FORMAT, -1); |
704 | if (err < 0) | 712 | if (err < 0) |
705 | goto unlock; | 713 | goto unlock; |
706 | err = snd_pcm_hw_rule_add(runtime, 0, | 714 | err = snd_pcm_hw_rule_add(runtime, 0, |
707 | SNDRV_PCM_HW_PARAM_RATE, | 715 | SNDRV_PCM_HW_PARAM_RATE, |
708 | rule_rate, &runtime->hw, | 716 | rule_rate, dpcm, |
709 | SNDRV_PCM_HW_PARAM_RATE, -1); | 717 | SNDRV_PCM_HW_PARAM_RATE, -1); |
710 | if (err < 0) | 718 | if (err < 0) |
711 | goto unlock; | 719 | goto unlock; |
712 | err = snd_pcm_hw_rule_add(runtime, 0, | 720 | err = snd_pcm_hw_rule_add(runtime, 0, |
713 | SNDRV_PCM_HW_PARAM_CHANNELS, | 721 | SNDRV_PCM_HW_PARAM_CHANNELS, |
714 | rule_channels, &runtime->hw, | 722 | rule_channels, dpcm, |
715 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | 723 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
716 | if (err < 0) | 724 | if (err < 0) |
717 | goto unlock; | 725 | goto unlock; |
@@ -723,6 +731,10 @@ static int loopback_open(struct snd_pcm_substream *substream) | |||
723 | else | 731 | else |
724 | runtime->hw = cable->hw; | 732 | runtime->hw = cable->hw; |
725 | unlock: | 733 | unlock: |
734 | if (err < 0) { | ||
735 | free_cable(substream); | ||
736 | kfree(dpcm); | ||
737 | } | ||
726 | mutex_unlock(&loopback->cable_lock); | 738 | mutex_unlock(&loopback->cable_lock); |
727 | return err; | 739 | return err; |
728 | } | 740 | } |
@@ -731,20 +743,10 @@ static int loopback_close(struct snd_pcm_substream *substream) | |||
731 | { | 743 | { |
732 | struct loopback *loopback = substream->private_data; | 744 | struct loopback *loopback = substream->private_data; |
733 | struct loopback_pcm *dpcm = substream->runtime->private_data; | 745 | struct loopback_pcm *dpcm = substream->runtime->private_data; |
734 | struct loopback_cable *cable; | ||
735 | int dev = get_cable_index(substream); | ||
736 | 746 | ||
737 | loopback_timer_stop(dpcm); | 747 | loopback_timer_stop(dpcm); |
738 | mutex_lock(&loopback->cable_lock); | 748 | mutex_lock(&loopback->cable_lock); |
739 | cable = loopback->cables[substream->number][dev]; | 749 | free_cable(substream); |
740 | if (cable->streams[!substream->stream]) { | ||
741 | /* other stream is still alive */ | ||
742 | cable->streams[substream->stream] = NULL; | ||
743 | } else { | ||
744 | /* free the cable */ | ||
745 | loopback->cables[substream->number][dev] = NULL; | ||
746 | kfree(cable); | ||
747 | } | ||
748 | mutex_unlock(&loopback->cable_lock); | 750 | mutex_unlock(&loopback->cable_lock); |
749 | return 0; | 751 | return 0; |
750 | } | 752 | } |