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>
This commit is contained in:
Russell King 2011-01-13 10:13:17 +00:00
Родитель b60fb519d7
Коммит e831d80b45
1 изменённых файлов: 52 добавлений и 62 удалений

Просмотреть файл

@ -357,7 +357,7 @@ static struct snd_pcm_hardware aaci_hw_info = {
/* rates are setup from the AC'97 codec */
.channels_min = 2,
.channels_max = 6,
.channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 256,
.period_bytes_max = PAGE_SIZE,
@ -365,22 +365,67 @@ static struct snd_pcm_hardware aaci_hw_info = {
.periods_max = PAGE_SIZE / 16,
};
static int __aaci_pcm_open(struct aaci *aaci,
struct snd_pcm_substream *substream,
struct aaci_runtime *aacirun)
/*
* We can support two and four channel audio. Unfortunately
* six channel audio requires a non-standard channel ordering:
* 2 -> FL(3), FR(4)
* 4 -> FL(3), FR(4), SL(7), SR(8)
* 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
* FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
* This requires an ALSA configuration file to correct.
*/
static int aaci_rule_channels(struct snd_pcm_hw_params *p,
struct snd_pcm_hw_rule *rule)
{
static unsigned int channel_list[] = { 2, 4, 6 };
struct aaci *aaci = rule->private;
unsigned int mask = 1 << 0, slots;
/* pcms[0] is the our 5.1 PCM instance. */
slots = aaci->ac97_bus->pcms[0].r[0].slots;
if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
mask |= 1 << 1;
if (slots & (1 << AC97_SLOT_LFE))
mask |= 1 << 2;
}
return snd_interval_list(hw_param_interval(p, rule->var),
ARRAY_SIZE(channel_list), channel_list, mask);
}
static int aaci_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct aaci *aaci = substream->private_data;
struct aaci_runtime *aacirun;
int ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
aacirun = &aaci->playback;
} else {
aacirun = &aaci->capture;
}
aacirun->substream = substream;
runtime->private_data = aacirun;
runtime->hw = aaci_hw_info;
runtime->hw.rates = aacirun->pcm->rates;
snd_pcm_limit_hw_rates(runtime);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
aacirun->pcm->r[1].slots)
snd_ac97_pcm_double_rate_rules(runtime);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.channels_max = 6;
/* Add rule describing channel dependency. */
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
aaci_rule_channels, aaci,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (ret)
return ret;
if (aacirun->pcm->r[1].slots)
snd_ac97_pcm_double_rate_rules(runtime);
}
/*
* FIXME: ALSA specifies fifo_size in bytes. If we're in normal
@ -512,61 +557,6 @@ static const u32 channels_to_txmask[] = {
[6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
};
/*
* We can support two and four channel audio. Unfortunately
* six channel audio requires a non-standard channel ordering:
* 2 -> FL(3), FR(4)
* 4 -> FL(3), FR(4), SL(7), SR(8)
* 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
* FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
* This requires an ALSA configuration file to correct.
*/
static unsigned int channel_list[] = { 2, 4, 6 };
static int
aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule)
{
struct aaci *aaci = rule->private;
unsigned int chan_mask = 1 << 0, slots;
/*
* pcms[0] is the our 5.1 PCM instance.
*/
slots = aaci->ac97_bus->pcms[0].r[0].slots;
if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
chan_mask |= 1 << 1;
if (slots & (1 << AC97_SLOT_LFE))
chan_mask |= 1 << 2;
}
return snd_interval_list(hw_param_interval(p, rule->var),
ARRAY_SIZE(channel_list), channel_list,
chan_mask);
}
static int aaci_pcm_open(struct snd_pcm_substream *substream)
{
struct aaci *aaci = substream->private_data;
int ret;
/*
* Add rule describing channel dependency.
*/
ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
aaci_rule_channels, aaci,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (ret)
return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = __aaci_pcm_open(aaci, substream, &aaci->playback);
} else {
ret = __aaci_pcm_open(aaci, substream, &aaci->capture);
}
return ret;
}
static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{