diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-13 05:13:17 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-25 16:20:23 -0500 |
commit | e831d80b453a3586f1e1664a705c153a4ced39b8 (patch) | |
tree | 7c6a48a62f299e8bdca946490571b176658831ac | |
parent | b60fb519d7977e606621af85585c3677fc290ef8 (diff) |
ALSA: AACI: fix number of channels for record
AC'97 codecs only support two channels for recording, so we shouldn't
advertize that there are up to six channels available. Limit the
selection of 4 and 6 channel audio to playback only.
As this adds additional SNDRV_PCM_STREAM_PLAYBACK conditionals, we can
combine some resulting in the elimination of __aaci_pcm_open() entirely,
and making the code easier to read.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | sound/arm/aaci.c | 114 |
1 files changed, 52 insertions, 62 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 65685afd8f77..ab66d462d865 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c | |||
@@ -357,7 +357,7 @@ static struct snd_pcm_hardware aaci_hw_info = { | |||
357 | 357 | ||
358 | /* rates are setup from the AC'97 codec */ | 358 | /* rates are setup from the AC'97 codec */ |
359 | .channels_min = 2, | 359 | .channels_min = 2, |
360 | .channels_max = 6, | 360 | .channels_max = 2, |
361 | .buffer_bytes_max = 64 * 1024, | 361 | .buffer_bytes_max = 64 * 1024, |
362 | .period_bytes_min = 256, | 362 | .period_bytes_min = 256, |
363 | .period_bytes_max = PAGE_SIZE, | 363 | .period_bytes_max = PAGE_SIZE, |
@@ -365,22 +365,67 @@ static struct snd_pcm_hardware aaci_hw_info = { | |||
365 | .periods_max = PAGE_SIZE / 16, | 365 | .periods_max = PAGE_SIZE / 16, |
366 | }; | 366 | }; |
367 | 367 | ||
368 | static int __aaci_pcm_open(struct aaci *aaci, | 368 | /* |
369 | struct snd_pcm_substream *substream, | 369 | * We can support two and four channel audio. Unfortunately |
370 | struct aaci_runtime *aacirun) | 370 | * six channel audio requires a non-standard channel ordering: |
371 | * 2 -> FL(3), FR(4) | ||
372 | * 4 -> FL(3), FR(4), SL(7), SR(8) | ||
373 | * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) | ||
374 | * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) | ||
375 | * This requires an ALSA configuration file to correct. | ||
376 | */ | ||
377 | static int aaci_rule_channels(struct snd_pcm_hw_params *p, | ||
378 | struct snd_pcm_hw_rule *rule) | ||
379 | { | ||
380 | static unsigned int channel_list[] = { 2, 4, 6 }; | ||
381 | struct aaci *aaci = rule->private; | ||
382 | unsigned int mask = 1 << 0, slots; | ||
383 | |||
384 | /* pcms[0] is the our 5.1 PCM instance. */ | ||
385 | slots = aaci->ac97_bus->pcms[0].r[0].slots; | ||
386 | if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { | ||
387 | mask |= 1 << 1; | ||
388 | if (slots & (1 << AC97_SLOT_LFE)) | ||
389 | mask |= 1 << 2; | ||
390 | } | ||
391 | |||
392 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
393 | ARRAY_SIZE(channel_list), channel_list, mask); | ||
394 | } | ||
395 | |||
396 | static int aaci_pcm_open(struct snd_pcm_substream *substream) | ||
371 | { | 397 | { |
372 | struct snd_pcm_runtime *runtime = substream->runtime; | 398 | struct snd_pcm_runtime *runtime = substream->runtime; |
399 | struct aaci *aaci = substream->private_data; | ||
400 | struct aaci_runtime *aacirun; | ||
373 | int ret = 0; | 401 | int ret = 0; |
374 | 402 | ||
403 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
404 | aacirun = &aaci->playback; | ||
405 | } else { | ||
406 | aacirun = &aaci->capture; | ||
407 | } | ||
408 | |||
375 | aacirun->substream = substream; | 409 | aacirun->substream = substream; |
376 | runtime->private_data = aacirun; | 410 | runtime->private_data = aacirun; |
377 | runtime->hw = aaci_hw_info; | 411 | runtime->hw = aaci_hw_info; |
378 | runtime->hw.rates = aacirun->pcm->rates; | 412 | runtime->hw.rates = aacirun->pcm->rates; |
379 | snd_pcm_limit_hw_rates(runtime); | 413 | snd_pcm_limit_hw_rates(runtime); |
380 | 414 | ||
381 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 415 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
382 | aacirun->pcm->r[1].slots) | 416 | runtime->hw.channels_max = 6; |
383 | snd_ac97_pcm_double_rate_rules(runtime); | 417 | |
418 | /* Add rule describing channel dependency. */ | ||
419 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
420 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
421 | aaci_rule_channels, aaci, | ||
422 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
423 | if (ret) | ||
424 | return ret; | ||
425 | |||
426 | if (aacirun->pcm->r[1].slots) | ||
427 | snd_ac97_pcm_double_rate_rules(runtime); | ||
428 | } | ||
384 | 429 | ||
385 | /* | 430 | /* |
386 | * FIXME: ALSA specifies fifo_size in bytes. If we're in normal | 431 | * FIXME: ALSA specifies fifo_size in bytes. If we're in normal |
@@ -512,61 +557,6 @@ static const u32 channels_to_txmask[] = { | |||
512 | [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, | 557 | [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9, |
513 | }; | 558 | }; |
514 | 559 | ||
515 | /* | ||
516 | * We can support two and four channel audio. Unfortunately | ||
517 | * six channel audio requires a non-standard channel ordering: | ||
518 | * 2 -> FL(3), FR(4) | ||
519 | * 4 -> FL(3), FR(4), SL(7), SR(8) | ||
520 | * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) | ||
521 | * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) | ||
522 | * This requires an ALSA configuration file to correct. | ||
523 | */ | ||
524 | static unsigned int channel_list[] = { 2, 4, 6 }; | ||
525 | |||
526 | static int | ||
527 | aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) | ||
528 | { | ||
529 | struct aaci *aaci = rule->private; | ||
530 | unsigned int chan_mask = 1 << 0, slots; | ||
531 | |||
532 | /* | ||
533 | * pcms[0] is the our 5.1 PCM instance. | ||
534 | */ | ||
535 | slots = aaci->ac97_bus->pcms[0].r[0].slots; | ||
536 | if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { | ||
537 | chan_mask |= 1 << 1; | ||
538 | if (slots & (1 << AC97_SLOT_LFE)) | ||
539 | chan_mask |= 1 << 2; | ||
540 | } | ||
541 | |||
542 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
543 | ARRAY_SIZE(channel_list), channel_list, | ||
544 | chan_mask); | ||
545 | } | ||
546 | |||
547 | static int aaci_pcm_open(struct snd_pcm_substream *substream) | ||
548 | { | ||
549 | struct aaci *aaci = substream->private_data; | ||
550 | int ret; | ||
551 | |||
552 | /* | ||
553 | * Add rule describing channel dependency. | ||
554 | */ | ||
555 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
556 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
557 | aaci_rule_channels, aaci, | ||
558 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
559 | if (ret) | ||
560 | return ret; | ||
561 | |||
562 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
563 | ret = __aaci_pcm_open(aaci, substream, &aaci->playback); | ||
564 | } else { | ||
565 | ret = __aaci_pcm_open(aaci, substream, &aaci->capture); | ||
566 | } | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, | 560 | static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, |
571 | struct snd_pcm_hw_params *params) | 561 | struct snd_pcm_hw_params *params) |
572 | { | 562 | { |