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

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
Loading
Loading
Loading
Loading
+91 −53
Original line number Diff line number Diff line
@@ -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 int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
				 struct hda_codec *codec,
static void substream_set_idle(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);
}

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;
	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;
	substream_set_idle(codec, substream);
	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;
}

static void playback_multi_pcm_prep_0(struct hda_codec *codec,
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;
}