diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-06-19 10:24:21 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-06-20 10:24:08 -0400 |
commit | ece8d0431fde78ea2c0a5be2884bcbc4940ae7c5 (patch) | |
tree | 3188d53fc3f5855a8e9cdf3fbd2997c2ed2f7459 /sound/pci/hda/patch_via.c | |
parent | 12daef65fd868cf30be5afe3e6be6689c44c7940 (diff) |
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>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r-- | sound/pci/hda/patch_via.c | 296 |
1 files changed, 58 insertions, 238 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 14fccdc21c33..fa5ed36d69e5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -133,6 +133,7 @@ struct via_spec { | |||
133 | /* playback */ | 133 | /* playback */ |
134 | struct hda_multi_out multiout; | 134 | struct hda_multi_out multiout; |
135 | hda_nid_t slave_dig_outs[2]; | 135 | hda_nid_t slave_dig_outs[2]; |
136 | hda_nid_t hp_dac_nid; | ||
136 | 137 | ||
137 | struct nid_path out_path[4]; | 138 | struct nid_path out_path[4]; |
138 | struct nid_path hp_path; | 139 | struct nid_path hp_path; |
@@ -702,64 +703,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
702 | struct snd_ctl_elem_value *ucontrol) | 703 | struct snd_ctl_elem_value *ucontrol) |
703 | { | 704 | { |
704 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 705 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
705 | hda_nid_t nid = kcontrol->private_value; | ||
706 | unsigned int pinsel; | ||
707 | |||
708 | /* use !! to translate conn sel 2 for VT1718S */ | ||
709 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | ||
710 | AC_VERB_GET_CONNECT_SEL, | ||
711 | 0x00); | ||
712 | ucontrol->value.enumerated.item[0] = pinsel; | ||
713 | |||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static void activate_ctl(struct hda_codec *codec, const char *name, int active) | ||
718 | { | ||
719 | struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); | ||
720 | if (ctl) { | ||
721 | ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
722 | ctl->vd[0].access |= active | ||
723 | ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
724 | snd_ctl_notify(codec->bus->card, | ||
725 | SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id); | ||
726 | } | ||
727 | } | ||
728 | |||
729 | static hda_nid_t side_mute_channel(struct via_spec *spec) | ||
730 | { | ||
731 | switch (spec->codec_type) { | ||
732 | case VT1708: return 0x1b; | ||
733 | case VT1709_10CH: return 0x29; | ||
734 | case VT1708B_8CH: /* fall thru */ | ||
735 | case VT1708S: return 0x27; | ||
736 | case VT2002P: return 0x19; | ||
737 | case VT1802: return 0x15; | ||
738 | case VT1812: return 0x15; | ||
739 | default: return 0; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | static int update_side_mute_status(struct hda_codec *codec) | ||
744 | { | ||
745 | /* mute side channel */ | ||
746 | struct via_spec *spec = codec->spec; | 706 | struct via_spec *spec = codec->spec; |
747 | unsigned int parm; | ||
748 | hda_nid_t sw3 = side_mute_channel(spec); | ||
749 | 707 | ||
750 | if (sw3) { | 708 | ucontrol->value.enumerated.item[0] = spec->hp_independent_mode; |
751 | if (VT2002P_COMPATIBLE(spec)) | ||
752 | parm = spec->hp_independent_mode ? | ||
753 | AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); | ||
754 | else | ||
755 | parm = spec->hp_independent_mode ? | ||
756 | AMP_OUT_MUTE : AMP_OUT_UNMUTE; | ||
757 | snd_hda_codec_write(codec, sw3, 0, | ||
758 | AC_VERB_SET_AMP_GAIN_MUTE, parm); | ||
759 | if (spec->codec_type == VT1812) | ||
760 | snd_hda_codec_write(codec, 0x1d, 0, | ||
761 | AC_VERB_SET_AMP_GAIN_MUTE, parm); | ||
762 | } | ||
763 | return 0; | 709 | return 0; |
764 | } | 710 | } |
765 | 711 | ||
@@ -773,50 +719,19 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
773 | /* Get Independent Mode index of headphone pin widget */ | 719 | /* Get Independent Mode index of headphone pin widget */ |
774 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel | 720 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
775 | ? 1 : 0; | 721 | ? 1 : 0; |
776 | if (spec->codec_type == VT1718S) | 722 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
777 | snd_hda_codec_write(codec, nid, 0, | ||
778 | AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0); | ||
779 | else | ||
780 | snd_hda_codec_write(codec, nid, 0, | ||
781 | AC_VERB_SET_CONNECT_SEL, pinsel); | ||
782 | 723 | ||
783 | if (spec->codec_type == VT1812) | ||
784 | snd_hda_codec_write(codec, 0x35, 0, | ||
785 | AC_VERB_SET_CONNECT_SEL, pinsel); | ||
786 | if (spec->multiout.hp_nid && spec->multiout.hp_nid | ||
787 | != spec->multiout.dac_nids[HDA_FRONT]) | ||
788 | snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, | ||
789 | 0, 0, 0); | ||
790 | |||
791 | update_side_mute_status(codec); | ||
792 | /* update HP volume/swtich active state */ | ||
793 | if (spec->codec_type == VT1708S | ||
794 | || spec->codec_type == VT1702 | ||
795 | || spec->codec_type == VT1718S | ||
796 | || spec->codec_type == VT1716S | ||
797 | || VT2002P_COMPATIBLE(spec)) { | ||
798 | activate_ctl(codec, "Headphone Playback Volume", | ||
799 | spec->hp_independent_mode); | ||
800 | activate_ctl(codec, "Headphone Playback Switch", | ||
801 | spec->hp_independent_mode); | ||
802 | } | ||
803 | /* update jack power state */ | 724 | /* update jack power state */ |
804 | set_widgets_power_state(codec); | 725 | set_widgets_power_state(codec); |
805 | return 0; | 726 | return 0; |
806 | } | 727 | } |
807 | 728 | ||
808 | static const struct snd_kcontrol_new via_hp_mixer[2] = { | 729 | static const struct snd_kcontrol_new via_hp_mixer = { |
809 | { | 730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
810 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 731 | .name = "Independent HP", |
811 | .name = "Independent HP", | 732 | .info = via_independent_hp_info, |
812 | .info = via_independent_hp_info, | 733 | .get = via_independent_hp_get, |
813 | .get = via_independent_hp_get, | 734 | .put = via_independent_hp_put, |
814 | .put = via_independent_hp_put, | ||
815 | }, | ||
816 | { | ||
817 | .iface = NID_MAPPING, | ||
818 | .name = "Independent HP", | ||
819 | }, | ||
820 | }; | 735 | }; |
821 | 736 | ||
822 | static int via_hp_build(struct hda_codec *codec) | 737 | static int via_hp_build(struct hda_codec *codec) |
@@ -824,44 +739,15 @@ static int via_hp_build(struct hda_codec *codec) | |||
824 | struct via_spec *spec = codec->spec; | 739 | struct via_spec *spec = codec->spec; |
825 | struct snd_kcontrol_new *knew; | 740 | struct snd_kcontrol_new *knew; |
826 | hda_nid_t nid; | 741 | hda_nid_t nid; |
827 | int nums; | ||
828 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | ||
829 | 742 | ||
830 | switch (spec->codec_type) { | 743 | nid = spec->autocfg.hp_pins[0]; |
831 | case VT1718S: | 744 | knew = via_clone_control(spec, &via_hp_mixer); |
832 | nid = 0x34; | ||
833 | break; | ||
834 | case VT2002P: | ||
835 | case VT1802: | ||
836 | nid = 0x35; | ||
837 | break; | ||
838 | case VT1812: | ||
839 | nid = 0x3d; | ||
840 | break; | ||
841 | default: | ||
842 | nid = spec->autocfg.hp_pins[0]; | ||
843 | break; | ||
844 | } | ||
845 | |||
846 | if (spec->codec_type != VT1708) { | ||
847 | nums = snd_hda_get_connections(codec, nid, | ||
848 | conn, HDA_MAX_CONNECTIONS); | ||
849 | if (nums <= 1) | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | knew = via_clone_control(spec, &via_hp_mixer[0]); | ||
854 | if (knew == NULL) | 745 | if (knew == NULL) |
855 | return -ENOMEM; | 746 | return -ENOMEM; |
856 | 747 | ||
857 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | 748 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; |
858 | knew->private_value = nid; | 749 | knew->private_value = nid; |
859 | 750 | ||
860 | knew = via_clone_control(spec, &via_hp_mixer[1]); | ||
861 | if (knew == NULL) | ||
862 | return -ENOMEM; | ||
863 | knew->subdevice = side_mute_channel(spec); | ||
864 | |||
865 | return 0; | 751 | return 0; |
866 | } | 752 | } |
867 | 753 | ||
@@ -1199,20 +1085,26 @@ static void substream_set_idle(struct hda_codec *codec, | |||
1199 | analog_low_current_mode(codec, idle); | 1085 | analog_low_current_mode(codec, idle); |
1200 | } | 1086 | } |
1201 | 1087 | ||
1202 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | 1088 | static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, |
1203 | struct hda_codec *codec, | 1089 | struct hda_codec *codec, |
1204 | struct snd_pcm_substream *substream) | 1090 | struct snd_pcm_substream *substream) |
1205 | { | 1091 | { |
1206 | struct via_spec *spec = codec->spec; | 1092 | struct via_spec *spec = codec->spec; |
1093 | |||
1094 | if (!spec->hp_independent_mode) | ||
1095 | spec->multiout.hp_nid = spec->hp_dac_nid; | ||
1207 | substream_set_idle(codec, substream); | 1096 | substream_set_idle(codec, substream); |
1208 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | 1097 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, |
1209 | hinfo); | 1098 | hinfo); |
1210 | } | 1099 | } |
1211 | 1100 | ||
1212 | static int via_playback_pcm_close(struct hda_pcm_stream *hinfo, | 1101 | static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, |
1213 | struct hda_codec *codec, | 1102 | struct hda_codec *codec, |
1214 | struct snd_pcm_substream *substream) | 1103 | struct snd_pcm_substream *substream) |
1215 | { | 1104 | { |
1105 | struct via_spec *spec = codec->spec; | ||
1106 | |||
1107 | spec->multiout.hp_nid = 0; | ||
1216 | substream_set_idle(codec, substream); | 1108 | substream_set_idle(codec, substream); |
1217 | return 0; | 1109 | return 0; |
1218 | } | 1110 | } |
@@ -1222,11 +1114,19 @@ static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, | |||
1222 | struct snd_pcm_substream *substream) | 1114 | struct snd_pcm_substream *substream) |
1223 | { | 1115 | { |
1224 | struct via_spec *spec = codec->spec; | 1116 | struct via_spec *spec = codec->spec; |
1225 | struct hda_multi_out *mout = &spec->multiout; | ||
1226 | 1117 | ||
1227 | if (!mout->hp_nid || mout->hp_nid == mout->dac_nids[HDA_FRONT] || | 1118 | if (snd_BUG_ON(!spec->hp_dac_nid)) |
1228 | !spec->hp_independent_mode) | ||
1229 | return -EINVAL; | 1119 | return -EINVAL; |
1120 | if (!spec->hp_independent_mode || spec->multiout.hp_nid) | ||
1121 | return -EBUSY; | ||
1122 | substream_set_idle(codec, substream); | ||
1123 | return 0; | ||
1124 | } | ||
1125 | |||
1126 | static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, | ||
1127 | struct hda_codec *codec, | ||
1128 | struct snd_pcm_substream *substream) | ||
1129 | { | ||
1230 | substream_set_idle(codec, substream); | 1130 | substream_set_idle(codec, substream); |
1231 | return 0; | 1131 | return 0; |
1232 | } | 1132 | } |
@@ -1238,68 +1138,9 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1238 | struct snd_pcm_substream *substream) | 1138 | struct snd_pcm_substream *substream) |
1239 | { | 1139 | { |
1240 | struct via_spec *spec = codec->spec; | 1140 | struct via_spec *spec = codec->spec; |
1241 | struct hda_multi_out *mout = &spec->multiout; | 1141 | |
1242 | const hda_nid_t *nids = mout->dac_nids; | 1142 | snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, |
1243 | int chs = substream->runtime->channels; | 1143 | format, substream); |
1244 | int i; | ||
1245 | struct hda_spdif_out *spdif = | ||
1246 | snd_hda_spdif_out_of_nid(codec, spec->multiout.dig_out_nid); | ||
1247 | |||
1248 | mutex_lock(&codec->spdif_mutex); | ||
1249 | if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { | ||
1250 | if (chs == 2 && | ||
1251 | snd_hda_is_supported_format(codec, mout->dig_out_nid, | ||
1252 | format) && | ||
1253 | !(spdif->status & IEC958_AES0_NONAUDIO)) { | ||
1254 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; | ||
1255 | /* turn off SPDIF once; otherwise the IEC958 bits won't | ||
1256 | * be updated */ | ||
1257 | if (spdif->ctls & AC_DIG1_ENABLE) | ||
1258 | snd_hda_codec_write(codec, mout->dig_out_nid, 0, | ||
1259 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1260 | spdif->ctls & | ||
1261 | ~AC_DIG1_ENABLE & 0xff); | ||
1262 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1263 | stream_tag, 0, format); | ||
1264 | /* turn on again (if needed) */ | ||
1265 | if (spdif->ctls & AC_DIG1_ENABLE) | ||
1266 | snd_hda_codec_write(codec, mout->dig_out_nid, 0, | ||
1267 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1268 | spdif->ctls & 0xff); | ||
1269 | } else { | ||
1270 | mout->dig_out_used = 0; | ||
1271 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1272 | 0, 0, 0); | ||
1273 | } | ||
1274 | } | ||
1275 | mutex_unlock(&codec->spdif_mutex); | ||
1276 | |||
1277 | /* front */ | ||
1278 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, | ||
1279 | 0, format); | ||
1280 | |||
1281 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] | ||
1282 | && !spec->hp_independent_mode) | ||
1283 | /* headphone out will just decode front left/right (stereo) */ | ||
1284 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, | ||
1285 | 0, format); | ||
1286 | |||
1287 | /* extra outputs copied from front */ | ||
1288 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | ||
1289 | if (mout->extra_out_nid[i]) | ||
1290 | snd_hda_codec_setup_stream(codec, | ||
1291 | mout->extra_out_nid[i], | ||
1292 | stream_tag, 0, format); | ||
1293 | |||
1294 | /* surrounds */ | ||
1295 | for (i = 1; i < mout->num_dacs; i++) { | ||
1296 | if (chs >= (i + 1) * 2) /* independent out */ | ||
1297 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | ||
1298 | i * 2, format); | ||
1299 | else /* copy front */ | ||
1300 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | ||
1301 | 0, format); | ||
1302 | } | ||
1303 | vt1708_start_hp_work(spec); | 1144 | vt1708_start_hp_work(spec); |
1304 | return 0; | 1145 | return 0; |
1305 | } | 1146 | } |
@@ -1311,9 +1152,9 @@ static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1311 | struct snd_pcm_substream *substream) | 1152 | struct snd_pcm_substream *substream) |
1312 | { | 1153 | { |
1313 | struct via_spec *spec = codec->spec; | 1154 | struct via_spec *spec = codec->spec; |
1314 | struct hda_multi_out *mout = &spec->multiout; | ||
1315 | 1155 | ||
1316 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | 1156 | snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, |
1157 | stream_tag, 0, format); | ||
1317 | vt1708_start_hp_work(spec); | 1158 | vt1708_start_hp_work(spec); |
1318 | return 0; | 1159 | return 0; |
1319 | } | 1160 | } |
@@ -1323,30 +1164,8 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
1323 | struct snd_pcm_substream *substream) | 1164 | struct snd_pcm_substream *substream) |
1324 | { | 1165 | { |
1325 | struct via_spec *spec = codec->spec; | 1166 | struct via_spec *spec = codec->spec; |
1326 | struct hda_multi_out *mout = &spec->multiout; | ||
1327 | const hda_nid_t *nids = mout->dac_nids; | ||
1328 | int i; | ||
1329 | 1167 | ||
1330 | for (i = 0; i < mout->num_dacs; i++) | 1168 | snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); |
1331 | snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); | ||
1332 | |||
1333 | if (mout->hp_nid && !spec->hp_independent_mode) | ||
1334 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
1335 | 0, 0, 0); | ||
1336 | |||
1337 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | ||
1338 | if (mout->extra_out_nid[i]) | ||
1339 | snd_hda_codec_setup_stream(codec, | ||
1340 | mout->extra_out_nid[i], | ||
1341 | 0, 0, 0); | ||
1342 | mutex_lock(&codec->spdif_mutex); | ||
1343 | if (mout->dig_out_nid && | ||
1344 | mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | ||
1345 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1346 | 0, 0, 0); | ||
1347 | mout->dig_out_used = 0; | ||
1348 | } | ||
1349 | mutex_unlock(&codec->spdif_mutex); | ||
1350 | vt1708_stop_hp_work(spec); | 1169 | vt1708_stop_hp_work(spec); |
1351 | return 0; | 1170 | return 0; |
1352 | } | 1171 | } |
@@ -1356,9 +1175,8 @@ static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
1356 | struct snd_pcm_substream *substream) | 1175 | struct snd_pcm_substream *substream) |
1357 | { | 1176 | { |
1358 | struct via_spec *spec = codec->spec; | 1177 | struct via_spec *spec = codec->spec; |
1359 | struct hda_multi_out *mout = &spec->multiout; | ||
1360 | 1178 | ||
1361 | snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); | 1179 | snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); |
1362 | vt1708_stop_hp_work(spec); | 1180 | vt1708_stop_hp_work(spec); |
1363 | return 0; | 1181 | return 0; |
1364 | } | 1182 | } |
@@ -1433,8 +1251,8 @@ static const struct hda_pcm_stream via_pcm_analog_playback = { | |||
1433 | .channels_max = 8, | 1251 | .channels_max = 8, |
1434 | /* NID is set in via_build_pcms */ | 1252 | /* NID is set in via_build_pcms */ |
1435 | .ops = { | 1253 | .ops = { |
1436 | .open = via_playback_pcm_open, | 1254 | .open = via_playback_multi_pcm_open, |
1437 | .close = via_playback_pcm_close, | 1255 | .close = via_playback_multi_pcm_close, |
1438 | .prepare = via_playback_multi_pcm_prepare, | 1256 | .prepare = via_playback_multi_pcm_prepare, |
1439 | .cleanup = via_playback_multi_pcm_cleanup | 1257 | .cleanup = via_playback_multi_pcm_cleanup |
1440 | }, | 1258 | }, |
@@ -1447,7 +1265,7 @@ static const struct hda_pcm_stream via_pcm_hp_playback = { | |||
1447 | /* NID is set in via_build_pcms */ | 1265 | /* NID is set in via_build_pcms */ |
1448 | .ops = { | 1266 | .ops = { |
1449 | .open = via_playback_hp_pcm_open, | 1267 | .open = via_playback_hp_pcm_open, |
1450 | .close = via_playback_pcm_close, | 1268 | .close = via_playback_hp_pcm_close, |
1451 | .prepare = via_playback_hp_pcm_prepare, | 1269 | .prepare = via_playback_hp_pcm_prepare, |
1452 | .cleanup = via_playback_hp_pcm_cleanup | 1270 | .cleanup = via_playback_hp_pcm_cleanup |
1453 | }, | 1271 | }, |
@@ -1464,8 +1282,8 @@ static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { | |||
1464 | */ | 1282 | */ |
1465 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1283 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1466 | .ops = { | 1284 | .ops = { |
1467 | .open = via_playback_pcm_open, | 1285 | .open = via_playback_multi_pcm_open, |
1468 | .close = via_playback_pcm_close, | 1286 | .close = via_playback_multi_pcm_close, |
1469 | .prepare = via_playback_multi_pcm_prepare, | 1287 | .prepare = via_playback_multi_pcm_prepare, |
1470 | .cleanup = via_playback_multi_pcm_cleanup | 1288 | .cleanup = via_playback_multi_pcm_cleanup |
1471 | }, | 1289 | }, |
@@ -1477,8 +1295,6 @@ static const struct hda_pcm_stream via_pcm_analog_capture = { | |||
1477 | .channels_max = 2, | 1295 | .channels_max = 2, |
1478 | /* NID is set in via_build_pcms */ | 1296 | /* NID is set in via_build_pcms */ |
1479 | .ops = { | 1297 | .ops = { |
1480 | .open = via_playback_pcm_open, | ||
1481 | .close = via_playback_pcm_close, | ||
1482 | .prepare = via_capture_pcm_prepare, | 1298 | .prepare = via_capture_pcm_prepare, |
1483 | .cleanup = via_capture_pcm_cleanup | 1299 | .cleanup = via_capture_pcm_cleanup |
1484 | }, | 1300 | }, |
@@ -1624,7 +1440,7 @@ static int via_build_pcms(struct hda_codec *codec) | |||
1624 | } | 1440 | } |
1625 | } | 1441 | } |
1626 | 1442 | ||
1627 | if (spec->multiout.hp_nid) { | 1443 | if (spec->hp_dac_nid) { |
1628 | codec->num_pcms++; | 1444 | codec->num_pcms++; |
1629 | info++; | 1445 | info++; |
1630 | snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), | 1446 | snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), |
@@ -1632,7 +1448,7 @@ static int via_build_pcms(struct hda_codec *codec) | |||
1632 | info->name = spec->stream_name_hp; | 1448 | info->name = spec->stream_name_hp; |
1633 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; | 1449 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; |
1634 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 1450 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
1635 | spec->multiout.hp_nid; | 1451 | spec->hp_dac_nid; |
1636 | } | 1452 | } |
1637 | return 0; | 1453 | return 0; |
1638 | } | 1454 | } |
@@ -1883,7 +1699,7 @@ static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) | |||
1883 | if (spec->multiout.dac_nids[i] == dac) | 1699 | if (spec->multiout.dac_nids[i] == dac) |
1884 | return false; | 1700 | return false; |
1885 | } | 1701 | } |
1886 | if (spec->multiout.hp_nid == dac) | 1702 | if (spec->hp_dac_nid == dac) |
1887 | return false; | 1703 | return false; |
1888 | return true; | 1704 | return true; |
1889 | } | 1705 | } |
@@ -2076,24 +1892,25 @@ static void create_hp_imux(struct via_spec *spec) | |||
2076 | static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) | 1892 | static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) |
2077 | { | 1893 | { |
2078 | struct via_spec *spec = codec->spec; | 1894 | struct via_spec *spec = codec->spec; |
2079 | hda_nid_t dac = 0; | ||
2080 | int err; | 1895 | int err; |
2081 | 1896 | ||
2082 | if (!pin) | 1897 | if (!pin) |
2083 | return 0; | 1898 | return 0; |
2084 | 1899 | ||
2085 | if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], | ||
2086 | &spec->hp_dep_path, 0, -1)) | ||
2087 | return 0; | ||
2088 | if (parse_output_path(codec, pin, 0, &spec->hp_path, 0, -1)) { | 1900 | if (parse_output_path(codec, pin, 0, &spec->hp_path, 0, -1)) { |
2089 | dac = spec->hp_path.path[spec->hp_path.depth - 1]; | 1901 | spec->hp_dac_nid = spec->hp_path.path[spec->hp_path.depth - 1]; |
2090 | spec->multiout.hp_nid = dac; | ||
2091 | spec->hp_independent_mode_index = | 1902 | spec->hp_independent_mode_index = |
2092 | spec->hp_path.idx[spec->hp_path.depth - 1]; | 1903 | spec->hp_path.idx[spec->hp_path.depth - 1]; |
2093 | create_hp_imux(spec); | 1904 | create_hp_imux(spec); |
2094 | } | 1905 | } |
2095 | 1906 | ||
2096 | err = create_ch_ctls(codec, "Headphone", pin, dac, 3); | 1907 | if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], |
1908 | &spec->hp_dep_path, 0, -1) && | ||
1909 | !spec->hp_dac_nid) | ||
1910 | return 0; | ||
1911 | |||
1912 | |||
1913 | err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3); | ||
2097 | if (err < 0) | 1914 | if (err < 0) |
2098 | return err; | 1915 | return err; |
2099 | 1916 | ||
@@ -2364,8 +2181,11 @@ static int via_parse_auto_config(struct hda_codec *codec) | |||
2364 | 2181 | ||
2365 | spec->input_mux = &spec->private_imux[0]; | 2182 | spec->input_mux = &spec->private_imux[0]; |
2366 | 2183 | ||
2367 | if (spec->hp_mux) | 2184 | if (spec->hp_mux) { |
2368 | via_hp_build(codec); | 2185 | err = via_hp_build(codec); |
2186 | if (err < 0) | ||
2187 | return err; | ||
2188 | } | ||
2369 | 2189 | ||
2370 | err = via_smart51_build(codec); | 2190 | err = via_smart51_build(codec); |
2371 | if (err < 0) | 2191 | if (err < 0) |