* parsing paths
*/
-/* get the path between the given NIDs;
- * passing 0 to either @pin or @dac behaves as a wildcard
- */
-struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
- hda_nid_t from_nid, hda_nid_t to_nid)
+static struct nid_path *get_nid_path(struct hda_codec *codec,
+ hda_nid_t from_nid, hda_nid_t to_nid,
+ int with_aa_mix)
{
struct hda_gen_spec *spec = codec->spec;
int i;
if (path->depth <= 0)
continue;
if ((!from_nid || path->path[0] == from_nid) &&
- (!to_nid || path->path[path->depth - 1] == to_nid))
- return path;
+ (!to_nid || path->path[path->depth - 1] == to_nid)) {
+ if (with_aa_mix == HDA_PARSE_ALL ||
+ path->with_aa_mix == with_aa_mix)
+ return path;
+ }
}
return NULL;
}
+
+/* get the path between the given NIDs;
+ * passing 0 to either @pin or @dac behaves as a wildcard
+ */
+struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
+ hda_nid_t from_nid, hda_nid_t to_nid)
+{
+ return get_nid_path(codec, from_nid, to_nid, HDA_PARSE_ALL);
+}
EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
+/* get the index number corresponding to the path instance;
+ * the index starts from 1, for easier checking the invalid value
+ */
+int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ struct nid_path *array = spec->paths.list;
+ ssize_t idx;
+
+ if (!spec->paths.used)
+ return 0;
+ idx = path - array;
+ if (idx < 0 || idx >= spec->paths.used)
+ return 0;
+ return idx + 1;
+}
+
+/* get the path instance corresponding to the given index number */
+struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (idx <= 0 || idx > spec->paths.used)
+ return NULL;
+ return snd_array_elem(&spec->paths, idx - 1);
+}
+
/* check whether the given DAC is already found in any existing paths */
static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
{
found:
path->path[path->depth] = conn[i];
+ if (conn[i] == spec->mixer_nid)
+ path->with_aa_mix = true;
path->idx[path->depth + 1] = i;
if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
path->multi[path->depth + 1] = 1;
if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
return NULL;
+ /* check whether the path has been already added */
+ path = get_nid_path(codec, from_nid, to_nid, with_aa_mix);
+ if (path)
+ return path;
+
path = snd_array_new(&spec->paths);
if (!path)
return NULL;
.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
};
+/* get the DAC of the primary output corresponding to the given array index */
+static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+
+ if (cfg->line_outs > idx)
+ return spec->private_dac_nids[idx];
+ idx -= cfg->line_outs;
+ if (spec->multi_ios > idx)
+ return spec->multi_io[idx].dac;
+ return 0;
+}
+
+/* return the DAC if it's reachable, otherwise zero */
+static inline hda_nid_t try_dac(struct hda_codec *codec,
+ hda_nid_t dac, hda_nid_t pin)
+{
+ return is_reachable_path(codec, dac, pin) ? dac : 0;
+}
+
/* try to assign DACs to pins and return the resultant badness */
static int try_assign_dacs(struct hda_codec *codec, int num_outs,
const hda_nid_t *pins, hda_nid_t *dacs,
+ int *path_idx,
const struct badness_table *bad)
{
struct hda_gen_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
int i, j;
int badness = 0;
hda_nid_t dac;
for (i = 0; i < num_outs; i++) {
struct nid_path *path;
hda_nid_t pin = pins[i];
- if (!dacs[i])
- dacs[i] = look_for_dac(codec, pin, false);
+
+ if (dacs[i]) {
+ badness += assign_out_path_ctls(codec, pin, dacs[i]);
+ continue;
+ }
+
+ dacs[i] = look_for_dac(codec, pin, false);
if (!dacs[i] && !i) {
for (j = 1; j < num_outs; j++) {
if (is_reachable_path(codec, dacs[j], pin)) {
dacs[0] = dacs[j];
dacs[j] = 0;
+ path_idx[j] = 0;
break;
}
}
}
dac = dacs[i];
if (!dac) {
- if (is_reachable_path(codec, dacs[0], pin))
- dac = dacs[0];
- else if (cfg->line_outs > i &&
- is_reachable_path(codec, spec->private_dac_nids[i], pin))
- dac = spec->private_dac_nids[i];
+ if (num_outs > 2)
+ dac = try_dac(codec, get_primary_out(codec, i), pin);
+ if (!dac)
+ dac = try_dac(codec, dacs[0], pin);
+ if (!dac)
+ dac = try_dac(codec, get_primary_out(codec, i), pin);
if (dac) {
if (!i)
badness += bad->shared_primary;
badness += bad->no_dac;
}
path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_NO_AAMIX);
- if (!path && i > 0 && spec->mixer_nid) {
+ if (!path && !i && spec->mixer_nid) {
/* try with aamix */
path = snd_hda_add_new_path(codec, dac, pin, HDA_PARSE_ALL);
}
if (!path)
dac = dacs[i] = 0;
- else
+ else {
print_nid_path("output", path);
+ path->active = true;
+ path_idx[i] = snd_hda_get_path_idx(codec, path);
+ }
if (dac)
badness += assign_out_path_ctls(codec, pin, dac);
}
return true;
}
+/* count the number of input pins that are capable to be multi-io */
+static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
+ unsigned int location = get_defcfg_location(defcfg);
+ int type, i;
+ int num_pins = 0;
+
+ for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].type != type)
+ continue;
+ if (can_be_multiio_pin(codec, location,
+ cfg->inputs[i].pin))
+ num_pins++;
+ }
+ }
+ return num_pins;
+}
+
/*
* multi-io helper
*
*/
static int fill_multi_ios(struct hda_codec *codec,
hda_nid_t reference_pin,
- bool hardwired, int offset)
+ bool hardwired)
{
struct hda_gen_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- int type, i, j, dacs, num_pins, old_pins;
+ int type, i, j, num_pins, old_pins;
unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
unsigned int location = get_defcfg_location(defcfg);
int badness = 0;
if (old_pins >= 2)
goto end_fill;
- num_pins = 0;
- for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].type != type)
- continue;
- if (can_be_multiio_pin(codec, location,
- cfg->inputs[i].pin))
- num_pins++;
- }
- }
+ num_pins = count_multiio_pins(codec, reference_pin);
if (num_pins < 2)
goto end_fill;
- dacs = spec->multiout.num_dacs;
for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
for (i = 0; i < cfg->num_inputs; i++) {
struct nid_path *path;
if (j < spec->multi_ios)
continue;
- if (offset && offset + spec->multi_ios < dacs) {
- dac = spec->private_dac_nids[offset + spec->multi_ios];
- if (!is_reachable_path(codec, dac, nid))
- dac = 0;
- }
if (hardwired)
dac = get_dac_if_single(codec, nid);
else if (!dac)
print_nid_path("multiio", path);
spec->multi_io[spec->multi_ios].pin = nid;
spec->multi_io[spec->multi_ios].dac = dac;
+ spec->out_paths[cfg->line_outs + spec->multi_ios] =
+ snd_hda_get_path_idx(codec, path);
spec->multi_ios++;
if (spec->multi_ios >= 2)
break;
/* map DACs for all pins in the list if they are single connections */
static bool map_singles(struct hda_codec *codec, int outs,
- const hda_nid_t *pins, hda_nid_t *dacs)
+ const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
{
struct hda_gen_spec *spec = codec->spec;
int i;
if (!dac)
continue;
path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_NO_AAMIX);
- if (!path && i > 0 && spec->mixer_nid)
+ if (!path && !i && spec->mixer_nid)
path = snd_hda_add_new_path(codec, dac, pins[i], HDA_PARSE_ALL);
if (path) {
dacs[i] = dac;
found = true;
print_nid_path("output", path);
+ path->active = true;
+ path_idx[i] = snd_hda_get_path_idx(codec, path);
}
}
return found;
}
+/* create a new path including aamix if available, and return its index */
+static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
+{
+ struct nid_path *path;
+
+ path = snd_hda_get_path_from_idx(codec, path_idx);
+ if (!path || !path->depth || path->with_aa_mix)
+ return 0;
+ path = snd_hda_add_new_path(codec, path->path[0],
+ path->path[path->depth - 1],
+ HDA_PARSE_ONLY_AAMIX);
+ if (!path)
+ return 0;
+ print_nid_path("output-aamix", path);
+ path->active = false; /* unused as default */
+ return snd_hda_get_path_idx(codec, path);
+}
+
/* fill in the dac_nids table from the parsed pin configuration */
static int fill_and_eval_dacs(struct hda_codec *codec,
bool fill_hardwired,
do {
mapped = map_singles(codec, cfg->line_outs,
cfg->line_out_pins,
- spec->private_dac_nids);
+ spec->private_dac_nids,
+ spec->out_paths);
mapped |= map_singles(codec, cfg->hp_outs,
cfg->hp_pins,
- spec->multiout.hp_out_nid);
+ spec->multiout.hp_out_nid,
+ spec->hp_paths);
mapped |= map_singles(codec, cfg->speaker_outs,
cfg->speaker_pins,
- spec->multiout.extra_out_nid);
+ spec->multiout.extra_out_nid,
+ spec->speaker_paths);
if (fill_mio_first && cfg->line_outs == 1 &&
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
- err = fill_multi_ios(codec, cfg->line_out_pins[0], true, 0);
+ err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
if (!err)
mapped = true;
}
}
badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
- spec->private_dac_nids,
+ spec->private_dac_nids, spec->out_paths,
&main_out_badness);
/* re-count num_dacs and squash invalid entries */
if (fill_mio_first &&
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
/* try to fill multi-io first */
- err = fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+ err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
if (err < 0)
return err;
/* we don't count badness at this stage yet */
if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
spec->multiout.hp_out_nid,
+ spec->hp_paths,
&extra_out_badness);
if (err < 0)
return err;
err = try_assign_dacs(codec, cfg->speaker_outs,
cfg->speaker_pins,
spec->multiout.extra_out_nid,
- &extra_out_badness);
+ spec->speaker_paths,
+ &extra_out_badness);
if (err < 0)
return err;
badness += err;
}
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
- err = fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+ err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
if (err < 0)
return err;
badness += err;
}
- if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
- /* try multi-ios with HP + inputs */
- int offset = 0;
- if (cfg->line_outs >= 3)
- offset = 1;
- err = fill_multi_ios(codec, cfg->hp_pins[0], false, offset);
- if (err < 0)
- return err;
- badness += err;
+
+ if (spec->mixer_nid) {
+ spec->aamix_out_paths[0] =
+ check_aamix_out_path(codec, spec->out_paths[0]);
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+ spec->aamix_out_paths[1] =
+ check_aamix_out_path(codec, spec->hp_paths[0]);
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+ spec->aamix_out_paths[2] =
+ check_aamix_out_path(codec, spec->speaker_paths[0]);
}
+ if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+ if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
+ spec->multi_ios = 1; /* give badness */
+
if (spec->multi_ios == 2) {
for (i = 0; i < 2; i++)
spec->private_dac_nids[spec->multiout.num_dacs++] =
if (cfg->line_out_pins[0]) {
struct nid_path *path;
- path = snd_hda_get_nid_path(codec,
- spec->multiout.dac_nids[0],
- cfg->line_out_pins[0]);
+ path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
if (path)
spec->vmaster_nid = look_for_out_vol_nid(codec, path);
}
for (i = 0; i < noutputs; i++) {
const char *name;
int index;
- hda_nid_t dac, pin;
+ hda_nid_t dac;
struct nid_path *path;
dac = spec->multiout.dac_nids[i];
if (!dac)
continue;
if (i >= cfg->line_outs) {
- pin = spec->multi_io[i - 1].pin;
index = 0;
name = channel_name[i];
} else {
- pin = cfg->line_out_pins[i];
name = get_line_out_pfx(spec, i, true, &index);
}
- path = snd_hda_get_nid_path(codec, dac, pin);
+ path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
if (!path)
continue;
if (!name || !strcmp(name, "CLFE")) {
}
static int create_extra_out(struct hda_codec *codec, hda_nid_t pin,
- hda_nid_t dac, const char *pfx, int cidx)
+ hda_nid_t dac, int path_idx,
+ const char *pfx, int cidx)
{
struct nid_path *path;
int err;
- path = snd_hda_get_nid_path(codec, dac, pin);
+ path = snd_hda_get_path_from_idx(codec, path_idx);
if (!path)
return 0;
/* bind volume control will be created in the case of dac = 0 */
/* add playback controls for speaker and HP outputs */
static int create_extra_outs(struct hda_codec *codec, int num_pins,
const hda_nid_t *pins, const hda_nid_t *dacs,
- const char *pfx)
+ const int *paths, const char *pfx)
{
struct hda_gen_spec *spec = codec->spec;
struct hda_bind_ctls *ctl;
- char name[32];
+ char name[44];
int i, n, err;
if (!num_pins || !pins[0])
hda_nid_t dac = *dacs;
if (!dac)
dac = spec->multiout.dac_nids[0];
- return create_extra_out(codec, *pins, dac, pfx, 0);
+ return create_extra_out(codec, *pins, dac, paths[0], pfx, 0);
}
for (i = 0; i < num_pins; i++) {
else
dac = 0;
if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) {
- err = create_extra_out(codec, pins[i], dac,
+ err = create_extra_out(codec, pins[i], dac, paths[i],
"Bass Speaker", 0);
} else if (num_pins >= 3) {
snprintf(name, sizeof(name), "%s %s",
pfx, channel_name[i]);
- err = create_extra_out(codec, pins[i], dac, name, 0);
+ err = create_extra_out(codec, pins[i], dac, paths[i],
+ name, 0);
} else {
- err = create_extra_out(codec, pins[i], dac, pfx, i);
+ err = create_extra_out(codec, pins[i], dac, paths[i],
+ pfx, i);
}
if (err < 0)
return err;
struct nid_path *path;
if (!pins[i] || !dacs[i])
continue;
- path = snd_hda_get_nid_path(codec, dacs[i], pins[i]);
+ path = snd_hda_get_path_from_idx(codec, paths[i]);
if (!path)
continue;
vol = look_for_out_vol_nid(codec, path);
return create_extra_outs(codec, spec->autocfg.hp_outs,
spec->autocfg.hp_pins,
spec->multiout.hp_out_nid,
+ spec->hp_paths,
"Headphone");
}
return create_extra_outs(codec, spec->autocfg.speaker_outs,
spec->autocfg.speaker_pins,
spec->multiout.extra_out_nid,
+ spec->speaker_paths,
"Speaker");
}
return 0;
}
+static inline struct nid_path *
+get_multiio_path(struct hda_codec *codec, int idx)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ return snd_hda_get_path_from_idx(codec,
+ spec->out_paths[spec->autocfg.line_outs + idx]);
+}
+
static int set_multi_io(struct hda_codec *codec, int idx, bool output)
{
struct hda_gen_spec *spec = codec->spec;
hda_nid_t nid = spec->multi_io[idx].pin;
struct nid_path *path;
- path = snd_hda_get_nid_path(codec, spec->multi_io[idx].dac, nid);
+ path = get_multiio_path(codec, idx);
if (!path)
return -EINVAL;
return 0;
}
+/*
+ * aamix loopback enable/disable switch
+ */
+
+#define loopback_mixing_info indep_hp_info
+
+static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->aamix_mode;
+ return 0;
+}
+
+static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
+ int nomix_path_idx, int mix_path_idx)
+{
+ struct nid_path *nomix_path, *mix_path;
+
+ nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
+ mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
+ if (!nomix_path || !mix_path)
+ return;
+ if (do_mix) {
+ snd_hda_activate_path(codec, nomix_path, false, true);
+ snd_hda_activate_path(codec, mix_path, true, true);
+ } else {
+ snd_hda_activate_path(codec, mix_path, false, true);
+ snd_hda_activate_path(codec, nomix_path, true, true);
+ }
+}
+
+static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int val = ucontrol->value.enumerated.item[0];
+
+ if (val == spec->aamix_mode)
+ return 0;
+ spec->aamix_mode = val;
+ update_aamix_paths(codec, val, spec->out_paths[0],
+ spec->aamix_out_paths[0]);
+ update_aamix_paths(codec, val, spec->hp_paths[0],
+ spec->aamix_out_paths[1]);
+ update_aamix_paths(codec, val, spec->speaker_paths[0],
+ spec->aamix_out_paths[2]);
+ return 1;
+}
+
+static const struct snd_kcontrol_new loopback_mixing_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Loopback Mixing",
+ .info = loopback_mixing_info,
+ .get = loopback_mixing_get,
+ .put = loopback_mixing_put,
+};
+
+static int create_loopback_mixing_ctl(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (!spec->mixer_nid)
+ return 0;
+ if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
+ spec->aamix_out_paths[2]))
+ return 0;
+ if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
+ return -ENOMEM;
+ return 0;
+}
+
/*
* shared headphone/mic handling
*/
#endif
/* create input playback/capture controls for the given pin */
-static int new_analog_input(struct hda_codec *codec, hda_nid_t pin,
- const char *ctlname, int ctlidx,
+static int new_analog_input(struct hda_codec *codec, int input_idx,
+ hda_nid_t pin, const char *ctlname, int ctlidx,
hda_nid_t mix_nid)
{
struct hda_gen_spec *spec = codec->spec;
if (!path)
return -EINVAL;
print_nid_path("loopback", path);
+ spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
idx = path->idx[path->depth - 1];
if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
if (mixer) {
if (is_reachable_path(codec, pin, mixer)) {
- err = new_analog_input(codec, pin,
+ err = new_analog_input(codec, i, pin,
label, type_idx, mixer);
if (err < 0)
return err;
nid = cfg->inputs[i].pin;
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
const char *label;
- char boost_label[32];
+ char boost_label[44];
struct nid_path *path;
unsigned int val;
if (!path)
continue;
print_nid_path("digout", path);
+ path->active = true;
+ spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
if (!nums) {
spec->multiout.dig_out_nid = dig_nid;
spec->dig_out_type = spec->autocfg.dig_out_type[0];
print_nid_path("digin", path);
path->active = true;
spec->dig_in_nid = dig_nid;
+ spec->digin_path = snd_hda_get_path_idx(codec, path);
break;
}
}
if (err < 0)
return err;
err = create_indep_hp_ctls(codec);
+ if (err < 0)
+ return err;
+ err = create_loopback_mixing_ctl(codec);
if (err < 0)
return err;
err = create_shared_input(codec);
"Front", "Surround", "Center", "LFE", "Side",
"Headphone", "Speaker", "Mono", "Line Out",
"CLFE", "Bass Speaker", "PCM",
+ "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
+ "Headphone Front", "Headphone Surround", "Headphone CLFE",
+ "Headphone Side",
NULL,
};
/* configure the path from the given dac to the pin as the proper output */
static void set_output_and_unmute(struct hda_codec *codec, hda_nid_t pin,
- int pin_type, hda_nid_t dac)
+ int pin_type, int path_idx)
{
struct nid_path *path;
snd_hda_set_pin_ctl_cache(codec, pin, pin_type);
- path = snd_hda_get_nid_path(codec, dac, pin);
+ path = snd_hda_get_path_from_idx(codec, path_idx);
if (!path)
return;
- if (path->active)
- return;
- snd_hda_activate_path(codec, path, true, true);
- set_pin_eapd(codec, pin, true);
+ snd_hda_activate_path(codec, path, path->active, true);
+ set_pin_eapd(codec, pin, path->active);
}
/* initialize primary output paths */
static void init_multi_out(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
- hda_nid_t nid, dac;
+ hda_nid_t nid;
int pin_type;
int i;
for (i = 0; i < spec->autocfg.line_outs; i++) {
nid = spec->autocfg.line_out_pins[i];
- if (nid) {
- dac = spec->multiout.dac_nids[i];
- if (!dac)
- dac = spec->multiout.dac_nids[0];
- set_output_and_unmute(codec, nid, pin_type, dac);
- }
+ if (nid)
+ set_output_and_unmute(codec, nid, pin_type,
+ spec->out_paths[i]);
}
}
static void __init_extra_out(struct hda_codec *codec, int num_outs,
- hda_nid_t *pins, hda_nid_t *dacs, int type)
+ hda_nid_t *pins, int *paths, int type)
{
- struct hda_gen_spec *spec = codec->spec;
int i;
- hda_nid_t pin, dac;
+ hda_nid_t pin;
for (i = 0; i < num_outs; i++) {
pin = pins[i];
if (!pin)
break;
- dac = dacs[i];
- if (!dac) {
- if (i > 0 && dacs[0])
- dac = dacs[0];
- else
- dac = spec->multiout.dac_nids[0];
- }
- set_output_and_unmute(codec, pin, type, dac);
+ set_output_and_unmute(codec, pin, type, paths[i]);
}
}
if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
__init_extra_out(codec, spec->autocfg.hp_outs,
spec->autocfg.hp_pins,
- spec->multiout.hp_out_nid, PIN_HP);
+ spec->hp_paths, PIN_HP);
if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
__init_extra_out(codec, spec->autocfg.speaker_outs,
spec->autocfg.speaker_pins,
- spec->multiout.extra_out_nid, PIN_OUT);
+ spec->speaker_paths, PIN_OUT);
}
/* initialize multi-io paths */
for (i = 0; i < spec->multi_ios; i++) {
hda_nid_t pin = spec->multi_io[i].pin;
struct nid_path *path;
- path = snd_hda_get_nid_path(codec, spec->multi_io[i].dac, pin);
+ path = get_multiio_path(codec, i);
if (!path)
continue;
if (!spec->multi_io[i].ctl_in)
/* init loopback inputs */
if (spec->mixer_nid) {
struct nid_path *path;
- path = snd_hda_get_nid_path(codec, nid, spec->mixer_nid);
+ path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]);
if (path)
snd_hda_activate_path(codec, path,
path->active, false);
pin = spec->autocfg.dig_out_pins[i];
if (!pin)
continue;
- set_output_and_unmute(codec, pin, PIN_OUT, 0);
+ set_output_and_unmute(codec, pin, PIN_OUT,
+ spec->digout_paths[i]);
}
pin = spec->autocfg.dig_in_pin;
- if (pin)
+ if (pin) {
+ struct nid_path *path;
snd_hda_set_pin_ctl_cache(codec, pin, PIN_IN);
+ path = snd_hda_get_path_from_idx(codec, spec->digin_path);
+ if (path)
+ snd_hda_activate_path(codec, path, path->active, false);
+ }
}
/* clear unsol-event tags on unused pins; Conexant codecs seem to leave