ALSA: hda - Assign HP-independent PCM to individual stream

Instead of using the secondary substream, create an individual PCM
stream for HP-independent PCM.  Otherwise it's difficult to handle
different channel numbers with multi-channel stream in the sam PCM
stream structure.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2011-06-18 16:40:14 +02:00
parent 9af7421091
commit 7eb56e84e6
1 changed files with 92 additions and 54 deletions

View File

@ -122,6 +122,7 @@ struct via_spec {
unsigned int num_iverbs;
char stream_name_analog[32];
char stream_name_hp[32];
const struct hda_pcm_stream *stream_analog_playback;
const struct hda_pcm_stream *stream_analog_capture;
@ -1210,14 +1211,20 @@ static const struct hda_verb vt1708_volume_init_verbs[] = {
{ }
};
static void substream_set_idle(struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
int idle = substream->pstr->substream_opened == 1
&& substream->ref_count == 0;
analog_low_current_mode(codec, idle);
}
static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
int idle = substream->pstr->substream_opened == 1
&& substream->ref_count == 0;
analog_low_current_mode(codec, idle);
substream_set_idle(codec, substream);
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
}
@ -1226,14 +1233,26 @@ static int via_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
int idle = substream->pstr->substream_opened == 1
&& substream->ref_count == 0;
analog_low_current_mode(codec, idle);
substream_set_idle(codec, substream);
return 0;
}
static void playback_multi_pcm_prep_0(struct hda_codec *codec,
static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout;
if (!mout->hp_nid || mout->hp_nid == mout->dac_nids[HDA_FRONT] ||
!spec->hp_independent_mode)
return -EINVAL;
substream_set_idle(codec, substream);
return 0;
}
static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
@ -1301,9 +1320,11 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
0, format);
}
vt1708_start_hp_work(spec);
return 0;
}
static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
@ -1311,17 +1332,8 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
{
struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout;
const hda_nid_t *nids = mout->dac_nids;
if (substream->number == 0)
playback_multi_pcm_prep_0(codec, stream_tag, format,
substream);
else {
if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
spec->hp_independent_mode)
snd_hda_codec_setup_stream(codec, mout->hp_nid,
stream_tag, 0, format);
}
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
vt1708_start_hp_work(spec);
return 0;
}
@ -1335,7 +1347,6 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
const hda_nid_t *nids = mout->dac_nids;
int i;
if (substream->number == 0) {
for (i = 0; i < mout->num_dacs; i++)
snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
@ -1356,12 +1367,18 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
mout->dig_out_used = 0;
}
mutex_unlock(&codec->spdif_mutex);
} else {
if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
spec->hp_independent_mode)
snd_hda_codec_setup_stream(codec, mout->hp_nid,
0, 0, 0);
}
vt1708_stop_hp_work(spec);
return 0;
}
static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout;
snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
vt1708_stop_hp_work(spec);
return 0;
}
@ -1431,7 +1448,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
}
static const struct hda_pcm_stream via_pcm_analog_playback = {
.substreams = 2, /* will be changed in via_build_pcms() */
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
/* NID is set in via_build_pcms */
@ -1443,8 +1460,21 @@ static const struct hda_pcm_stream via_pcm_analog_playback = {
},
};
static const struct hda_pcm_stream via_pcm_hp_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in via_build_pcms */
.ops = {
.open = via_playback_hp_pcm_open,
.close = via_playback_pcm_close,
.prepare = via_playback_hp_pcm_prepare,
.cleanup = via_playback_hp_pcm_cleanup
},
};
static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
.substreams = 2, /* will be changed in via_build_pcms() */
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
/* NID is set in via_build_pcms */
@ -1462,7 +1492,7 @@ static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
};
static const struct hda_pcm_stream via_pcm_analog_capture = {
.substreams = 2, /* will be changed in via_build_pcms() */
.substreams = 1, /* will be changed in via_build_pcms() */
.channels_min = 2,
.channels_max = 2,
/* NID is set in via_build_pcms */
@ -1577,8 +1607,6 @@ static int via_build_pcms(struct hda_codec *codec)
spec->multiout.dac_nids[0];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
spec->multiout.max_channels;
if (!spec->multiout.hp_nid)
info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams = 1;
if (!spec->stream_analog_capture)
spec->stream_analog_capture = &via_pcm_analog_capture;
@ -1616,6 +1644,16 @@ static int via_build_pcms(struct hda_codec *codec)
}
}
if (spec->multiout.hp_nid) {
codec->num_pcms++;
info++;
snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp),
"%s HP", codec->chip_name);
info->name = spec->stream_name_hp;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
spec->multiout.hp_nid;
}
return 0;
}