Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 293117
b: refs/heads/master
c: 18478e8
h: refs/heads/master
i:
  293115: 5a696da
v: v3
  • Loading branch information
Takashi Iwai committed Mar 9, 2012
1 parent 1b00cc2 commit a0f53e7
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 785f857d1cb0856b612b46a0545b74aa2596e44a
refs/heads/master: 18478e8b626edc2d181dcb1b93e1f99ad72095e9
65 changes: 62 additions & 3 deletions trunk/sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -2340,13 +2341,64 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
return 1;
}

/* guess the value corresponding to 0dB */
static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
{
int _tlv[4];
const int *tlv = NULL;
int val = -1;

if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
/* FIXME: set_fs() hack for obtaining user-space TLV data */
mm_segment_t fs = get_fs();
set_fs(get_ds());
if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv))
tlv = _tlv;
set_fs(fs);
} else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
tlv = kctl->tlv.p;
if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE)
val = -tlv[2] / tlv[3];
return val;
}

/* call kctl->put with the given value(s) */
static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
{
struct snd_ctl_elem_value *ucontrol;
ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
if (!ucontrol)
return -ENOMEM;
ucontrol->value.integer.value[0] = val;
ucontrol->value.integer.value[1] = val;
kctl->put(kctl, ucontrol);
kfree(ucontrol);
return 0;
}

/* initialize the slave volume with 0dB */
static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
{
int offset = get_kctl_0dB_offset(slave);
if (offset > 0)
put_kctl_with_value(slave, offset);
return 0;
}

/* unmute the slave */
static int init_slave_unmute(void *data, struct snd_kcontrol *slave)
{
return put_kctl_with_value(slave, 1);
}

/**
* snd_hda_add_vmaster - create a virtual master control and add slaves
* @codec: HD-audio codec
* @name: vmaster control name
* @tlv: TLV data (optional)
* @slaves: slave control names (optional)
* @suffix: suffix string to each slave name (optional)
* @init_slave_vol: initialize slaves to unmute/0dB
*
* Create a virtual master control with the given name. The TLV data
* must be either NULL or a valid data.
Expand All @@ -2357,9 +2409,9 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
*
* This function returns zero if successful or a negative error code.
*/
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves,
const char *suffix)
const char *suffix, bool init_slave_vol)
{
struct snd_kcontrol *kctl;
int err;
Expand All @@ -2380,9 +2432,16 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
(map_slave_func_t)snd_ctl_add_slave, kctl);
if (err < 0)
return err;

/* init with master mute & zero volume */
put_kctl_with_value(kctl, 0);
if (init_slave_vol)
map_slaves(codec, slaves, suffix,
tlv ? init_slave_0dB : init_slave_unmute, kctl);

return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);

/**
* snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
Expand Down
6 changes: 4 additions & 2 deletions trunk/sound/pci/hda/hda_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int *tlv);
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves,
const char *suffix);
const char *suffix, bool init_slave_vol);
#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
__snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true)
int snd_hda_codec_reset(struct hda_codec *codec);

/* amp value bits */
Expand Down
8 changes: 6 additions & 2 deletions trunk/sound/pci/hda/patch_analog.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct ad198x_spec {
unsigned int inv_jack_detect: 1;/* inverted jack-detection */
unsigned int inv_eapd: 1; /* inverted EAPD implementation */
unsigned int analog_beep: 1; /* analog beep input present */
unsigned int avoid_init_slave_vol:1;

#ifdef CONFIG_SND_HDA_POWER_SAVE
struct hda_loopback_check loopback;
Expand Down Expand Up @@ -223,11 +224,12 @@ static int ad198x_build_controls(struct hda_codec *codec)
unsigned int vmaster_tlv[4];
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
HDA_OUTPUT, vmaster_tlv);
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv,
(spec->slave_vols ?
spec->slave_vols : ad_slave_pfxs),
"Playback Volume");
"Playback Volume",
!spec->avoid_init_slave_vol);
if (err < 0)
return err;
}
Expand Down Expand Up @@ -3604,6 +3606,8 @@ static int patch_ad1884(struct hda_codec *codec)
spec->vmaster_nid = 0x04;
/* we need to cover all playback volumes */
spec->slave_vols = ad1884_slave_vols;
/* slaves may contain input volumes, so we can't raise to 0dB blindly */
spec->avoid_init_slave_vol = 1;

codec->patch_ops = ad198x_patch_ops;

Expand Down

0 comments on commit a0f53e7

Please sign in to comment.