mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-11-07 03:47:13 +00:00
ALSA: hda - Fix independent-HP handling in patch_via.c
Fix races in handling of HP DAC and independent streams for VIA codecs. Also, allow the HP output path without front-DAC, and removed unnecessary activation of HP mixer elements. This also removes the handling of shared side/HP stream; it's anyway implemented in a broken way, so we need to re-implement the feature later... Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
12daef65fd
commit
ece8d0431f
1 changed files with 57 additions and 237 deletions
|
@ -133,6 +133,7 @@ struct via_spec {
|
||||||
/* playback */
|
/* playback */
|
||||||
struct hda_multi_out multiout;
|
struct hda_multi_out multiout;
|
||||||
hda_nid_t slave_dig_outs[2];
|
hda_nid_t slave_dig_outs[2];
|
||||||
|
hda_nid_t hp_dac_nid;
|
||||||
|
|
||||||
struct nid_path out_path[4];
|
struct nid_path out_path[4];
|
||||||
struct nid_path hp_path;
|
struct nid_path hp_path;
|
||||||
|
@ -702,64 +703,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
hda_nid_t nid = kcontrol->private_value;
|
|
||||||
unsigned int pinsel;
|
|
||||||
|
|
||||||
/* use !! to translate conn sel 2 for VT1718S */
|
|
||||||
pinsel = !!snd_hda_codec_read(codec, nid, 0,
|
|
||||||
AC_VERB_GET_CONNECT_SEL,
|
|
||||||
0x00);
|
|
||||||
ucontrol->value.enumerated.item[0] = pinsel;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void activate_ctl(struct hda_codec *codec, const char *name, int active)
|
|
||||||
{
|
|
||||||
struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
|
|
||||||
if (ctl) {
|
|
||||||
ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
||||||
ctl->vd[0].access |= active
|
|
||||||
? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
||||||
snd_ctl_notify(codec->bus->card,
|
|
||||||
SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static hda_nid_t side_mute_channel(struct via_spec *spec)
|
|
||||||
{
|
|
||||||
switch (spec->codec_type) {
|
|
||||||
case VT1708: return 0x1b;
|
|
||||||
case VT1709_10CH: return 0x29;
|
|
||||||
case VT1708B_8CH: /* fall thru */
|
|
||||||
case VT1708S: return 0x27;
|
|
||||||
case VT2002P: return 0x19;
|
|
||||||
case VT1802: return 0x15;
|
|
||||||
case VT1812: return 0x15;
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int update_side_mute_status(struct hda_codec *codec)
|
|
||||||
{
|
|
||||||
/* mute side channel */
|
|
||||||
struct via_spec *spec = codec->spec;
|
struct via_spec *spec = codec->spec;
|
||||||
unsigned int parm;
|
|
||||||
hda_nid_t sw3 = side_mute_channel(spec);
|
|
||||||
|
|
||||||
if (sw3) {
|
ucontrol->value.enumerated.item[0] = spec->hp_independent_mode;
|
||||||
if (VT2002P_COMPATIBLE(spec))
|
|
||||||
parm = spec->hp_independent_mode ?
|
|
||||||
AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
|
|
||||||
else
|
|
||||||
parm = spec->hp_independent_mode ?
|
|
||||||
AMP_OUT_MUTE : AMP_OUT_UNMUTE;
|
|
||||||
snd_hda_codec_write(codec, sw3, 0,
|
|
||||||
AC_VERB_SET_AMP_GAIN_MUTE, parm);
|
|
||||||
if (spec->codec_type == VT1812)
|
|
||||||
snd_hda_codec_write(codec, 0x1d, 0,
|
|
||||||
AC_VERB_SET_AMP_GAIN_MUTE, parm);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,50 +719,19 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
|
||||||
/* Get Independent Mode index of headphone pin widget */
|
/* Get Independent Mode index of headphone pin widget */
|
||||||
spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
|
spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
|
||||||
? 1 : 0;
|
? 1 : 0;
|
||||||
if (spec->codec_type == VT1718S)
|
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
|
||||||
snd_hda_codec_write(codec, nid, 0,
|
|
||||||
AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
|
|
||||||
else
|
|
||||||
snd_hda_codec_write(codec, nid, 0,
|
|
||||||
AC_VERB_SET_CONNECT_SEL, pinsel);
|
|
||||||
|
|
||||||
if (spec->codec_type == VT1812)
|
|
||||||
snd_hda_codec_write(codec, 0x35, 0,
|
|
||||||
AC_VERB_SET_CONNECT_SEL, pinsel);
|
|
||||||
if (spec->multiout.hp_nid && spec->multiout.hp_nid
|
|
||||||
!= spec->multiout.dac_nids[HDA_FRONT])
|
|
||||||
snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
|
|
||||||
0, 0, 0);
|
|
||||||
|
|
||||||
update_side_mute_status(codec);
|
|
||||||
/* update HP volume/swtich active state */
|
|
||||||
if (spec->codec_type == VT1708S
|
|
||||||
|| spec->codec_type == VT1702
|
|
||||||
|| spec->codec_type == VT1718S
|
|
||||||
|| spec->codec_type == VT1716S
|
|
||||||
|| VT2002P_COMPATIBLE(spec)) {
|
|
||||||
activate_ctl(codec, "Headphone Playback Volume",
|
|
||||||
spec->hp_independent_mode);
|
|
||||||
activate_ctl(codec, "Headphone Playback Switch",
|
|
||||||
spec->hp_independent_mode);
|
|
||||||
}
|
|
||||||
/* update jack power state */
|
/* update jack power state */
|
||||||
set_widgets_power_state(codec);
|
set_widgets_power_state(codec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_kcontrol_new via_hp_mixer[2] = {
|
static const struct snd_kcontrol_new via_hp_mixer = {
|
||||||
{
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
.name = "Independent HP",
|
||||||
.name = "Independent HP",
|
.info = via_independent_hp_info,
|
||||||
.info = via_independent_hp_info,
|
.get = via_independent_hp_get,
|
||||||
.get = via_independent_hp_get,
|
.put = via_independent_hp_put,
|
||||||
.put = via_independent_hp_put,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.iface = NID_MAPPING,
|
|
||||||
.name = "Independent HP",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int via_hp_build(struct hda_codec *codec)
|
static int via_hp_build(struct hda_codec *codec)
|
||||||
|
@ -824,44 +739,15 @@ static int via_hp_build(struct hda_codec *codec)
|
||||||
struct via_spec *spec = codec->spec;
|
struct via_spec *spec = codec->spec;
|
||||||
struct snd_kcontrol_new *knew;
|
struct snd_kcontrol_new *knew;
|
||||||
hda_nid_t nid;
|
hda_nid_t nid;
|
||||||
int nums;
|
|
||||||
hda_nid_t conn[HDA_MAX_CONNECTIONS];
|
|
||||||
|
|
||||||
switch (spec->codec_type) {
|
nid = spec->autocfg.hp_pins[0];
|
||||||
case VT1718S:
|
knew = via_clone_control(spec, &via_hp_mixer);
|
||||||
nid = 0x34;
|
|
||||||
break;
|
|
||||||
case VT2002P:
|
|
||||||
case VT1802:
|
|
||||||
nid = 0x35;
|
|
||||||
break;
|
|
||||||
case VT1812:
|
|
||||||
nid = 0x3d;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
nid = spec->autocfg.hp_pins[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec->codec_type != VT1708) {
|
|
||||||
nums = snd_hda_get_connections(codec, nid,
|
|
||||||
conn, HDA_MAX_CONNECTIONS);
|
|
||||||
if (nums <= 1)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
knew = via_clone_control(spec, &via_hp_mixer[0]);
|
|
||||||
if (knew == NULL)
|
if (knew == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
|
knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
|
||||||
knew->private_value = nid;
|
knew->private_value = nid;
|
||||||
|
|
||||||
knew = via_clone_control(spec, &via_hp_mixer[1]);
|
|
||||||
if (knew == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
knew->subdevice = side_mute_channel(spec);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,20 +1085,26 @@ static void substream_set_idle(struct hda_codec *codec,
|
||||||
analog_low_current_mode(codec, idle);
|
analog_low_current_mode(codec, idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
static int via_playback_multi_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;
|
||||||
|
|
||||||
|
if (!spec->hp_independent_mode)
|
||||||
|
spec->multiout.hp_nid = spec->hp_dac_nid;
|
||||||
substream_set_idle(codec, substream);
|
substream_set_idle(codec, substream);
|
||||||
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
|
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
|
||||||
hinfo);
|
hinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int via_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
static int via_playback_multi_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)
|
||||||
{
|
{
|
||||||
|
struct via_spec *spec = codec->spec;
|
||||||
|
|
||||||
|
spec->multiout.hp_nid = 0;
|
||||||
substream_set_idle(codec, substream);
|
substream_set_idle(codec, substream);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1222,11 +1114,19 @@ static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo,
|
||||||
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;
|
|
||||||
|
|
||||||
if (!mout->hp_nid || mout->hp_nid == mout->dac_nids[HDA_FRONT] ||
|
if (snd_BUG_ON(!spec->hp_dac_nid))
|
||||||
!spec->hp_independent_mode)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
if (!spec->hp_independent_mode || spec->multiout.hp_nid)
|
||||||
|
return -EBUSY;
|
||||||
|
substream_set_idle(codec, substream);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo,
|
||||||
|
struct hda_codec *codec,
|
||||||
|
struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
substream_set_idle(codec, substream);
|
substream_set_idle(codec, substream);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1238,68 +1138,9 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||||
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;
|
|
||||||
const hda_nid_t *nids = mout->dac_nids;
|
|
||||||
int chs = substream->runtime->channels;
|
|
||||||
int i;
|
|
||||||
struct hda_spdif_out *spdif =
|
|
||||||
snd_hda_spdif_out_of_nid(codec, spec->multiout.dig_out_nid);
|
|
||||||
|
|
||||||
mutex_lock(&codec->spdif_mutex);
|
snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
|
||||||
if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
|
format, substream);
|
||||||
if (chs == 2 &&
|
|
||||||
snd_hda_is_supported_format(codec, mout->dig_out_nid,
|
|
||||||
format) &&
|
|
||||||
!(spdif->status & IEC958_AES0_NONAUDIO)) {
|
|
||||||
mout->dig_out_used = HDA_DIG_ANALOG_DUP;
|
|
||||||
/* turn off SPDIF once; otherwise the IEC958 bits won't
|
|
||||||
* be updated */
|
|
||||||
if (spdif->ctls & AC_DIG1_ENABLE)
|
|
||||||
snd_hda_codec_write(codec, mout->dig_out_nid, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
spdif->ctls &
|
|
||||||
~AC_DIG1_ENABLE & 0xff);
|
|
||||||
snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
|
|
||||||
stream_tag, 0, format);
|
|
||||||
/* turn on again (if needed) */
|
|
||||||
if (spdif->ctls & AC_DIG1_ENABLE)
|
|
||||||
snd_hda_codec_write(codec, mout->dig_out_nid, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
spdif->ctls & 0xff);
|
|
||||||
} else {
|
|
||||||
mout->dig_out_used = 0;
|
|
||||||
snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
|
|
||||||
0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
|
||||||
|
|
||||||
/* front */
|
|
||||||
snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
|
|
||||||
0, format);
|
|
||||||
|
|
||||||
if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
|
|
||||||
&& !spec->hp_independent_mode)
|
|
||||||
/* headphone out will just decode front left/right (stereo) */
|
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
|
|
||||||
0, format);
|
|
||||||
|
|
||||||
/* extra outputs copied from front */
|
|
||||||
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],
|
|
||||||
stream_tag, 0, format);
|
|
||||||
|
|
||||||
/* surrounds */
|
|
||||||
for (i = 1; i < mout->num_dacs; i++) {
|
|
||||||
if (chs >= (i + 1) * 2) /* independent out */
|
|
||||||
snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
|
|
||||||
i * 2, format);
|
|
||||||
else /* copy front */
|
|
||||||
snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
|
|
||||||
0, format);
|
|
||||||
}
|
|
||||||
vt1708_start_hp_work(spec);
|
vt1708_start_hp_work(spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1311,9 +1152,9 @@ static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
|
||||||
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;
|
|
||||||
|
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
|
snd_hda_codec_setup_stream(codec, spec->hp_dac_nid,
|
||||||
|
stream_tag, 0, format);
|
||||||
vt1708_start_hp_work(spec);
|
vt1708_start_hp_work(spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1323,30 +1164,8 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||||||
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;
|
|
||||||
const hda_nid_t *nids = mout->dac_nids;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < mout->num_dacs; i++)
|
snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
vt1708_stop_hp_work(spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1356,9 +1175,8 @@ static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
||||||
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;
|
|
||||||
|
|
||||||
snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
|
snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0);
|
||||||
vt1708_stop_hp_work(spec);
|
vt1708_stop_hp_work(spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1433,8 +1251,8 @@ static const struct hda_pcm_stream via_pcm_analog_playback = {
|
||||||
.channels_max = 8,
|
.channels_max = 8,
|
||||||
/* NID is set in via_build_pcms */
|
/* NID is set in via_build_pcms */
|
||||||
.ops = {
|
.ops = {
|
||||||
.open = via_playback_pcm_open,
|
.open = via_playback_multi_pcm_open,
|
||||||
.close = via_playback_pcm_close,
|
.close = via_playback_multi_pcm_close,
|
||||||
.prepare = via_playback_multi_pcm_prepare,
|
.prepare = via_playback_multi_pcm_prepare,
|
||||||
.cleanup = via_playback_multi_pcm_cleanup
|
.cleanup = via_playback_multi_pcm_cleanup
|
||||||
},
|
},
|
||||||
|
@ -1447,7 +1265,7 @@ static const struct hda_pcm_stream via_pcm_hp_playback = {
|
||||||
/* NID is set in via_build_pcms */
|
/* NID is set in via_build_pcms */
|
||||||
.ops = {
|
.ops = {
|
||||||
.open = via_playback_hp_pcm_open,
|
.open = via_playback_hp_pcm_open,
|
||||||
.close = via_playback_pcm_close,
|
.close = via_playback_hp_pcm_close,
|
||||||
.prepare = via_playback_hp_pcm_prepare,
|
.prepare = via_playback_hp_pcm_prepare,
|
||||||
.cleanup = via_playback_hp_pcm_cleanup
|
.cleanup = via_playback_hp_pcm_cleanup
|
||||||
},
|
},
|
||||||
|
@ -1464,8 +1282,8 @@ static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
|
||||||
*/
|
*/
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.ops = {
|
.ops = {
|
||||||
.open = via_playback_pcm_open,
|
.open = via_playback_multi_pcm_open,
|
||||||
.close = via_playback_pcm_close,
|
.close = via_playback_multi_pcm_close,
|
||||||
.prepare = via_playback_multi_pcm_prepare,
|
.prepare = via_playback_multi_pcm_prepare,
|
||||||
.cleanup = via_playback_multi_pcm_cleanup
|
.cleanup = via_playback_multi_pcm_cleanup
|
||||||
},
|
},
|
||||||
|
@ -1477,8 +1295,6 @@ static const struct hda_pcm_stream via_pcm_analog_capture = {
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
/* NID is set in via_build_pcms */
|
/* NID is set in via_build_pcms */
|
||||||
.ops = {
|
.ops = {
|
||||||
.open = via_playback_pcm_open,
|
|
||||||
.close = via_playback_pcm_close,
|
|
||||||
.prepare = via_capture_pcm_prepare,
|
.prepare = via_capture_pcm_prepare,
|
||||||
.cleanup = via_capture_pcm_cleanup
|
.cleanup = via_capture_pcm_cleanup
|
||||||
},
|
},
|
||||||
|
@ -1624,7 +1440,7 @@ static int via_build_pcms(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spec->multiout.hp_nid) {
|
if (spec->hp_dac_nid) {
|
||||||
codec->num_pcms++;
|
codec->num_pcms++;
|
||||||
info++;
|
info++;
|
||||||
snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp),
|
snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp),
|
||||||
|
@ -1632,7 +1448,7 @@ static int via_build_pcms(struct hda_codec *codec)
|
||||||
info->name = spec->stream_name_hp;
|
info->name = spec->stream_name_hp;
|
||||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback;
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback;
|
||||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
||||||
spec->multiout.hp_nid;
|
spec->hp_dac_nid;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1883,7 +1699,7 @@ static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac)
|
||||||
if (spec->multiout.dac_nids[i] == dac)
|
if (spec->multiout.dac_nids[i] == dac)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (spec->multiout.hp_nid == dac)
|
if (spec->hp_dac_nid == dac)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2076,24 +1892,25 @@ static void create_hp_imux(struct via_spec *spec)
|
||||||
static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
||||||
{
|
{
|
||||||
struct via_spec *spec = codec->spec;
|
struct via_spec *spec = codec->spec;
|
||||||
hda_nid_t dac = 0;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!pin)
|
if (!pin)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
|
|
||||||
&spec->hp_dep_path, 0, -1))
|
|
||||||
return 0;
|
|
||||||
if (parse_output_path(codec, pin, 0, &spec->hp_path, 0, -1)) {
|
if (parse_output_path(codec, pin, 0, &spec->hp_path, 0, -1)) {
|
||||||
dac = spec->hp_path.path[spec->hp_path.depth - 1];
|
spec->hp_dac_nid = spec->hp_path.path[spec->hp_path.depth - 1];
|
||||||
spec->multiout.hp_nid = dac;
|
|
||||||
spec->hp_independent_mode_index =
|
spec->hp_independent_mode_index =
|
||||||
spec->hp_path.idx[spec->hp_path.depth - 1];
|
spec->hp_path.idx[spec->hp_path.depth - 1];
|
||||||
create_hp_imux(spec);
|
create_hp_imux(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = create_ch_ctls(codec, "Headphone", pin, dac, 3);
|
if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
|
||||||
|
&spec->hp_dep_path, 0, -1) &&
|
||||||
|
!spec->hp_dac_nid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -2364,8 +2181,11 @@ static int via_parse_auto_config(struct hda_codec *codec)
|
||||||
|
|
||||||
spec->input_mux = &spec->private_imux[0];
|
spec->input_mux = &spec->private_imux[0];
|
||||||
|
|
||||||
if (spec->hp_mux)
|
if (spec->hp_mux) {
|
||||||
via_hp_build(codec);
|
err = via_hp_build(codec);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = via_smart51_build(codec);
|
err = via_smart51_build(codec);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|
Loading…
Reference in a new issue