summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_generic.c139
-rw-r--r--sound/pci/hda/hda_generic.h9
2 files changed, 98 insertions, 50 deletions
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,