]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 7c7767ebe2fa847c91a0dd5551ca422aba359473 Mon Sep 17 00:00:00 2001 |
2 | From: Takashi Iwai <tiwai@suse.de> | |
3 | Date: Tue, 20 Jan 2009 15:28:38 +0100 | |
4 | Subject: ALSA: hda - Halve too large volume scales for STAC/IDT codecs | |
5 | Patch-mainline: | |
6 | References: bnc#466428 | |
7 | ||
8 | STAC/IDT codecs have often too large volume scales such as -96dB, | |
9 | and exposing this as is results in too large scale in percentage | |
10 | representation. | |
11 | ||
12 | This patch adds the check of the volume scale and halves the | |
13 | volume range if it's too large automatically. | |
14 | ||
15 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
16 | ||
17 | --- | |
18 | sound/pci/hda/patch_sigmatel.c | 41 +++++++++++++++++++++++++++++++++-------- | |
19 | 1 file changed, 33 insertions(+), 8 deletions(-) | |
20 | ||
21 | --- a/sound/pci/hda/patch_sigmatel.c | |
22 | +++ b/sound/pci/hda/patch_sigmatel.c | |
23 | @@ -155,6 +155,7 @@ struct sigmatel_spec { | |
24 | unsigned int alt_switch: 1; | |
25 | unsigned int hp_detect: 1; | |
26 | unsigned int spdif_mute: 1; | |
27 | + unsigned int check_volume_offset:1; | |
28 | ||
29 | /* gpio lines */ | |
30 | unsigned int eapd_mask; | |
31 | @@ -183,6 +184,8 @@ struct sigmatel_spec { | |
32 | struct hda_multi_out multiout; | |
33 | hda_nid_t dac_nids[5]; | |
34 | ||
35 | + int volume_offset; | |
36 | + | |
37 | /* capture */ | |
38 | hda_nid_t *adc_nids; | |
39 | unsigned int num_adcs; | |
40 | @@ -1310,6 +1313,8 @@ static int stac92xx_build_controls(struc | |
41 | unsigned int vmaster_tlv[4]; | |
42 | snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], | |
43 | HDA_OUTPUT, vmaster_tlv); | |
44 | + /* correct volume offset */ | |
45 | + vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; | |
46 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | |
47 | vmaster_tlv, slave_vols); | |
48 | if (err < 0) | |
49 | @@ -2885,14 +2890,34 @@ static int stac92xx_auto_fill_dac_nids(s | |
50 | } | |
51 | ||
52 | /* create volume control/switch for the given prefx type */ | |
53 | -static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) | |
54 | +static int create_controls(struct hda_codec *codec, const char *pfx, | |
55 | + hda_nid_t nid, int chs) | |
56 | { | |
57 | + struct sigmatel_spec *spec = codec->spec; | |
58 | char name[32]; | |
59 | int err; | |
60 | ||
61 | + if (!spec->check_volume_offset) { | |
62 | + unsigned int caps, step, nums, db_scale; | |
63 | + caps = query_amp_caps(codec, nid, HDA_OUTPUT); | |
64 | + step = (caps & AC_AMPCAP_STEP_SIZE) >> | |
65 | + AC_AMPCAP_STEP_SIZE_SHIFT; | |
66 | + step = (step + 1) * 25; /* in .01dB unit */ | |
67 | + nums = (caps & AC_AMPCAP_NUM_STEPS) >> | |
68 | + AC_AMPCAP_NUM_STEPS_SHIFT; | |
69 | + db_scale = nums * step; | |
70 | + /* if dB scale is over -64dB, and finer enough, | |
71 | + * let's reduce it to half | |
72 | + */ | |
73 | + if (db_scale > 6400 && nums >= 0x1f) | |
74 | + spec->volume_offset = nums / 2; | |
75 | + spec->check_volume_offset = 1; | |
76 | + } | |
77 | + | |
78 | sprintf(name, "%s Playback Volume", pfx); | |
79 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | |
80 | - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | |
81 | + HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, | |
82 | + spec->volume_offset)); | |
83 | if (err < 0) | |
84 | return err; | |
85 | sprintf(name, "%s Playback Switch", pfx); | |
86 | @@ -2948,10 +2973,10 @@ static int stac92xx_auto_create_multi_ou | |
87 | ||
88 | if (i == 2) { | |
89 | /* Center/LFE */ | |
90 | - err = create_controls(spec, "Center", nid, 1); | |
91 | + err = create_controls(codec, "Center", nid, 1); | |
92 | if (err < 0) | |
93 | return err; | |
94 | - err = create_controls(spec, "LFE", nid, 2); | |
95 | + err = create_controls(codec, "LFE", nid, 2); | |
96 | if (err < 0) | |
97 | return err; | |
98 | ||
99 | @@ -2967,7 +2992,7 @@ static int stac92xx_auto_create_multi_ou | |
100 | } | |
101 | ||
102 | } else { | |
103 | - err = create_controls(spec, chname[i], nid, 3); | |
104 | + err = create_controls(codec, chname[i], nid, 3); | |
105 | if (err < 0) | |
106 | return err; | |
107 | } | |
108 | @@ -3074,13 +3099,13 @@ static int stac92xx_auto_create_hp_ctls( | |
109 | static const char *pfxs[] = { | |
110 | "Speaker", "External Speaker", "Speaker2", | |
111 | }; | |
112 | - err = create_controls(spec, pfxs[i - old_num_dacs], | |
113 | + err = create_controls(codec, pfxs[i - old_num_dacs], | |
114 | spec->multiout.dac_nids[i], 3); | |
115 | if (err < 0) | |
116 | return err; | |
117 | } | |
118 | if (spec->multiout.hp_nid) { | |
119 | - err = create_controls(spec, "Headphone", | |
120 | + err = create_controls(codec, "Headphone", | |
121 | spec->multiout.hp_nid, 3); | |
122 | if (err < 0) | |
123 | return err; | |
124 | @@ -3670,7 +3695,7 @@ static int stac9200_auto_create_lfe_ctls | |
125 | } | |
126 | ||
127 | if (lfe_pin) { | |
128 | - err = create_controls(spec, "LFE", lfe_pin, 1); | |
129 | + err = create_controls(codec, "LFE", lfe_pin, 1); | |
130 | if (err < 0) | |
131 | return err; | |
132 | } |