diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 93db02121efb..c8bf81230206 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -147,6 +147,33 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, } 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) { @@ -836,6 +863,7 @@ static struct badness_table extra_out_badness = { /* 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; @@ -862,6 +890,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, if (is_reachable_path(codec, dacs[j], pin)) { dacs[0] = dacs[j]; dacs[j] = 0; + path_idx[j] = 0; break; } } @@ -898,6 +927,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, 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); @@ -1025,6 +1055,8 @@ static int fill_multi_ios(struct hda_codec *codec, 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; @@ -1056,7 +1088,7 @@ static int fill_multi_ios(struct hda_codec *codec, /* 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; @@ -1077,6 +1109,7 @@ static bool map_singles(struct hda_codec *codec, int outs, found = true; print_nid_path("output", path); path->active = true; + path_idx[i] = snd_hda_get_path_idx(codec, path); } } return found; @@ -1107,13 +1140,16 @@ static int fill_and_eval_dacs(struct hda_codec *codec, 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); @@ -1124,7 +1160,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, } 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 */ @@ -1152,6 +1188,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, 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; @@ -1161,7 +1198,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, 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; @@ -1336,9 +1374,7 @@ static int parse_output_paths(struct hda_codec *codec) 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); } @@ -1361,22 +1397,20 @@ static int create_multi_out_ctls(struct hda_codec *codec, 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 - cfg->line_outs].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")) { @@ -1406,12 +1440,13 @@ static int create_multi_out_ctls(struct hda_codec *codec, } 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 */ @@ -1429,7 +1464,7 @@ static int create_extra_out(struct hda_codec *codec, hda_nid_t pin, /* 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; @@ -1443,7 +1478,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins, 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++) { @@ -1453,14 +1488,16 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins, 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; @@ -1478,7 +1515,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins, 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); @@ -1501,6 +1538,7 @@ static int create_hp_out_ctls(struct hda_codec *codec) return create_extra_outs(codec, spec->autocfg.hp_outs, spec->autocfg.hp_pins, spec->multiout.hp_out_nid, + spec->hp_paths, "Headphone"); } @@ -1510,6 +1548,7 @@ static int create_speaker_out_ctls(struct hda_codec *codec) return create_extra_outs(codec, spec->autocfg.speaker_outs, spec->autocfg.speaker_pins, spec->multiout.extra_out_nid, + spec->speaker_paths, "Speaker"); } @@ -1615,13 +1654,21 @@ static int ch_mode_get(struct snd_kcontrol *kcontrol, 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; @@ -1775,8 +1822,8 @@ static void add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) #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; @@ -1792,6 +1839,7 @@ static int new_analog_input(struct hda_codec *codec, hda_nid_t pin, 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)) { @@ -1944,7 +1992,7 @@ static int create_input_ctls(struct hda_codec *codec) 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; @@ -2445,6 +2493,7 @@ static void parse_digital(struct hda_codec *codec) 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]; @@ -3575,12 +3624,12 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms); /* 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; snd_hda_activate_path(codec, path, path->active, true); @@ -3591,7 +3640,7 @@ static void set_output_and_unmute(struct hda_codec *codec, hda_nid_t pin, 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; @@ -3602,35 +3651,24 @@ static void init_multi_out(struct hda_codec *codec) 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]); } } @@ -3642,11 +3680,11 @@ static void init_extra_out(struct hda_codec *codec) 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 */ @@ -3658,7 +3696,7 @@ static void init_multi_io(struct hda_codec *codec) 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) @@ -3694,7 +3732,7 @@ static void init_analog_input(struct hda_codec *codec) /* 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); @@ -3746,7 +3784,8 @@ static void init_digital(struct hda_codec *codec) 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) diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index f1cae2e49377..71d409f5de87 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -130,6 +130,13 @@ struct hda_gen_spec { /* path list */ struct snd_array paths; + /* path indices */ + int out_paths[AUTO_CFG_MAX_OUTS]; + int hp_paths[AUTO_CFG_MAX_OUTS]; + int speaker_paths[AUTO_CFG_MAX_OUTS]; + int digout_paths[AUTO_CFG_MAX_OUTS]; + int loopback_paths[HDA_MAX_NUM_INPUTS]; + /* auto-mic stuff */ int am_num_entries; struct automic_entry am_entry[MAX_AUTO_MIC_PINS]; @@ -198,6 +205,8 @@ int snd_hda_gen_init(struct hda_codec *codec); struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid); +int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); +struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); enum { HDA_PARSE_NO_AAMIX,