Commit 7eb56e84 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 9af74210
...@@ -122,6 +122,7 @@ struct via_spec { ...@@ -122,6 +122,7 @@ struct via_spec {
unsigned int num_iverbs; unsigned int num_iverbs;
char stream_name_analog[32]; 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_playback;
const struct hda_pcm_stream *stream_analog_capture; const struct hda_pcm_stream *stream_analog_capture;
...@@ -1210,14 +1211,20 @@ static const struct hda_verb vt1708_volume_init_verbs[] = { ...@@ -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, static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec;
int idle = substream->pstr->substream_opened == 1 substream_set_idle(codec, substream);
&& substream->ref_count == 0;
analog_low_current_mode(codec, idle);
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo); hinfo);
} }
...@@ -1226,17 +1233,29 @@ static int via_playback_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -1226,17 +1233,29 @@ static int via_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
int idle = substream->pstr->substream_opened == 1 substream_set_idle(codec, substream);
&& substream->ref_count == 0; return 0;
}
analog_low_current_mode(codec, idle); 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; return 0;
} }
static void playback_multi_pcm_prep_0(struct hda_codec *codec, static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
unsigned int stream_tag, struct hda_codec *codec,
unsigned int format, unsigned int stream_tag,
struct snd_pcm_substream *substream) unsigned int format,
struct snd_pcm_substream *substream)
{ {
struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout; struct hda_multi_out *mout = &spec->multiout;
...@@ -1301,27 +1320,20 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, ...@@ -1301,27 +1320,20 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec, nids[i], stream_tag, snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
0, format); 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, struct hda_codec *codec,
unsigned int stream_tag, unsigned int stream_tag,
unsigned int format, unsigned int format,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout; struct hda_multi_out *mout = &spec->multiout;
const hda_nid_t *nids = mout->dac_nids;
if (substream->number == 0) snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
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);
}
vt1708_start_hp_work(spec); vt1708_start_hp_work(spec);
return 0; return 0;
} }
...@@ -1335,33 +1347,38 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -1335,33 +1347,38 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
const hda_nid_t *nids = mout->dac_nids; const hda_nid_t *nids = mout->dac_nids;
int i; int i;
if (substream->number == 0) { for (i = 0; i < mout->num_dacs; i++)
for (i = 0; i < mout->num_dacs; i++) snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
if (mout->hp_nid && !spec->hp_independent_mode) if (mout->hp_nid && !spec->hp_independent_mode)
snd_hda_codec_setup_stream(codec, mout->hp_nid, snd_hda_codec_setup_stream(codec, mout->hp_nid,
0, 0, 0); 0, 0, 0);
for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
if (mout->extra_out_nid[i]) if (mout->extra_out_nid[i])
snd_hda_codec_setup_stream(codec, snd_hda_codec_setup_stream(codec,
mout->extra_out_nid[i], mout->extra_out_nid[i],
0, 0, 0);
mutex_lock(&codec->spdif_mutex);
if (mout->dig_out_nid &&
mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
0, 0, 0);
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); 0, 0, 0);
mutex_lock(&codec->spdif_mutex);
if (mout->dig_out_nid &&
mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
0, 0, 0);
mout->dig_out_used = 0;
} }
mutex_unlock(&codec->spdif_mutex);
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); vt1708_stop_hp_work(spec);
return 0; return 0;
} }
...@@ -1431,7 +1448,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -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 = { 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_min = 2,
.channels_max = 8, .channels_max = 8,
/* NID is set in via_build_pcms */ /* NID is set in via_build_pcms */
...@@ -1443,8 +1460,21 @@ static const struct hda_pcm_stream via_pcm_analog_playback = { ...@@ -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 = { 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_min = 2,
.channels_max = 8, .channels_max = 8,
/* NID is set in via_build_pcms */ /* NID is set in via_build_pcms */
...@@ -1462,7 +1492,7 @@ static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { ...@@ -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 = { 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_min = 2,
.channels_max = 2, .channels_max = 2,
/* NID is set in via_build_pcms */ /* NID is set in via_build_pcms */
...@@ -1577,8 +1607,6 @@ static int via_build_pcms(struct hda_codec *codec) ...@@ -1577,8 +1607,6 @@ static int via_build_pcms(struct hda_codec *codec)
spec->multiout.dac_nids[0]; spec->multiout.dac_nids[0];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
spec->multiout.max_channels; spec->multiout.max_channels;
if (!spec->multiout.hp_nid)
info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams = 1;
if (!spec->stream_analog_capture) if (!spec->stream_analog_capture)
spec->stream_analog_capture = &via_pcm_analog_capture; spec->stream_analog_capture = &via_pcm_analog_capture;
...@@ -1616,6 +1644,16 @@ static int via_build_pcms(struct hda_codec *codec) ...@@ -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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment