summaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-18 11:07:15 +0100
committerTakashi Iwai <tiwai@suse.de>2013-01-18 11:07:15 +0100
commit6f7c83afc6cc3f66d13e4ad0a0f5693d9175e1ab (patch)
tree7b3e620e0069a1e00890841287ffde18331948c8 /sound/pci
parent8999bf0af035ecbea039914a5af2f23f5a621d62 (diff)
ALSA: hda - Look for boost controls more deeply
In the current generic parser code, we look for the (mic) boost controls only on input pins. But many codecs assign the boost volume to a widget connected to each input pin instead of the input amp of the pin itself. In this patch, the parser tries to look through more widgets connected to the pin and find a boost amp. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_generic.c101
1 files changed, 77 insertions, 24 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index edec98f1a9a5..cadfe65e2fe1 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -3056,39 +3056,92 @@ static int create_capture_mixers(struct hda_codec *codec)
/*
* add mic boosts if needed
*/
+
+/* check whether the given amp is feasible as a boost volume */
+static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
+ int dir, int idx)
+{
+ unsigned int step;
+
+ if (!nid_has_volume(codec, nid, dir) ||
+ is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+ is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+ return false;
+
+ step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
+ >> AC_AMPCAP_STEP_SIZE_SHIFT;
+ if (step < 0x20)
+ return false;
+ return true;
+}
+
+/* look for a boost amp in a widget close to the pin */
+static unsigned int look_for_boost_amp(struct hda_codec *codec,
+ struct nid_path *path)
+{
+ unsigned int val = 0;
+ hda_nid_t nid;
+ int depth;
+
+ for (depth = 0; depth < 3; depth++) {
+ if (depth >= path->depth - 1)
+ break;
+ nid = path->path[depth];
+ if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
+ val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+ break;
+ } else if (check_boost_vol(codec, nid, HDA_INPUT,
+ path->idx[depth])) {
+ val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
+ HDA_INPUT);
+ break;
+ }
+ }
+
+ return val;
+}
+
static int parse_mic_boost(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct hda_input_mux *imux = &spec->input_mux;
int i, err;
- hda_nid_t nid;
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].type > AUTO_PIN_MIC)
- break;
- nid = cfg->inputs[i].pin;
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
- char boost_label[44];
- struct nid_path *path;
- unsigned int val;
+ if (!spec->num_adc_nids)
+ return 0;
- if (!nid_has_volume(codec, nid, HDA_INPUT))
- continue;
+ for (i = 0; i < imux->num_items; i++) {
+ struct nid_path *path;
+ unsigned int val;
+ int idx;
+ char boost_label[44];
- snprintf(boost_label, sizeof(boost_label),
- "%s Boost Volume",
- spec->input_labels[i]);
- val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
- err = add_control(spec, HDA_CTL_WIDGET_VOL,
- boost_label,
- spec->input_label_idxs[i], val);
- if (err < 0)
- return err;
+ idx = imux->items[i].index;
+ if (idx >= imux->num_items)
+ continue;
- path = snd_hda_get_nid_path(codec, nid, 0);
- if (path)
- path->ctls[NID_PATH_BOOST_CTL] = val;
- }
+ /* check only line-in and mic pins */
+ if (cfg->inputs[idx].type > AUTO_PIN_MIC)
+ continue;
+
+ path = get_input_path(codec, 0, i);
+ if (!path)
+ continue;
+
+ val = look_for_boost_amp(codec, path);
+ if (!val)
+ continue;
+
+ /* create a boost control */
+ snprintf(boost_label, sizeof(boost_label),
+ "%s Boost Volume", spec->input_labels[idx]);
+ err = add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
+ spec->input_label_idxs[idx], val);
+ if (err < 0)
+ return err;
+
+ path->ctls[NID_PATH_BOOST_CTL] = val;
}
return 0;
}