summaryrefslogtreecommitdiff
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-06-18 16:40:14 +0200
committerTakashi Iwai <tiwai@suse.de>2011-06-20 16:24:05 +0200
commit7eb56e84e6c4deaa552db96834ea0b233ba92f50 (patch)
treee9904734cc9d14f23b2cd05568d3a7292fcd3023 /sound/pci/hda/patch_via.c
parent9af7421091fd37a2f8c35ca8b3a5f78a6f20fa89 (diff)
downloadlinux-3.10-7eb56e84e6c4deaa552db96834ea0b233ba92f50.tar.gz
linux-3.10-7eb56e84e6c4deaa552db96834ea0b233ba92f50.tar.bz2
linux-3.10-7eb56e84e6c4deaa552db96834ea0b233ba92f50.zip
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>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r--sound/pci/hda/patch_via.c144
1 files changed, 91 insertions, 53 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 18f2a135c02..264889c9c17 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -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,17 +1233,29 @@ 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,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
+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)
{
struct via_spec *spec = codec->spec;
struct hda_multi_out *mout = &spec->multiout;
@@ -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,
0, format);
}
+ vt1708_start_hp_work(spec);
+ 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)
+static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
{
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,33 +1347,38 @@ 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);
+ for (i = 0; i < mout->num_dacs; i++)
+ snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
- if (mout->hp_nid && !spec->hp_independent_mode)
- snd_hda_codec_setup_stream(codec, mout->hp_nid,
- 0, 0, 0);
+ if (mout->hp_nid && !spec->hp_independent_mode)
+ snd_hda_codec_setup_stream(codec, mout->hp_nid,
+ 0, 0, 0);
- for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
- if (mout->extra_out_nid[i])
- snd_hda_codec_setup_stream(codec,
- 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,
+ for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+ if (mout->extra_out_nid[i])
+ snd_hda_codec_setup_stream(codec,
+ 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);
+ 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;
}