diff options
-rw-r--r-- | sound/pci/hda/hda_generic.c | 106 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 4 |
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 */ | ||
1119 | static 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 */ |
1119 | static int fill_and_eval_dacs(struct hda_codec *codec, | 1137 | static 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 | |||
1767 | static 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 | |||
1776 | static 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 | |||
1794 | static 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 | |||
1813 | static 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 | |||
1821 | static 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; |