summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-12-15 10:45:10 +0100
committerTakashi Iwai <tiwai@suse.de>2009-12-15 10:45:10 +0100
commit709350506567029021b8a38ee7e65bc246fceabc (patch)
tree94e3865d62b9b964e2272d0844629ec88808cb42
parentMerge branch 'fix/hda' into for-linus (diff)
parentALSA: hda - simplify usage of HDA_SUBDEV_AMP_FLAG (diff)
downloadlinux-709350506567029021b8a38ee7e65bc246fceabc.tar.xz
linux-709350506567029021b8a38ee7e65bc246fceabc.zip
Merge remote branch 'alsa/devel' into topic/hda
-rw-r--r--sound/pci/hda/hda_codec.c79
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_generic.c3
-rw-r--r--sound/pci/hda/hda_local.h16
-rw-r--r--sound/pci/hda/hda_proc.c31
-rw-r--r--sound/pci/hda/patch_analog.c37
-rw-r--r--sound/pci/hda/patch_cirrus.c10
-rw-r--r--sound/pci/hda/patch_cmedia.c12
-rw-r--r--sound/pci/hda/patch_conexant.c1
-rw-r--r--sound/pci/hda/patch_realtek.c125
-rw-r--r--sound/pci/hda/patch_si3054.c1
-rw-r--r--sound/pci/hda/patch_sigmatel.c7
-rw-r--r--sound/pci/hda/patch_via.c275
13 files changed, 455 insertions, 143 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 9cfdb771928c..c848ec0f085e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
#endif
list_del(&codec->list);
snd_array_free(&codec->mixers);
+ snd_array_free(&codec->nids);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
@@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
mutex_init(&codec->control_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
- snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
+ snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
+ snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
if (codec->bus->modelname) {
@@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
/**
- * snd_hda_ctl-add - Add a control element and assign to the codec
+ * snd_hda_ctl_add - Add a control element and assign to the codec
* @codec: HD-audio codec
* @nid: corresponding NID (optional)
* @kctl: the control element to assign
@@ -1721,19 +1723,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
*
* snd_hda_ctl_add() checks the control subdev id field whether
* #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower
- * bits value is taken as the NID to assign.
+ * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
+ * specifies if kctl->private_value is a HDA amplifier value.
*/
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl)
{
int err;
+ unsigned short flags = 0;
struct hda_nid_item *item;
- if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
+ if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
+ flags |= HDA_NID_ITEM_AMP;
if (nid == 0)
- nid = kctl->id.subdevice & 0xffff;
- kctl->id.subdevice = 0;
+ nid = get_amp_nid_(kctl->private_value);
}
+ if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
+ nid = kctl->id.subdevice & 0xffff;
+ if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
+ kctl->id.subdevice = 0;
err = snd_ctl_add(codec->bus->card, kctl);
if (err < 0)
return err;
@@ -1742,11 +1750,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
return -ENOMEM;
item->kctl = kctl;
item->nid = nid;
+ item->flags = flags;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
/**
+ * snd_hda_add_nid - Assign a NID to a control element
+ * @codec: HD-audio codec
+ * @nid: corresponding NID (optional)
+ * @kctl: the control element to assign
+ * @index: index to kctl
+ *
+ * Add the given control element to an array inside the codec instance.
+ * This function is used when #snd_hda_ctl_add cannot be used for 1:1
+ * NID:KCTL mapping - for example "Capture Source" selector.
+ */
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t nid)
+{
+ struct hda_nid_item *item;
+
+ if (nid > 0) {
+ item = snd_array_new(&codec->nids);
+ if (!item)
+ return -ENOMEM;
+ item->kctl = kctl;
+ item->index = index;
+ item->nid = nid;
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nid);
+
+/**
* snd_hda_ctls_clear - Clear all controls assigned to the given codec
* @codec: HD-audio codec
*/
@@ -1757,6 +1795,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->bus->card, items[i].kctl);
snd_array_free(&codec->mixers);
+ snd_array_free(&codec->nids);
}
/* pseudo device locking
@@ -3476,6 +3515,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
+ if (knew->iface == -1) /* skip this codec private value */
+ continue;
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
@@ -3496,6 +3537,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
}
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
+/**
+ * snd_hda_add_nids - assign nids to controls from the array
+ * @codec: the HDA codec
+ * @kctl: struct snd_kcontrol
+ * @index: index to kctl
+ * @nids: the array of hda_nid_t
+ * @size: count of hda_nid_t items
+ *
+ * This helper function assigns NIDs in the given array to a control element.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t *nids, unsigned int size)
+{
+ int err;
+
+ for ( ; size > 0; size--, nids++) {
+ err = snd_hda_add_nid(codec, kctl, index, *nids);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nids);
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1d541b7f5547..0d08ad5bd898 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -789,6 +789,7 @@ struct hda_codec {
u32 *wcaps;
struct snd_array mixers; /* list of assigned mixer elements */
+ struct snd_array nids; /* list of mapped mixer elements */
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 092c6a7c2ff3..5ea21285ee1f 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
}
/* create input MUX if multiple sources are available */
- err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
+ err = snd_hda_ctl_add(codec, spec->adc_node->nid,
+ snd_ctl_new1(&cap_sel, codec));
if (err < 0)
return err;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5778ae882b83..d505d052972e 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -31,6 +31,7 @@
* in snd_hda_ctl_add(), so that this value won't appear in the outside.
*/
#define HDA_SUBDEV_NID_FLAG (1U << 31)
+#define HDA_SUBDEV_AMP_FLAG (1U << 30)
/*
* for mixer controls
@@ -42,7 +43,7 @@
/* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -63,7 +64,7 @@
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.info = snd_hda_mixer_amp_switch_info, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put, \
@@ -81,7 +82,7 @@
/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.info = snd_hda_mixer_amp_switch_info, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put_beep, \
@@ -342,6 +343,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew);
+int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t *nids, unsigned int size);
/*
* unsolicited event handler
@@ -464,13 +467,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
+/* flags for hda_nid_item */
+#define HDA_NID_ITEM_AMP (1<<0)
+
struct hda_nid_item {
struct snd_kcontrol *kctl;
+ unsigned int index;
hda_nid_t nid;
+ unsigned short flags;
};
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl);
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t nid);
void snd_hda_ctls_clear(struct hda_codec *codec);
/*
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c9afc04adac8..f97d35de66c4 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value)
return "UNKNOWN Widget";
}
-static void print_nid_mixers(struct snd_info_buffer *buffer,
- struct hda_codec *codec, hda_nid_t nid)
+static void print_nid_array(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid,
+ struct snd_array *array)
{
int i;
- struct hda_nid_item *items = codec->mixers.list;
+ struct hda_nid_item *items = array->list, *item;
struct snd_kcontrol *kctl;
- for (i = 0; i < codec->mixers.used; i++) {
- if (items[i].nid == nid) {
- kctl = items[i].kctl;
+ for (i = 0; i < array->used; i++) {
+ item = &items[i];
+ if (item->nid == nid) {
+ kctl = item->kctl;
snd_iprintf(buffer,
" Control: name=\"%s\", index=%i, device=%i\n",
- kctl->id.name, kctl->id.index, kctl->id.device);
+ kctl->id.name, kctl->id.index + item->index,
+ kctl->id.device);
+ if (item->flags & HDA_NID_ITEM_AMP)
+ snd_iprintf(buffer,
+ " ControlAmp: chs=%lu, dir=%s, "
+ "idx=%lu, ofs=%lu\n",
+ get_amp_channels(kctl),
+ get_amp_direction(kctl) ? "Out" : "In",
+ get_amp_index(kctl),
+ get_amp_offset(kctl));
}
}
}
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
(data & (1<<i)) ? 1 : 0,
(unsol & (1<<i)) ? 1 : 0);
/* FIXME: add GPO and GPI pin information */
- print_nid_mixers(buffer, codec, nid);
+ print_nid_array(buffer, codec, nid, &codec->mixers);
+ print_nid_array(buffer, codec, nid, &codec->nids);
}
static void print_codec_info(struct snd_info_entry *entry,
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_iprintf(buffer, " CP");
snd_iprintf(buffer, "\n");
- print_nid_mixers(buffer, codec, nid);
+ print_nid_array(buffer, codec, nid, &codec->mixers);
+ print_nid_array(buffer, codec, nid, &codec->nids);
print_nid_pcms(buffer, codec, nid);
/* volume knob is a special widget that always have connection
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 1a36137e13ec..92b72d4f3984 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
static int ad198x_build_controls(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
+ struct snd_kcontrol *kctl;
unsigned int i;
int err;
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
if (!kctl)
return -ENOMEM;
kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec,
- get_amp_nid_(spec->beep_amp),
- kctl);
+ err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;
}
@@ -239,6 +238,28 @@ static int ad198x_build_controls(struct hda_codec *codec)
}
ad198x_free_kctls(codec); /* no longer needed */
+
+ /* assign Capture Source enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+ if (!kctl)
+ kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
+ spec->input_mux->num_items);
+ if (err < 0)
+ return err;
+ }
+
+ /* assign IEC958 enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec,
+ SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
+ if (kctl) {
+ err = snd_hda_add_nid(codec, kctl, 0,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+
return 0;
}
@@ -701,6 +722,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
.put = ad198x_eapd_put,
@@ -808,6 +830,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1986a_hp_master_sw_put,
@@ -1608,6 +1631,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
.name = "Master Playback Switch",
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
@@ -2129,6 +2153,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
.put = ad198x_eapd_put,
@@ -2250,6 +2275,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Source",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad1988_spdif_playback_source_info,
.get = ad1988_spdif_playback_source_get,
.put = ad1988_spdif_playback_source_put,
@@ -2582,7 +2608,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
if (! knew->name)
return -ENOMEM;
if (get_amp_nid_(val))
- knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+ knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
return 0;
}
@@ -3736,6 +3762,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put,
@@ -3764,6 +3791,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put,
@@ -4105,6 +4133,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.name = "Master Playback Switch",
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 4b200da1bd18..eeb91f6a06c2 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -500,7 +500,8 @@ static int add_mute(struct hda_codec *codec, const char *name, int index,
knew.private_value = pval;
snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]);
*kctlp = snd_ctl_new1(&knew, codec);
- return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
+ (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+ return snd_hda_ctl_add(codec, 0, *kctlp);
}
static int add_volume(struct hda_codec *codec, const char *name,
@@ -513,7 +514,8 @@ static int add_volume(struct hda_codec *codec, const char *name,
knew.private_value = pval;
snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]);
*kctlp = snd_ctl_new1(&knew, codec);
- return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
+ (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+ return snd_hda_ctl_add(codec, 0, *kctlp);
}
static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
@@ -759,6 +761,10 @@ static int build_input(struct hda_codec *codec)
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;
+ err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid,
+ spec->num_inputs);
+ if (err < 0)
+ return err;
}
if (spec->num_inputs > 1 && !spec->mic_detect) {
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index a45c1169762b..cc1c22370a60 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = {
static int cmi9880_build_controls(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
- int err;
+ struct snd_kcontrol *kctl;
+ int i, err;
err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
if (err < 0)
@@ -340,6 +341,15 @@ static int cmi9880_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
+
+ /* assign Capture Source enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids,
+ spec->input_mux->num_items);
+ if (err < 0)
+ return err;
+ }
return 0;
}
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index a09c03c3f62b..1ab2958a290b 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -2178,6 +2178,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_volume_info,
.get = snd_hda_mixer_amp_volume_get,
.put = snd_hda_mixer_amp_volume_put,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index aeed4cc5aa79..f88577897e46 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -627,6 +627,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
#define ALC_PIN_MODE(xname, nid, dir) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_pin_mode_info, \
.get = alc_pin_mode_get, \
.put = alc_pin_mode_put, \
@@ -678,6 +679,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
}
#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_gpio_data_info, \
.get = alc_gpio_data_get, \
.put = alc_gpio_data_put, \
@@ -732,6 +734,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
}
#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_spdif_ctrl_info, \
.get = alc_spdif_ctrl_get, \
.put = alc_spdif_ctrl_put, \
@@ -785,6 +788,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_eapd_ctrl_info, \
.get = alc_eapd_ctrl_get, \
.put = alc_eapd_ctrl_put, \
@@ -2410,6 +2414,15 @@ static const char *alc_slave_sws[] = {
* build control elements
*/
+#define NID_MAPPING (-1)
+
+#define SUBDEV_SPEAKER_ (0 << 6)
+#define SUBDEV_HP_ (1 << 6)
+#define SUBDEV_LINE_ (2 << 6)
+#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
+#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
+#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
+
static void alc_free_kctls(struct hda_codec *codec);
#ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -2424,8 +2437,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = {
static int alc_build_controls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- int err;
- int i;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new *knew;
+ int i, j, err;
+ unsigned int u;
+ hda_nid_t nid;
for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -2466,8 +2482,7 @@ static int alc_build_controls(struct hda_codec *codec)
if (!kctl)
return -ENOMEM;
kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec,
- get_amp_nid_(spec->beep_amp), kctl);
+ err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;
}
@@ -2494,6 +2509,73 @@ static int alc_build_controls(struct hda_codec *codec)
}
alc_free_kctls(codec); /* no longer needed */
+
+ /* assign Capture Source enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+ if (!kctl)
+ kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
+ spec->input_mux->num_items);
+ if (err < 0)
+ return err;
+ }
+ if (spec->cap_mixer) {
+ const char *kname = kctl ? kctl->id.name : NULL;
+ for (knew = spec->cap_mixer; knew->name; knew++) {
+ if (kname && strcmp(knew->name, kname) == 0)
+ continue;
+ kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nid(codec, kctl, i,
+ spec->adc_nids[i]);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
+
+ /* other nid->control mapping */
+ for (i = 0; i < spec->num_mixers; i++) {
+ for (knew = spec->mixers[i]; knew->name; knew++) {
+ if (knew->iface != NID_MAPPING)
+ continue;
+ kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+ if (kctl == NULL)
+ continue;
+ u = knew->subdevice;
+ for (j = 0; j < 4; j++, u >>= 8) {
+ nid = u & 0x3f;
+ if (nid == 0)
+ continue;
+ switch (u & 0xc0) {
+ case SUBDEV_SPEAKER_:
+ nid = spec->autocfg.speaker_pins[nid];
+ break;
+ case SUBDEV_LINE_:
+ nid = spec->autocfg.line_out_pins[nid];
+ break;
+ case SUBDEV_HP_:
+ nid = spec->autocfg.hp_pins[nid];
+ break;
+ default:
+ continue;
+ }
+ err = snd_hda_add_nid(codec, kctl, 0, nid);
+ if (err < 0)
+ return err;
+ }
+ u = knew->private_value;
+ for (j = 0; j < 4; j++, u >>= 8) {
+ nid = u & 0xff;
+ if (nid == 0)
+ continue;
+ err = snd_hda_add_nid(codec, kctl, 0, nid);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
return 0;
}
@@ -3781,6 +3863,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
#define PIN_CTL_TEST(xname,nid) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_test_pin_ctl_info, \
.get = alc_test_pin_ctl_get, \
.put = alc_test_pin_ctl_put, \
@@ -3790,6 +3873,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
#define PIN_SRC_TEST(xname,nid) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_test_pin_src_info, \
.get = alc_test_pin_src_get, \
.put = alc_test_pin_src_put, \
@@ -4329,7 +4413,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
if (!knew->name)
return -ENOMEM;
if (get_amp_nid_(val))
- knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+ knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
return 0;
}
@@ -5080,6 +5164,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
.info = snd_ctl_boolean_mono_info,
.get = alc260_hp_master_sw_get,
.put = alc260_hp_master_sw_put,
@@ -5118,6 +5203,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
.info = snd_ctl_boolean_mono_info,
.get = alc260_hp_master_sw_get,
.put = alc260_hp_master_sw_put,
@@ -10189,8 +10275,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
.info = snd_ctl_boolean_mono_info, \
.get = alc262_hp_master_sw_get, \
.put = alc262_hp_master_sw_put, \
+ }, \
+ { \
+ .iface = NID_MAPPING, \
+ .name = "Master Playback Switch", \
+ .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
}
+
static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
ALC262_HP_MASTER_SWITCH,
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -10348,6 +10440,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
.info = snd_ctl_boolean_mono_info, \
.get = alc262_hippo_master_sw_get, \
.put = alc262_hippo_master_sw_put, \
+ }, \
+ { \
+ .iface = NID_MAPPING, \
+ .name = "Master Playback Switch", \
+ .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
+ (SUBDEV_SPEAKER(0) << 16), \
}
static struct snd_kcontrol_new alc262_hippo_mixer[] = {
@@ -10821,11 +10919,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc262_fujitsu_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
},
+ {
+ .iface = NID_MAPPING,
+ .name = "Master Playback Switch",
+ .private_value = 0x1b,
+ },
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -10856,6 +10960,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc262_lenovo_3000_master_sw_put,
@@ -11010,6 +11115,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
.get = alc_mux_enum_get,
.put = alc262_ultra_mux_enum_put,
},
+ {
+ .iface = NID_MAPPING,
+ .name = "Capture Source",
+ .private_value = 0x15,
+ },
{ } /* end */
};
@@ -12027,6 +12137,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put,
@@ -12042,6 +12153,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put,
@@ -12059,6 +12171,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put,
@@ -13011,6 +13124,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put,
@@ -13031,6 +13145,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put,
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 43b436c5d01b..f419ee8d75f0 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
#define SI3054_KCONTROL(kname,reg,mask) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = kname, \
+ .subdevice = HDA_SUBDEV_NID_FLAG | reg, \
.info = si3054_switch_info, \
.get = si3054_switch_get, \
.put = si3054_switch_put, \
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 3d59f8325848..0bafea9d5106 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -2685,7 +2685,7 @@ static struct snd_kcontrol_new *
stac_control_new(struct sigmatel_spec *spec,
struct snd_kcontrol_new *ktemp,
const char *name,
- hda_nid_t nid)
+ unsigned int subdev)
{
struct snd_kcontrol_new *knew;
@@ -2701,8 +2701,7 @@ stac_control_new(struct sigmatel_spec *spec,
spec->kctls.alloced--;
return NULL;
}
- if (nid)
- knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+ knew->subdevice = subdev;
return knew;
}
@@ -2712,7 +2711,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
unsigned long val)
{
struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
- get_amp_nid_(val));
+ HDA_SUBDEV_AMP_FLAG);
if (!knew)
return -ENOMEM;
knew->index = idx;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index b70e26ad263f..de4839e46762 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -54,6 +54,8 @@
#include "hda_codec.h"
#include "hda_local.h"
+#define NID_MAPPING (-1)
+
/* amp values */
#define AMP_VAL_IDX_SHIFT 19
#define AMP_VAL_IDX_MASK (0x0f<<19)
@@ -157,6 +159,19 @@ struct via_spec {
#endif
};
+static struct via_spec * via_new_spec(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return NULL;
+
+ codec->spec = spec;
+ spec->codec = codec;
+ return spec;
+}
+
static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
{
u32 vendor_id = codec->vendor_id;
@@ -443,11 +458,27 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
if (!knew->name)
return -ENOMEM;
if (get_amp_nid_(val))
- knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+ knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
return 0;
}
+static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
+ struct snd_kcontrol_new *tmpl)
+{
+ struct snd_kcontrol_new *knew;
+
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return NULL;
+ *knew = *tmpl;
+ knew->name = kstrdup(tmpl->name, GFP_KERNEL);
+ if (!knew->name)
+ return NULL;
+ return 0;
+}
+
static void via_free_kctls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct via_spec *spec = codec->spec;
- hda_nid_t nid;
+ hda_nid_t nid = kcontrol->private_value;
unsigned int pinsel;
- switch (spec->codec_type) {
- case VT1718S:
- nid = 0x34;
- break;
- case VT2002P:
- nid = 0x35;
- break;
- case VT1812:
- nid = 0x3d;
- break;
- default:
- nid = spec->autocfg.hp_pins[0];
- break;
- }
/* use !! to translate conn sel 2 for VT1718S */
pinsel = !!snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_SEL,
@@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active)
}
}
+static hda_nid_t side_mute_channel(struct via_spec *spec)
+{
+ switch (spec->codec_type) {
+ case VT1708: return 0x1b;
+ case VT1709_10CH: return 0x29;
+ case VT1708B_8CH: /* fall thru */
+ case VT1708S: return 0x27;
+ default: return 0;
+ }
+}
+
static int update_side_mute_status(struct hda_codec *codec)
{
/* mute side channel */
struct via_spec *spec = codec->spec;
unsigned int parm = spec->hp_independent_mode
? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
- hda_nid_t sw3;
-
- switch (spec->codec_type) {
- case VT1708:
- sw3 = 0x1b;
- break;
- case VT1709_10CH:
- sw3 = 0x29;
- break;
- case VT1708B_8CH:
- case VT1708S:
- sw3 = 0x27;
- break;
- default:
- sw3 = 0;
- break;
- }
+ hda_nid_t sw3 = side_mute_channel(spec);
if (sw3)
snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- hda_nid_t nid = spec->autocfg.hp_pins[0];
+ hda_nid_t nid = kcontrol->private_value;
unsigned int pinsel = ucontrol->value.enumerated.item[0];
/* Get Independent Mode index of headphone pin widget */
spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
? 1 : 0;
-
- switch (spec->codec_type) {
- case VT1718S:
- nid = 0x34;
- pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
- spec->multiout.num_dacs = 4;
- break;
- case VT2002P:
- nid = 0x35;
- break;
- case VT1812:
- nid = 0x3d;
- break;
- default:
- nid = spec->autocfg.hp_pins[0];
- break;
- }
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
if (spec->multiout.hp_nid && spec->multiout.hp_nid
@@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new via_hp_mixer[] = {
+static struct snd_kcontrol_new via_hp_mixer[2] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Independent HP",
- .count = 1,
.info = via_independent_hp_info,
.get = via_independent_hp_get,
.put = via_independent_hp_put,
},
- { } /* end */
+ {
+ .iface = NID_MAPPING,
+ .name = "Independent HP",
+ },
};
+static int via_hp_build(struct via_spec *spec)
+{
+ struct snd_kcontrol_new *knew;
+ hda_nid_t nid;
+
+ knew = via_clone_control(spec, &via_hp_mixer[0]);
+ if (knew == NULL)
+ return -ENOMEM;
+
+ switch (spec->codec_type) {
+ case VT1718S:
+ nid = 0x34;
+ break;
+ case VT2002P:
+ nid = 0x35;
+ break;
+ case VT1812:
+ nid = 0x3d;
+ break;
+ default:
+ nid = spec->autocfg.hp_pins[0];
+ break;
+ }
+
+ knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+ knew->private_value = nid;
+
+ knew = via_clone_control(spec, &via_hp_mixer[1]);
+ if (knew == NULL)
+ return -ENOMEM;
+ knew->subdevice = side_mute_channel(spec);
+
+ return 0;
+}
+
static void notify_aa_path_ctls(struct hda_codec *codec)
{
int i;
@@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static struct snd_kcontrol_new via_smart51_mixer[] = {
+static struct snd_kcontrol_new via_smart51_mixer[2] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Smart 5.1",
@@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = {
.get = via_smart51_get,
.put = via_smart51_put,
},
- {} /* end */
+ {
+ .iface = NID_MAPPING,
+ .name = "Smart 5.1",
+ }
};
+static int via_smart51_build(struct via_spec *spec)
+{
+ struct snd_kcontrol_new *knew;
+ int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+ hda_nid_t nid;
+ int i;
+
+ knew = via_clone_control(spec, &via_smart51_mixer[0]);
+ if (knew == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(index); i++) {
+ nid = spec->autocfg.input_pins[index[i]];
+ if (nid) {
+ knew = via_clone_control(spec, &via_smart51_mixer[1]);
+ if (knew == NULL)
+ return -ENOMEM;
+ knew->subdevice = nid;
+ }
+ }
+
+ return 0;
+}
+
/* capture mixer elements */
static struct snd_kcontrol_new vt1708_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = {
static int via_build_controls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- int err;
- int i;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new *knew;
+ int err, i;
for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -1845,6 +1904,28 @@ static int via_build_controls(struct hda_codec *codec)
return err;
}
+ /* assign Capture Source enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids,
+ spec->input_mux->num_items);
+ if (err < 0)
+ return err;
+ }
+
+ /* other nid->control mapping */
+ for (i = 0; i < spec->num_mixers; i++) {
+ for (knew = spec->mixers[i]; knew->name; knew++) {
+ if (knew->iface != NID_MAPPING)
+ continue;
+ kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+ if (kctl == NULL)
+ continue;
+ err = snd_hda_add_nid(codec, kctl, 0,
+ knew->subdevice);
+ }
+ }
+
/* init power states */
set_jack_power_state(codec);
analog_low_current_mode(codec, 1);
@@ -2481,9 +2562,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -2554,12 +2635,10 @@ static int patch_vt1708(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1708_parse_auto_config(codec);
if (err < 0) {
@@ -2597,7 +2676,6 @@ static int patch_vt1708(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_POWER_SAVE
spec->loopback.amplist = vt1708_loopbacks;
#endif
- spec->codec = codec;
INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
return 0;
}
@@ -3010,9 +3088,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -3032,12 +3110,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
err = vt1709_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
@@ -3126,12 +3202,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
err = vt1709_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
@@ -3581,9 +3655,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -3605,12 +3679,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
if (get_codec_type(codec) == VT1708BCE)
return patch_vt1708S(codec);
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1708B_parse_auto_config(codec);
if (err < 0) {
@@ -3657,12 +3729,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1708B_parse_auto_config(codec);
if (err < 0) {
@@ -4071,9 +4141,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -4103,12 +4173,10 @@ static int patch_vt1708S(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1708S_parse_auto_config(codec);
if (err < 0) {
@@ -4443,7 +4511,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
return 1;
}
@@ -4464,12 +4532,10 @@ static int patch_vt1702(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1702_parse_auto_config(codec);
if (err < 0) {
@@ -4865,9 +4931,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -4888,12 +4954,10 @@ static int patch_vt1718S(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1718S_parse_auto_config(codec);
if (err < 0) {
@@ -5014,6 +5078,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mic Capture Switch",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
.count = 1,
.info = vt1716s_dmic_info,
.get = vt1716s_dmic_get,
@@ -5361,9 +5426,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
- spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+ via_smart51_build(spec);
return 1;
}
@@ -5384,12 +5449,10 @@ static int patch_vt1716S(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1716S_parse_auto_config(codec);
if (err < 0) {
@@ -5719,7 +5782,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
return 1;
}
@@ -5741,12 +5804,10 @@ static int patch_vt2002P(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt2002P_parse_auto_config(codec);
if (err < 0) {
@@ -6070,7 +6131,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
spec->input_mux = &spec->private_imux[0];
if (spec->hp_mux)
- spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ via_hp_build(spec);
return 1;
}
@@ -6092,12 +6153,10 @@ static int patch_vt1812(struct hda_codec *codec)
int err;
/* create a codec specific record */
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
- codec->spec = spec;
-
/* automatic parse from the BIOS config */
err = vt1812_parse_auto_config(codec);
if (err < 0) {