Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 353203
b: refs/heads/master
c: 272f3ea
h: refs/heads/master
i:
  353201: cf105fd
  353199: b980c73
v: v3
  • Loading branch information
Takashi Iwai committed Jan 22, 2013
1 parent d1695bc commit ac5d768
Show file tree
Hide file tree
Showing 2 changed files with 262 additions and 6 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: dc870f38e9faf7dd89355aae2252126688a1a372
refs/heads/master: 272f3ea317762e55740326c01af64052a5fbb819
266 changes: 261 additions & 5 deletions trunk/sound/pci/hda/patch_analog.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
struct ad198x_spec {
struct hda_gen_spec gen;

/* for auto parser */
int smux_paths[4];
unsigned int cur_smux;

const struct snd_kcontrol_new *mixers[6];
int num_mixers;
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Expand Down Expand Up @@ -1519,13 +1523,94 @@ static const char * const ad1983_models[AD1983_MODELS] = {
[AD1983_BASIC] = "basic",
};

/*
* SPDIF mux control for AD1983 auto-parser
*/
static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;
static const char * const texts2[] = { "PCM", "ADC" };
static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
int num_conns = snd_hda_get_num_conns(codec, dig_out);

if (num_conns == 2)
return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
else if (num_conns == 3)
return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
else
return -EINVAL;
}

static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;

ucontrol->value.enumerated.item[0] = spec->cur_smux;
return 0;
}

static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;
unsigned int val = ucontrol->value.enumerated.item[0];
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
int num_conns = snd_hda_get_num_conns(codec, dig_out);

if (val >= num_conns)
return -EINVAL;
if (spec->cur_smux == val)
return 0;
spec->cur_smux = val;
snd_hda_codec_write_cache(codec, dig_out, 0,
AC_VERB_SET_CONNECT_SEL, val);
return 1;
}

static struct snd_kcontrol_new ad1983_auto_smux_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Source",
.info = ad1983_auto_smux_enum_info,
.get = ad1983_auto_smux_enum_get,
.put = ad1983_auto_smux_enum_put,
};

static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
int num_conns;

if (!dig_out)
return 0;
num_conns = snd_hda_get_num_conns(codec, dig_out);
if (num_conns != 2 && num_conns != 3)
return 0;
if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
return -ENOMEM;
return 0;
}

static int ad1983_parse_auto_config(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int err;

spec->beep_dev_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
return ad198x_parse_auto_config(codec);
err = ad198x_parse_auto_config(codec);
if (err < 0)
return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
return err;
return 0;
}

static int patch_ad1983(struct hda_codec *codec)
Expand Down Expand Up @@ -1950,11 +2035,18 @@ static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
static int ad1981_parse_auto_config(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int err;

spec->gen.mixer_nid = 0x0e;
spec->beep_dev_nid = 0x10;
set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
return ad198x_parse_auto_config(codec);
err = ad198x_parse_auto_config(codec);
if (err < 0)
return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
return err;
return 0;
}

static int patch_ad1981(struct hda_codec *codec)
Expand Down Expand Up @@ -2820,17 +2912,167 @@ static const struct hda_amp_list ad1988_loopbacks[] = {
};
#endif

static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
static const char * const texts[] = {
"PCM", "ADC1", "ADC2", "ADC3",
};
int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
if (num_conns > 4)
num_conns = 4;
return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
}

static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;

ucontrol->value.enumerated.item[0] = spec->cur_smux;
return 0;
}

static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ad198x_spec *spec = codec->spec;
unsigned int val = ucontrol->value.enumerated.item[0];
struct nid_path *path;
int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;

if (val >= num_conns)
return -EINVAL;
if (spec->cur_smux == val)
return 0;

mutex_lock(&codec->control_mutex);
codec->cached_write = 1;
path = snd_hda_get_path_from_idx(codec,
spec->smux_paths[spec->cur_smux]);
if (path)
snd_hda_activate_path(codec, path, false, true);
path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
if (path)
snd_hda_activate_path(codec, path, true, true);
spec->cur_smux = val;
codec->cached_write = 0;
mutex_unlock(&codec->control_mutex);
snd_hda_codec_flush_cache(codec); /* flush the updates */
return 1;
}

static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Source",
.info = ad1988_auto_smux_enum_info,
.get = ad1988_auto_smux_enum_get,
.put = ad1988_auto_smux_enum_put,
};

static int ad1988_auto_init(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int i, err;

err = snd_hda_gen_init(codec);
if (err < 0)
return err;
if (!spec->gen.autocfg.dig_outs)
return 0;

for (i = 0; i < 4; i++) {
struct nid_path *path;
path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
if (path)
snd_hda_activate_path(codec, path, path->active, false);
}

return 0;
}

static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int i, num_conns;
/* we create four static faked paths, since AD codecs have odd
* widget connections regarding the SPDIF out source
*/
static struct nid_path fake_paths[4] = {
{
.depth = 3,
.path = { 0x02, 0x1d, 0x1b },
.idx = { 0, 0, 0 },
.multi = { 0, 0, 0 },
},
{
.depth = 4,
.path = { 0x08, 0x0b, 0x1d, 0x1b },
.idx = { 0, 0, 1, 0 },
.multi = { 0, 1, 0, 0 },
},
{
.depth = 4,
.path = { 0x09, 0x0b, 0x1d, 0x1b },
.idx = { 0, 1, 1, 0 },
.multi = { 0, 1, 0, 0 },
},
{
.depth = 4,
.path = { 0x0f, 0x0b, 0x1d, 0x1b },
.idx = { 0, 2, 1, 0 },
.multi = { 0, 1, 0, 0 },
},
};

/* SPDIF source mux appears to be present only on AD1988A */
if (!spec->gen.autocfg.dig_outs ||
get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
return 0;

num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
if (num_conns != 3 && num_conns != 4)
return 0;

for (i = 0; i < num_conns; i++) {
struct nid_path *path = snd_array_new(&spec->gen.paths);
if (!path)
return -ENOMEM;
*path = fake_paths[i];
if (!i)
path->active = 1;
spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
}

if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
return -ENOMEM;

codec->patch_ops.init = ad1988_auto_init;

return 0;
}

/*
*/

static int ad1988_parse_auto_config(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int err;

spec->gen.mixer_nid = 0x20;
spec->beep_dev_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
return ad198x_parse_auto_config(codec);
err = ad198x_parse_auto_config(codec);
if (err < 0)
return err;
err = ad1988_add_spdif_mux_ctl(codec);
if (err < 0)
return err;
return 0;
}

/*
Expand Down Expand Up @@ -3174,11 +3416,18 @@ static const char * const ad1884_models[AD1884_MODELS] = {
static int ad1884_parse_auto_config(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int err;

spec->gen.mixer_nid = 0x20;
spec->beep_dev_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
return ad198x_parse_auto_config(codec);
err = ad198x_parse_auto_config(codec);
if (err < 0)
return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
return err;
return 0;
}

static int patch_ad1884_auto(struct hda_codec *codec)
Expand Down Expand Up @@ -4635,11 +4884,18 @@ static const char * const ad1882_models[AD1986A_MODELS] = {
static int ad1882_parse_auto_config(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int err;

spec->gen.mixer_nid = 0x20;
spec->beep_dev_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
return ad198x_parse_auto_config(codec);
err = ad198x_parse_auto_config(codec);
if (err < 0)
return err;
err = ad1988_add_spdif_mux_ctl(codec);
if (err < 0)
return err;
return 0;
}

static int patch_ad1882(struct hda_codec *codec)
Expand Down

0 comments on commit ac5d768

Please sign in to comment.