aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-03-09 11:51:10 -0500
committerTakashi Iwai <tiwai@suse.de>2012-03-09 11:55:30 -0500
commit18478e8b626edc2d181dcb1b93e1f99ad72095e9 (patch)
tree572587c5e3ce39669e4dff26b165e93ba3181946 /sound/pci
parent785f857d1cb0856b612b46a0545b74aa2596e44a (diff)
ALSA: hda - Initialize vmaster slave volumes
When the driver is changed to use vmaster or a new slave element is added by the improvement of the parser code, user may face often the silent output because of the muted slave mixer although Master volume is properly set. And they complain. And I get upset. Although such a mixer element should be initialized via "alsactl init", it'd be more user-friendly if the known output slaves are unmuted and set to 0dB so that user can control the volume only with Master as default. Since Master is still set muted as default even with this change, no risk of the speaker blow up, too. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c65
-rw-r--r--sound/pci/hda/hda_local.h6
-rw-r--r--sound/pci/hda/patch_analog.c8
3 files changed, 72 insertions, 7 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 0527ae1ab96e..0c0ac0e1d504 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -19,6 +19,7 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22#include <linux/mm.h>
22#include <linux/init.h> 23#include <linux/init.h>
23#include <linux/delay.h> 24#include <linux/delay.h>
24#include <linux/slab.h> 25#include <linux/slab.h>
@@ -2340,6 +2341,56 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
2340 return 1; 2341 return 1;
2341} 2342}
2342 2343
2344/* guess the value corresponding to 0dB */
2345static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
2346{
2347 int _tlv[4];
2348 const int *tlv = NULL;
2349 int val = -1;
2350
2351 if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
2352 /* FIXME: set_fs() hack for obtaining user-space TLV data */
2353 mm_segment_t fs = get_fs();
2354 set_fs(get_ds());
2355 if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv))
2356 tlv = _tlv;
2357 set_fs(fs);
2358 } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
2359 tlv = kctl->tlv.p;
2360 if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE)
2361 val = -tlv[2] / tlv[3];
2362 return val;
2363}
2364
2365/* call kctl->put with the given value(s) */
2366static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
2367{
2368 struct snd_ctl_elem_value *ucontrol;
2369 ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
2370 if (!ucontrol)
2371 return -ENOMEM;
2372 ucontrol->value.integer.value[0] = val;
2373 ucontrol->value.integer.value[1] = val;
2374 kctl->put(kctl, ucontrol);
2375 kfree(ucontrol);
2376 return 0;
2377}
2378
2379/* initialize the slave volume with 0dB */
2380static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
2381{
2382 int offset = get_kctl_0dB_offset(slave);
2383 if (offset > 0)
2384 put_kctl_with_value(slave, offset);
2385 return 0;
2386}
2387
2388/* unmute the slave */
2389static int init_slave_unmute(void *data, struct snd_kcontrol *slave)
2390{
2391 return put_kctl_with_value(slave, 1);
2392}
2393
2343/** 2394/**
2344 * snd_hda_add_vmaster - create a virtual master control and add slaves 2395 * snd_hda_add_vmaster - create a virtual master control and add slaves
2345 * @codec: HD-audio codec 2396 * @codec: HD-audio codec
@@ -2347,6 +2398,7 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
2347 * @tlv: TLV data (optional) 2398 * @tlv: TLV data (optional)
2348 * @slaves: slave control names (optional) 2399 * @slaves: slave control names (optional)
2349 * @suffix: suffix string to each slave name (optional) 2400 * @suffix: suffix string to each slave name (optional)
2401 * @init_slave_vol: initialize slaves to unmute/0dB
2350 * 2402 *
2351 * Create a virtual master control with the given name. The TLV data 2403 * Create a virtual master control with the given name. The TLV data
2352 * must be either NULL or a valid data. 2404 * must be either NULL or a valid data.
@@ -2357,9 +2409,9 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
2357 * 2409 *
2358 * This function returns zero if successful or a negative error code. 2410 * This function returns zero if successful or a negative error code.
2359 */ 2411 */
2360int snd_hda_add_vmaster(struct hda_codec *codec, char *name, 2412int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
2361 unsigned int *tlv, const char * const *slaves, 2413 unsigned int *tlv, const char * const *slaves,
2362 const char *suffix) 2414 const char *suffix, bool init_slave_vol)
2363{ 2415{
2364 struct snd_kcontrol *kctl; 2416 struct snd_kcontrol *kctl;
2365 int err; 2417 int err;
@@ -2380,9 +2432,16 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
2380 (map_slave_func_t)snd_ctl_add_slave, kctl); 2432 (map_slave_func_t)snd_ctl_add_slave, kctl);
2381 if (err < 0) 2433 if (err < 0)
2382 return err; 2434 return err;
2435
2436 /* init with master mute & zero volume */
2437 put_kctl_with_value(kctl, 0);
2438 if (init_slave_vol)
2439 map_slaves(codec, slaves, suffix,
2440 tlv ? init_slave_0dB : init_slave_unmute, kctl);
2441
2383 return 0; 2442 return 0;
2384} 2443}
2385EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); 2444EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);
2386 2445
2387/** 2446/**
2388 * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch 2447 * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 6094dea82bc3..caa64686267b 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -139,9 +139,11 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
139 unsigned int *tlv); 139 unsigned int *tlv);
140struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, 140struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
141 const char *name); 141 const char *name);
142int snd_hda_add_vmaster(struct hda_codec *codec, char *name, 142int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
143 unsigned int *tlv, const char * const *slaves, 143 unsigned int *tlv, const char * const *slaves,
144 const char *suffix); 144 const char *suffix, bool init_slave_vol);
145#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
146 __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true)
145int snd_hda_codec_reset(struct hda_codec *codec); 147int snd_hda_codec_reset(struct hda_codec *codec);
146 148
147/* amp value bits */ 149/* amp value bits */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 9771b0702455..fa97a0c5ced0 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -82,6 +82,7 @@ struct ad198x_spec {
82 unsigned int inv_jack_detect: 1;/* inverted jack-detection */ 82 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
83 unsigned int inv_eapd: 1; /* inverted EAPD implementation */ 83 unsigned int inv_eapd: 1; /* inverted EAPD implementation */
84 unsigned int analog_beep: 1; /* analog beep input present */ 84 unsigned int analog_beep: 1; /* analog beep input present */
85 unsigned int avoid_init_slave_vol:1;
85 86
86#ifdef CONFIG_SND_HDA_POWER_SAVE 87#ifdef CONFIG_SND_HDA_POWER_SAVE
87 struct hda_loopback_check loopback; 88 struct hda_loopback_check loopback;
@@ -223,11 +224,12 @@ static int ad198x_build_controls(struct hda_codec *codec)
223 unsigned int vmaster_tlv[4]; 224 unsigned int vmaster_tlv[4];
224 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 225 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
225 HDA_OUTPUT, vmaster_tlv); 226 HDA_OUTPUT, vmaster_tlv);
226 err = snd_hda_add_vmaster(codec, "Master Playback Volume", 227 err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
227 vmaster_tlv, 228 vmaster_tlv,
228 (spec->slave_vols ? 229 (spec->slave_vols ?
229 spec->slave_vols : ad_slave_pfxs), 230 spec->slave_vols : ad_slave_pfxs),
230 "Playback Volume"); 231 "Playback Volume",
232 !spec->avoid_init_slave_vol);
231 if (err < 0) 233 if (err < 0)
232 return err; 234 return err;
233 } 235 }
@@ -3604,6 +3606,8 @@ static int patch_ad1884(struct hda_codec *codec)
3604 spec->vmaster_nid = 0x04; 3606 spec->vmaster_nid = 0x04;
3605 /* we need to cover all playback volumes */ 3607 /* we need to cover all playback volumes */
3606 spec->slave_vols = ad1884_slave_vols; 3608 spec->slave_vols = ad1884_slave_vols;
3609 /* slaves may contain input volumes, so we can't raise to 0dB blindly */
3610 spec->avoid_init_slave_vol = 1;
3607 3611
3608 codec->patch_ops = ad198x_patch_ops; 3612 codec->patch_ops = ad198x_patch_ops;
3609 3613