aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_generic.c106
-rw-r--r--sound/pci/hda/hda_generic.h4
2 files changed, 110 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index e7574a863d21..a34c581b6082 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -1115,6 +1115,24 @@ static bool map_singles(struct hda_codec *codec, int outs,
1115 return found; 1115 return found;
1116} 1116}
1117 1117
1118/* create a new path including aamix if available, and return its index */
1119static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
1120{
1121 struct nid_path *path;
1122
1123 path = snd_hda_get_path_from_idx(codec, path_idx);
1124 if (!path || !path->depth || path->with_aa_mix)
1125 return 0;
1126 path = snd_hda_add_new_path(codec, path->path[0],
1127 path->path[path->depth - 1],
1128 HDA_PARSE_ONLY_AAMIX);
1129 if (!path)
1130 return 0;
1131 print_nid_path("output-aamix", path);
1132 path->active = false; /* unused as default */
1133 return snd_hda_get_path_idx(codec, path);
1134}
1135
1118/* fill in the dac_nids table from the parsed pin configuration */ 1136/* fill in the dac_nids table from the parsed pin configuration */
1119static int fill_and_eval_dacs(struct hda_codec *codec, 1137static int fill_and_eval_dacs(struct hda_codec *codec,
1120 bool fill_hardwired, 1138 bool fill_hardwired,
@@ -1211,6 +1229,17 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
1211 badness += err; 1229 badness += err;
1212 } 1230 }
1213 1231
1232 if (spec->mixer_nid) {
1233 spec->aamix_out_paths[0] =
1234 check_aamix_out_path(codec, spec->out_paths[0]);
1235 if (cfg->line_out_type != AUTO_PIN_HP_OUT)
1236 spec->aamix_out_paths[1] =
1237 check_aamix_out_path(codec, spec->hp_paths[0]);
1238 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1239 spec->aamix_out_paths[2] =
1240 check_aamix_out_path(codec, spec->speaker_paths[0]);
1241 }
1242
1214 if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) 1243 if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
1215 if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) 1244 if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
1216 spec->multi_ios = 1; /* give badness */ 1245 spec->multi_ios = 1; /* give badness */
@@ -1730,6 +1759,80 @@ static int create_multi_channel_mode(struct hda_codec *codec)
1730} 1759}
1731 1760
1732/* 1761/*
1762 * aamix loopback enable/disable switch
1763 */
1764
1765#define loopback_mixing_info indep_hp_info
1766
1767static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
1768 struct snd_ctl_elem_value *ucontrol)
1769{
1770 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1771 struct hda_gen_spec *spec = codec->spec;
1772 ucontrol->value.enumerated.item[0] = spec->aamix_mode;
1773 return 0;
1774}
1775
1776static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
1777 int nomix_path_idx, int mix_path_idx)
1778{
1779 struct nid_path *nomix_path, *mix_path;
1780
1781 nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
1782 mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
1783 if (!nomix_path || !mix_path)
1784 return;
1785 if (do_mix) {
1786 snd_hda_activate_path(codec, nomix_path, false, true);
1787 snd_hda_activate_path(codec, mix_path, true, true);
1788 } else {
1789 snd_hda_activate_path(codec, mix_path, false, true);
1790 snd_hda_activate_path(codec, nomix_path, true, true);
1791 }
1792}
1793
1794static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
1795 struct snd_ctl_elem_value *ucontrol)
1796{
1797 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1798 struct hda_gen_spec *spec = codec->spec;
1799 unsigned int val = ucontrol->value.enumerated.item[0];
1800
1801 if (val == spec->aamix_mode)
1802 return 0;
1803 spec->aamix_mode = val;
1804 update_aamix_paths(codec, val, spec->out_paths[0],
1805 spec->aamix_out_paths[0]);
1806 update_aamix_paths(codec, val, spec->hp_paths[0],
1807 spec->aamix_out_paths[1]);
1808 update_aamix_paths(codec, val, spec->speaker_paths[0],
1809 spec->aamix_out_paths[2]);
1810 return 1;
1811}
1812
1813static const struct snd_kcontrol_new loopback_mixing_enum = {
1814 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1815 .name = "Loopback Mixing",
1816 .info = loopback_mixing_info,
1817 .get = loopback_mixing_get,
1818 .put = loopback_mixing_put,
1819};
1820
1821static int create_loopback_mixing_ctl(struct hda_codec *codec)
1822{
1823 struct hda_gen_spec *spec = codec->spec;
1824
1825 if (!spec->mixer_nid)
1826 return 0;
1827 if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
1828 spec->aamix_out_paths[2]))
1829 return 0;
1830 if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
1831 return -ENOMEM;
1832 return 0;
1833}
1834
1835/*
1733 * shared headphone/mic handling 1836 * shared headphone/mic handling
1734 */ 1837 */
1735 1838
@@ -3067,6 +3170,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
3067 err = create_indep_hp_ctls(codec); 3170 err = create_indep_hp_ctls(codec);
3068 if (err < 0) 3171 if (err < 0)
3069 return err; 3172 return err;
3173 err = create_loopback_mixing_ctl(codec);
3174 if (err < 0)
3175 return err;
3070 err = create_shared_input(codec); 3176 err = create_shared_input(codec);
3071 if (err < 0) 3177 if (err < 0)
3072 return err; 3178 return err;
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index ba8de12b7125..d4a8f6c4e7a9 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -134,6 +134,7 @@ struct hda_gen_spec {
134 int out_paths[AUTO_CFG_MAX_OUTS]; 134 int out_paths[AUTO_CFG_MAX_OUTS];
135 int hp_paths[AUTO_CFG_MAX_OUTS]; 135 int hp_paths[AUTO_CFG_MAX_OUTS];
136 int speaker_paths[AUTO_CFG_MAX_OUTS]; 136 int speaker_paths[AUTO_CFG_MAX_OUTS];
137 int aamix_out_paths[3];
137 int digout_paths[AUTO_CFG_MAX_OUTS]; 138 int digout_paths[AUTO_CFG_MAX_OUTS];
138 int loopback_paths[HDA_MAX_NUM_INPUTS]; 139 int loopback_paths[HDA_MAX_NUM_INPUTS];
139 int digin_path; 140 int digin_path;
@@ -169,6 +170,9 @@ struct hda_gen_spec {
169 unsigned int indep_hp:1; /* independent HP supported */ 170 unsigned int indep_hp:1; /* independent HP supported */
170 unsigned int indep_hp_enabled:1; /* independent HP enabled */ 171 unsigned int indep_hp_enabled:1; /* independent HP enabled */
171 172
173 /* loopback mixing mode */
174 bool aamix_mode;
175
172 /* for virtual master */ 176 /* for virtual master */
173 hda_nid_t vmaster_nid; 177 hda_nid_t vmaster_nid;
174 struct hda_vmaster_mute_hook vmaster_mute; 178 struct hda_vmaster_mute_hook vmaster_mute;