From 7c7767ebe2fa847c91a0dd5551ca422aba359473 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2009 15:28:38 +0100 Subject: ALSA: hda - Halve too large volume scales for STAC/IDT codecs Patch-mainline: References: bnc#466428 STAC/IDT codecs have often too large volume scales such as -96dB, and exposing this as is results in too large scale in percentage representation. This patch adds the check of the volume scale and halves the volume range if it's too large automatically. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -155,6 +155,7 @@ struct sigmatel_spec { unsigned int alt_switch: 1; unsigned int hp_detect: 1; unsigned int spdif_mute: 1; + unsigned int check_volume_offset:1; /* gpio lines */ unsigned int eapd_mask; @@ -183,6 +184,8 @@ struct sigmatel_spec { struct hda_multi_out multiout; hda_nid_t dac_nids[5]; + int volume_offset; + /* capture */ hda_nid_t *adc_nids; unsigned int num_adcs; @@ -1310,6 +1313,8 @@ static int stac92xx_build_controls(struc unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], HDA_OUTPUT, vmaster_tlv); + /* correct volume offset */ + vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; err = snd_hda_add_vmaster(codec, "Master Playback Volume", vmaster_tlv, slave_vols); if (err < 0) @@ -2885,14 +2890,34 @@ static int stac92xx_auto_fill_dac_nids(s } /* create volume control/switch for the given prefx type */ -static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) +static int create_controls(struct hda_codec *codec, const char *pfx, + hda_nid_t nid, int chs) { + struct sigmatel_spec *spec = codec->spec; char name[32]; int err; + if (!spec->check_volume_offset) { + unsigned int caps, step, nums, db_scale; + caps = query_amp_caps(codec, nid, HDA_OUTPUT); + step = (caps & AC_AMPCAP_STEP_SIZE) >> + AC_AMPCAP_STEP_SIZE_SHIFT; + step = (step + 1) * 25; /* in .01dB unit */ + nums = (caps & AC_AMPCAP_NUM_STEPS) >> + AC_AMPCAP_NUM_STEPS_SHIFT; + db_scale = nums * step; + /* if dB scale is over -64dB, and finer enough, + * let's reduce it to half + */ + if (db_scale > 6400 && nums >= 0x1f) + spec->volume_offset = nums / 2; + spec->check_volume_offset = 1; + } + sprintf(name, "%s Playback Volume", pfx); err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, + spec->volume_offset)); if (err < 0) return err; sprintf(name, "%s Playback Switch", pfx); @@ -2948,10 +2973,10 @@ static int stac92xx_auto_create_multi_ou if (i == 2) { /* Center/LFE */ - err = create_controls(spec, "Center", nid, 1); + err = create_controls(codec, "Center", nid, 1); if (err < 0) return err; - err = create_controls(spec, "LFE", nid, 2); + err = create_controls(codec, "LFE", nid, 2); if (err < 0) return err; @@ -2967,7 +2992,7 @@ static int stac92xx_auto_create_multi_ou } } else { - err = create_controls(spec, chname[i], nid, 3); + err = create_controls(codec, chname[i], nid, 3); if (err < 0) return err; } @@ -3074,13 +3099,13 @@ static int stac92xx_auto_create_hp_ctls( static const char *pfxs[] = { "Speaker", "External Speaker", "Speaker2", }; - err = create_controls(spec, pfxs[i - old_num_dacs], + err = create_controls(codec, pfxs[i - old_num_dacs], spec->multiout.dac_nids[i], 3); if (err < 0) return err; } if (spec->multiout.hp_nid) { - err = create_controls(spec, "Headphone", + err = create_controls(codec, "Headphone", spec->multiout.hp_nid, 3); if (err < 0) return err; @@ -3670,7 +3695,7 @@ static int stac9200_auto_create_lfe_ctls } if (lfe_pin) { - err = create_controls(spec, "LFE", lfe_pin, 1); + err = create_controls(codec, "LFE", lfe_pin, 1); if (err < 0) return err; }