Commit 5b0cb1d8 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA: hda - add more NID->Control mapping

This set of changes add missing NID values to some static control
elemenents. Also, it handles all "Capture Source" or "Input Source"
controls.
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent f4054253
...@@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) ...@@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
#endif #endif
list_del(&codec->list); list_del(&codec->list);
snd_array_free(&codec->mixers); snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
codec->bus->caddr_tbl[codec->addr] = NULL; codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free) if (codec->patch_ops.free)
codec->patch_ops.free(codec); codec->patch_ops.free(codec);
...@@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr ...@@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
mutex_init(&codec->control_mutex); mutex_init(&codec->control_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 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->init_pins, sizeof(struct hda_pincfg), 16);
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
if (codec->bus->modelname) { if (codec->bus->modelname) {
...@@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, ...@@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); 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 * @codec: HD-audio codec
* @nid: corresponding NID (optional) * @nid: corresponding NID (optional)
* @kctl: the control element to assign * @kctl: the control element to assign
...@@ -1746,6 +1748,35 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, ...@@ -1746,6 +1748,35 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
} }
EXPORT_SYMBOL_HDA(snd_hda_ctl_add); 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 * snd_hda_ctls_clear - Clear all controls assigned to the given codec
* @codec: HD-audio codec * @codec: HD-audio codec
...@@ -1757,6 +1788,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) ...@@ -1757,6 +1788,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
for (i = 0; i < codec->mixers.used; i++) for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->bus->card, items[i].kctl); snd_ctl_remove(codec->bus->card, items[i].kctl);
snd_array_free(&codec->mixers); snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
} }
/* pseudo device locking /* pseudo device locking
...@@ -3476,6 +3508,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) ...@@ -3476,6 +3508,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
for (; knew->name; knew++) { for (; knew->name; knew++) {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
if (knew->iface == -1) /* skip this codec private value */
continue;
kctl = snd_ctl_new1(knew, codec); kctl = snd_ctl_new1(knew, codec);
if (!kctl) if (!kctl)
return -ENOMEM; return -ENOMEM;
...@@ -3496,6 +3530,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) ...@@ -3496,6 +3530,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
} }
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); 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 #ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state); unsigned int power_state);
......
...@@ -789,6 +789,7 @@ struct hda_codec { ...@@ -789,6 +789,7 @@ struct hda_codec {
u32 *wcaps; u32 *wcaps;
struct snd_array mixers; /* list of assigned mixer elements */ 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 amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */ struct hda_cache_rec cmd_cache; /* cache for other commands */
......
...@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec) ...@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
} }
/* create input MUX if multiple sources are available */ /* 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) if (err < 0)
return err; return err;
......
...@@ -342,6 +342,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, ...@@ -342,6 +342,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
const struct snd_pci_quirk *tbl); const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec, int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew); 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 * unsolicited event handler
...@@ -466,11 +468,14 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); ...@@ -466,11 +468,14 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
struct hda_nid_item { struct hda_nid_item {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
unsigned int index;
hda_nid_t nid; hda_nid_t nid;
}; };
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl); 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); void snd_hda_ctls_clear(struct hda_codec *codec);
/* /*
......
...@@ -61,18 +61,21 @@ static const char *get_wid_type_name(unsigned int wid_value) ...@@ -61,18 +61,21 @@ static const char *get_wid_type_name(unsigned int wid_value)
return "UNKNOWN Widget"; return "UNKNOWN Widget";
} }
static void print_nid_mixers(struct snd_info_buffer *buffer, static void print_nid_array(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid) struct hda_codec *codec, hda_nid_t nid,
struct snd_array *array)
{ {
int i; int i;
struct hda_nid_item *items = codec->mixers.list; struct hda_nid_item *items = array->list, *item;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
for (i = 0; i < codec->mixers.used; i++) { for (i = 0; i < array->used; i++) {
if (items[i].nid == nid) { item = &items[i];
kctl = items[i].kctl; if (item->nid == nid) {
kctl = item->kctl;
snd_iprintf(buffer, snd_iprintf(buffer,
" Control: name=\"%s\", index=%i, device=%i\n", " 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);
} }
} }
} }
...@@ -528,7 +531,8 @@ static void print_gpio(struct snd_info_buffer *buffer, ...@@ -528,7 +531,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
(data & (1<<i)) ? 1 : 0, (data & (1<<i)) ? 1 : 0,
(unsol & (1<<i)) ? 1 : 0); (unsol & (1<<i)) ? 1 : 0);
/* FIXME: add GPO and GPI pin information */ /* 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, static void print_codec_info(struct snd_info_entry *entry,
...@@ -608,7 +612,8 @@ static void print_codec_info(struct snd_info_entry *entry, ...@@ -608,7 +612,8 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_iprintf(buffer, " CP"); snd_iprintf(buffer, " CP");
snd_iprintf(buffer, "\n"); 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); print_nid_pcms(buffer, codec, nid);
/* volume knob is a special widget that always have connection /* volume knob is a special widget that always have connection
......
...@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { ...@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
static int ad198x_build_controls(struct hda_codec *codec) static int ad198x_build_controls(struct hda_codec *codec)
{ {
struct ad198x_spec *spec = codec->spec; struct ad198x_spec *spec = codec->spec;
struct snd_kcontrol *kctl;
unsigned int i; unsigned int i;
int err; int err;
...@@ -239,6 +240,28 @@ static int ad198x_build_controls(struct hda_codec *codec) ...@@ -239,6 +240,28 @@ static int ad198x_build_controls(struct hda_codec *codec)
} }
ad198x_free_kctls(codec); /* no longer needed */ 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; return 0;
} }
...@@ -701,6 +724,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { ...@@ -701,6 +724,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier", .name = "External Amplifier",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad198x_eapd_info, .info = ad198x_eapd_info,
.get = ad198x_eapd_get, .get = ad198x_eapd_get,
.put = ad198x_eapd_put, .put = ad198x_eapd_put,
...@@ -808,6 +832,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { ...@@ -808,6 +832,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x1a,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = ad1986a_hp_master_sw_put, .put = ad1986a_hp_master_sw_put,
...@@ -1608,6 +1633,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { ...@@ -1608,6 +1633,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.info = ad198x_eapd_info, .info = ad198x_eapd_info,
.get = ad198x_eapd_get, .get = ad198x_eapd_get,
...@@ -2121,6 +2147,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { ...@@ -2121,6 +2147,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier", .name = "External Amplifier",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
.info = ad198x_eapd_info, .info = ad198x_eapd_info,
.get = ad198x_eapd_get, .get = ad198x_eapd_get,
.put = ad198x_eapd_put, .put = ad198x_eapd_put,
...@@ -2242,6 +2269,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { ...@@ -2242,6 +2269,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Source", .name = "IEC958 Playback Source",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad1988_spdif_playback_source_info, .info = ad1988_spdif_playback_source_info,
.get = ad1988_spdif_playback_source_get, .get = ad1988_spdif_playback_source_get,
.put = ad1988_spdif_playback_source_put, .put = ad1988_spdif_playback_source_put,
...@@ -3728,6 +3756,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { ...@@ -3728,6 +3756,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x21,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put, .put = ad1884a_mobile_master_sw_put,
...@@ -3756,6 +3785,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { ...@@ -3756,6 +3785,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x21,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put, .put = ad1884a_mobile_master_sw_put,
...@@ -4097,6 +4127,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { ...@@ -4097,6 +4127,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.subdevice = HDA_SUBDEV_NID_FLAG | 0x21,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
......
...@@ -759,6 +759,10 @@ static int build_input(struct hda_codec *codec) ...@@ -759,6 +759,10 @@ static int build_input(struct hda_codec *codec)
err = snd_hda_ctl_add(codec, 0, kctl); err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0) if (err < 0)
return err; 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) { if (spec->num_inputs > 1 && !spec->mic_detect) {
......
...@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = { ...@@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = {
static int cmi9880_build_controls(struct hda_codec *codec) static int cmi9880_build_controls(struct hda_codec *codec)
{ {
struct cmi_spec *spec = codec->spec; 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); err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
if (err < 0) if (err < 0)
...@@ -340,6 +341,15 @@ static int cmi9880_build_controls(struct hda_codec *codec) ...@@ -340,6 +341,15 @@ static int cmi9880_build_controls(struct hda_codec *codec)
if (err < 0) if (err < 0)
return err; 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; return 0;
} }
......
...@@ -627,6 +627,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, ...@@ -627,6 +627,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
#define ALC_PIN_MODE(xname, nid, dir) \ #define ALC_PIN_MODE(xname, nid, dir) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_pin_mode_info, \ .info = alc_pin_mode_info, \
.get = alc_pin_mode_get, \ .get = alc_pin_mode_get, \
.put = alc_pin_mode_put, \ .put = alc_pin_mode_put, \
...@@ -678,6 +679,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, ...@@ -678,6 +679,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
} }
#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_gpio_data_info, \ .info = alc_gpio_data_info, \
.get = alc_gpio_data_get, \ .get = alc_gpio_data_get, \
.put = alc_gpio_data_put, \ .put = alc_gpio_data_put, \
...@@ -732,6 +734,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, ...@@ -732,6 +734,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
} }
#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_spdif_ctrl_info, \ .info = alc_spdif_ctrl_info, \
.get = alc_spdif_ctrl_get, \ .get = alc_spdif_ctrl_get, \
.put = alc_spdif_ctrl_put, \ .put = alc_spdif_ctrl_put, \
...@@ -785,6 +788,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, ...@@ -785,6 +788,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_eapd_ctrl_info, \ .info = alc_eapd_ctrl_info, \
.get = alc_eapd_ctrl_get, \ .get = alc_eapd_ctrl_get, \
.put = alc_eapd_ctrl_put, \ .put = alc_eapd_ctrl_put, \
...@@ -2410,6 +2414,15 @@ static const char *alc_slave_sws[] = { ...@@ -2410,6 +2414,15 @@ static const char *alc_slave_sws[] = {
* build control elements * 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); static void alc_free_kctls(struct hda_codec *codec);
#ifdef CONFIG_SND_HDA_INPUT_BEEP #ifdef CONFIG_SND_HDA_INPUT_BEEP
...@@ -2424,8 +2437,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = { ...@@ -2424,8 +2437,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = {
static int alc_build_controls(struct hda_codec *codec) static int alc_build_controls(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int err; struct snd_kcontrol *kctl;
int i; struct snd_kcontrol_new *knew;
int i, j, err;
unsigned int u;
hda_nid_t nid;
for (i = 0; i < spec->num_mixers; i++) { for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]); err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
...@@ -2494,6 +2510,73 @@ static int alc_build_controls(struct hda_codec *codec) ...@@ -2494,6 +2510,73 @@ static int alc_build_controls(struct hda_codec *codec)
} }
alc_free_kctls(codec); /* no longer needed */ 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; return 0;
} }
...@@ -3781,6 +3864,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, ...@@ -3781,6 +3864,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
#define PIN_CTL_TEST(xname,nid) { \ #define PIN_CTL_TEST(xname,nid) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \ .name = xname, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_test_pin_ctl_info, \ .info = alc_test_pin_ctl_info, \
.get = alc_test_pin_ctl_get, \ .get = alc_test_pin_ctl_get, \
.put = alc_test_pin_ctl_put, \ .put = alc_test_pin_ctl_put, \
...@@ -3790,6 +3874,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, ...@@ -3790,6 +3874,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
#define PIN_SRC_TEST(xname,nid) { \ #define PIN_SRC_TEST(xname,nid) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \ .name = xname, \
.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
.info = alc_test_pin_src_info, \ .info = alc_test_pin_src_info, \
.get = alc_test_pin_src_get, \ .get = alc_test_pin_src_get, \
.put = alc_test_pin_src_put, \ .put = alc_test_pin_src_put, \
...@@ -5080,6 +5165,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { ...@@ -5080,6 +5165,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
.info = snd_ctl_boolean_mono_info, .info = snd_ctl_boolean_mono_info,
.get = alc260_hp_master_sw_get, .get = alc260_hp_master_sw_get,
.put = alc260_hp_master_sw_put, .put = alc260_hp_master_sw_put,
...@@ -5118,6 +5204,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { ...@@ -5118,6 +5204,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
.info = snd_ctl_boolean_mono_info, .info = snd_ctl_boolean_mono_info,
.get = alc260_hp_master_sw_get, .get = alc260_hp_master_sw_get,
.put = alc260_hp_master_sw_put, .put = alc260_hp_master_sw_put,
...@@ -10188,8 +10275,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, ...@@ -10188,8 +10275,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
.info = snd_ctl_boolean_mono_info, \ .info = snd_ctl_boolean_mono_info, \
.get = alc262_hp_master_sw_get, \ .get = alc262_hp_master_sw_get, \
.put = alc262_hp_master_sw_put, \ .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[] = { static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
ALC262_HP_MASTER_SWITCH, ALC262_HP_MASTER_SWITCH,
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
...@@ -10347,6 +10440,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, ...@@ -10347,6 +10440,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
.info = snd_ctl_boolean_mono_info, \ .info = snd_ctl_boolean_mono_info, \
.get = alc262_hippo_master_sw_get, \ .get = alc262_hippo_master_sw_get, \
.put = alc262_hippo_master_sw_put, \ .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[] = { static struct snd_kcontrol_new alc262_hippo_mixer[] = {
...@@ -10820,11 +10919,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { ...@@ -10820,11 +10919,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc262_fujitsu_master_sw_put, .put = alc262_fujitsu_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), .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_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
...@@ -10855,6 +10960,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { ...@@ -10855,6 +10960,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc262_lenovo_3000_master_sw_put, .put = alc262_lenovo_3000_master_sw_put,
...@@ -11009,6 +11115,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { ...@@ -11009,6 +11115,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
.get = alc_mux_enum_get, .get = alc_mux_enum_get,
.put = alc262_ultra_mux_enum_put, .put = alc262_ultra_mux_enum_put,
}, },
{
.iface = NID_MAPPING,
.name = "Capture Source",
.private_value = 0x15,
},
{ } /* end */ { } /* end */
}; };
...@@ -12026,6 +12137,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { ...@@ -12026,6 +12137,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put, .put = alc268_acer_master_sw_put,
...@@ -12041,6 +12153,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { ...@@ -12041,6 +12153,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put, .put = alc268_acer_master_sw_put,
...@@ -12058,6 +12171,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { ...@@ -12058,6 +12171,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put, .put = alc268_acer_master_sw_put,
...@@ -13010,6 +13124,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { ...@@ -13010,6 +13124,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put, .put = alc268_acer_master_sw_put,
...@@ -13030,6 +13145,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { ...@@ -13030,6 +13145,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
{ {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch", .name = "Master Playback Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
.info = snd_hda_mixer_amp_switch_info, .info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get, .get = snd_hda_mixer_amp_switch_get,
.put = alc268_acer_master_sw_put, .put = alc268_acer_master_sw_put,
......
...@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, ...@@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
#define SI3054_KCONTROL(kname,reg,mask) { \ #define SI3054_KCONTROL(kname,reg,mask) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = kname, \ .name = kname, \
.subdevice = HDA_SUBDEV_NID_FLAG | reg, \
.info = si3054_switch_info, \ .info = si3054_switch_info, \
.get = si3054_switch_get, \ .get = si3054_switch_get, \
.put = si3054_switch_put, \ .put = si3054_switch_put, \
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment