diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-10-11 07:56:12 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-10-11 07:56:12 -0400 |
commit | e799d0bce6b191de6e96e556528243c1d73303ca (patch) | |
tree | e61f5996d97f80734f6ca139decb052a3b6c5339 /sound | |
parent | 1d2019fb6be2f318f0aa85be5f224f47a5f006fe (diff) | |
parent | 838c364ff05c143fd1810e8ad1469935d6c23a7a (diff) |
Merge remote branch 'alsa/devel' into topic/misc
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/oss/mixer_oss.c | 12 | ||||
-rw-r--r-- | sound/drivers/aloop.c | 124 |
2 files changed, 114 insertions, 22 deletions
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 86afb13cd240..822dd56993ca 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, | |||
618 | if (numid == ID_UNKNOWN) | 618 | if (numid == ID_UNKNOWN) |
619 | return; | 619 | return; |
620 | down_read(&card->controls_rwsem); | 620 | down_read(&card->controls_rwsem); |
621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) | 621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
622 | up_read(&card->controls_rwsem); | ||
622 | return; | 623 | return; |
624 | } | ||
623 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 625 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
624 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 626 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
625 | if (uinfo == NULL || uctl == NULL) | 627 | if (uinfo == NULL || uctl == NULL) |
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, | |||
658 | return; | 660 | return; |
659 | down_read(&card->controls_rwsem); | 661 | down_read(&card->controls_rwsem); |
660 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 662 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
661 | up_read(&fmixer->card->controls_rwsem); | 663 | up_read(&card->controls_rwsem); |
662 | return; | 664 | return; |
663 | } | 665 | } |
664 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 666 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
797 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 799 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
798 | if (uinfo == NULL || uctl == NULL) { | 800 | if (uinfo == NULL || uctl == NULL) { |
799 | err = -ENOMEM; | 801 | err = -ENOMEM; |
800 | goto __unlock; | 802 | goto __free_only; |
801 | } | 803 | } |
802 | down_read(&card->controls_rwsem); | 804 | down_read(&card->controls_rwsem); |
803 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 805 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
826 | err = 0; | 828 | err = 0; |
827 | __unlock: | 829 | __unlock: |
828 | up_read(&card->controls_rwsem); | 830 | up_read(&card->controls_rwsem); |
831 | __free_only: | ||
829 | kfree(uctl); | 832 | kfree(uctl); |
830 | kfree(uinfo); | 833 | kfree(uinfo); |
831 | return err; | 834 | return err; |
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
847 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 850 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
848 | if (uinfo == NULL || uctl == NULL) { | 851 | if (uinfo == NULL || uctl == NULL) { |
849 | err = -ENOMEM; | 852 | err = -ENOMEM; |
850 | goto __unlock; | 853 | goto __free_only; |
851 | } | 854 | } |
852 | down_read(&card->controls_rwsem); | 855 | down_read(&card->controls_rwsem); |
853 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 856 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
880 | err = 0; | 883 | err = 0; |
881 | __unlock: | 884 | __unlock: |
882 | up_read(&card->controls_rwsem); | 885 | up_read(&card->controls_rwsem); |
886 | __free_only: | ||
883 | kfree(uctl); | 887 | kfree(uctl); |
884 | kfree(uinfo); | 888 | kfree(uinfo); |
885 | return err; | 889 | return err; |
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 040030aa9d8e..3c0088272095 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c | |||
@@ -188,7 +188,7 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm) | |||
188 | 188 | ||
189 | static int loopback_check_format(struct loopback_cable *cable, int stream) | 189 | static int loopback_check_format(struct loopback_cable *cable, int stream) |
190 | { | 190 | { |
191 | struct snd_pcm_runtime *runtime; | 191 | struct snd_pcm_runtime *runtime, *cruntime; |
192 | struct loopback_setup *setup; | 192 | struct loopback_setup *setup; |
193 | struct snd_card *card; | 193 | struct snd_card *card; |
194 | int check; | 194 | int check; |
@@ -200,11 +200,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream) | |||
200 | } | 200 | } |
201 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | 201 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> |
202 | substream->runtime; | 202 | substream->runtime; |
203 | check = cable->hw.formats != (1ULL << runtime->format) || | 203 | cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> |
204 | cable->hw.rate_min != runtime->rate || | 204 | substream->runtime; |
205 | cable->hw.rate_max != runtime->rate || | 205 | check = runtime->format != cruntime->format || |
206 | cable->hw.channels_min != runtime->channels || | 206 | runtime->rate != cruntime->rate || |
207 | cable->hw.channels_max != runtime->channels; | 207 | runtime->channels != cruntime->channels; |
208 | if (!check) | 208 | if (!check) |
209 | return 0; | 209 | return 0; |
210 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { | 210 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { |
@@ -274,12 +274,42 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | static void params_change_substream(struct loopback_pcm *dpcm, | ||
278 | struct snd_pcm_runtime *runtime) | ||
279 | { | ||
280 | struct snd_pcm_runtime *dst_runtime; | ||
281 | |||
282 | if (dpcm == NULL || dpcm->substream == NULL) | ||
283 | return; | ||
284 | dst_runtime = dpcm->substream->runtime; | ||
285 | if (dst_runtime == NULL) | ||
286 | return; | ||
287 | dst_runtime->hw = dpcm->cable->hw; | ||
288 | } | ||
289 | |||
290 | static void params_change(struct snd_pcm_substream *substream) | ||
291 | { | ||
292 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
293 | struct loopback_pcm *dpcm = runtime->private_data; | ||
294 | struct loopback_cable *cable = dpcm->cable; | ||
295 | |||
296 | cable->hw.formats = (1ULL << runtime->format); | ||
297 | cable->hw.rate_min = runtime->rate; | ||
298 | cable->hw.rate_max = runtime->rate; | ||
299 | cable->hw.channels_min = runtime->channels; | ||
300 | cable->hw.channels_max = runtime->channels; | ||
301 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
302 | runtime); | ||
303 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
304 | runtime); | ||
305 | } | ||
306 | |||
277 | static int loopback_prepare(struct snd_pcm_substream *substream) | 307 | static int loopback_prepare(struct snd_pcm_substream *substream) |
278 | { | 308 | { |
279 | struct snd_pcm_runtime *runtime = substream->runtime; | 309 | struct snd_pcm_runtime *runtime = substream->runtime; |
280 | struct loopback_pcm *dpcm = runtime->private_data; | 310 | struct loopback_pcm *dpcm = runtime->private_data; |
281 | struct loopback_cable *cable = dpcm->cable; | 311 | struct loopback_cable *cable = dpcm->cable; |
282 | unsigned int bps, salign; | 312 | int bps, salign; |
283 | 313 | ||
284 | salign = (snd_pcm_format_width(runtime->format) * | 314 | salign = (snd_pcm_format_width(runtime->format) * |
285 | runtime->channels) / 8; | 315 | runtime->channels) / 8; |
@@ -303,13 +333,10 @@ static int loopback_prepare(struct snd_pcm_substream *substream) | |||
303 | dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); | 333 | dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); |
304 | 334 | ||
305 | mutex_lock(&dpcm->loopback->cable_lock); | 335 | mutex_lock(&dpcm->loopback->cable_lock); |
306 | if (!(cable->valid & ~(1 << substream->stream))) { | 336 | if (!(cable->valid & ~(1 << substream->stream)) || |
307 | cable->hw.formats = (1ULL << runtime->format); | 337 | (get_setup(dpcm)->notify && |
308 | cable->hw.rate_min = runtime->rate; | 338 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) |
309 | cable->hw.rate_max = runtime->rate; | 339 | params_change(substream); |
310 | cable->hw.channels_min = runtime->channels; | ||
311 | cable->hw.channels_max = runtime->channels; | ||
312 | } | ||
313 | cable->valid |= 1 << substream->stream; | 340 | cable->valid |= 1 << substream->stream; |
314 | mutex_unlock(&dpcm->loopback->cable_lock); | 341 | mutex_unlock(&dpcm->loopback->cable_lock); |
315 | 342 | ||
@@ -542,6 +569,47 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream) | |||
542 | return !substream->stream; | 569 | return !substream->stream; |
543 | } | 570 | } |
544 | 571 | ||
572 | static int rule_format(struct snd_pcm_hw_params *params, | ||
573 | struct snd_pcm_hw_rule *rule) | ||
574 | { | ||
575 | |||
576 | struct snd_pcm_hardware *hw = rule->private; | ||
577 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
578 | |||
579 | maskp->bits[0] &= (u_int32_t)hw->formats; | ||
580 | maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); | ||
581 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ | ||
582 | if (! maskp->bits[0] && ! maskp->bits[1]) | ||
583 | return -EINVAL; | ||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static int rule_rate(struct snd_pcm_hw_params *params, | ||
588 | struct snd_pcm_hw_rule *rule) | ||
589 | { | ||
590 | struct snd_pcm_hardware *hw = rule->private; | ||
591 | struct snd_interval t; | ||
592 | |||
593 | t.min = hw->rate_min; | ||
594 | t.max = hw->rate_max; | ||
595 | t.openmin = t.openmax = 0; | ||
596 | t.integer = 0; | ||
597 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
598 | } | ||
599 | |||
600 | static int rule_channels(struct snd_pcm_hw_params *params, | ||
601 | struct snd_pcm_hw_rule *rule) | ||
602 | { | ||
603 | struct snd_pcm_hardware *hw = rule->private; | ||
604 | struct snd_interval t; | ||
605 | |||
606 | t.min = hw->channels_min; | ||
607 | t.max = hw->channels_max; | ||
608 | t.openmin = t.openmax = 0; | ||
609 | t.integer = 0; | ||
610 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
611 | } | ||
612 | |||
545 | static int loopback_open(struct snd_pcm_substream *substream) | 613 | static int loopback_open(struct snd_pcm_substream *substream) |
546 | { | 614 | { |
547 | struct snd_pcm_runtime *runtime = substream->runtime; | 615 | struct snd_pcm_runtime *runtime = substream->runtime; |
@@ -579,14 +647,34 @@ static int loopback_open(struct snd_pcm_substream *substream) | |||
579 | 647 | ||
580 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | 648 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
581 | 649 | ||
650 | /* use dynamic rules based on actual runtime->hw values */ | ||
651 | /* note that the default rules created in the PCM midlevel code */ | ||
652 | /* are cached -> they do not reflect the actual state */ | ||
653 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
654 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
655 | rule_format, &runtime->hw, | ||
656 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | ||
657 | if (err < 0) | ||
658 | goto unlock; | ||
659 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
660 | SNDRV_PCM_HW_PARAM_RATE, | ||
661 | rule_rate, &runtime->hw, | ||
662 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
663 | if (err < 0) | ||
664 | goto unlock; | ||
665 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
666 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
667 | rule_channels, &runtime->hw, | ||
668 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
669 | if (err < 0) | ||
670 | goto unlock; | ||
671 | |||
582 | runtime->private_data = dpcm; | 672 | runtime->private_data = dpcm; |
583 | runtime->private_free = loopback_runtime_free; | 673 | runtime->private_free = loopback_runtime_free; |
584 | if (get_notify(dpcm) && | 674 | if (get_notify(dpcm)) |
585 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
586 | runtime->hw = loopback_pcm_hardware; | 675 | runtime->hw = loopback_pcm_hardware; |
587 | } else { | 676 | else |
588 | runtime->hw = cable->hw; | 677 | runtime->hw = cable->hw; |
589 | } | ||
590 | unlock: | 678 | unlock: |
591 | mutex_unlock(&loopback->cable_lock); | 679 | mutex_unlock(&loopback->cable_lock); |
592 | return err; | 680 | return err; |