[alsa-devel] [PATCH] snd-hda-intel: Jack Mode changes for Sigmatel boards

This patch changes Line In as Out Switch and Mic In as Out Switch to enums for consistency, and causes all mic ports to be probed and controls to be added appropriately.
Signed-off-by: Nickolas Lloyd ultrageek.lloyd@gmail.com
Note: diffed against alsa-driver-20090520 ----
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-19 22:05:02.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-20 12:17:49.000000000 +0000 @@ -668,62 +668,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2695,7 +2639,93 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + if (kcontrol->private_value & 0x100) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0x0ff; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = (kcontrol->private_value & 0x0ff); + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 1; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + + + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + if (kcontrol->private_value & 0xff) + texts[0] = "Mic In"; + else + texts[0] = "Line In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2703,7 +2733,7 @@ static int stac92xx_io_switch_get(struct struct sigmatel_spec *spec = codec->spec; int io_idx = kcontrol-> private_value & 0xff;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2713,7 +2743,7 @@ static int stac92xx_io_switch_put(struct struct sigmatel_spec *spec = codec->spec; hda_nid_t nid = kcontrol->private_value >> 8; int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -3242,7 +3272,10 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; + int def_conf; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3261,18 +3294,34 @@ static int stac92xx_auto_create_multi_ou
if (spec->line_switch) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", + "Line In Jack Mode", spec->line_switch << 8); if (err < 0) return err; }
- if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); - if (err < 0) - return err; + nid = cfg->input_pins[AUTO_PIN_MIC]; + idx = 0; +again: + if (nid) { + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + stac92xx_add_control_idx(spec, + STAC_CTL_WIDGET_DC_BIAS, idx++, + "Mic Jack Mode", nid + | ((nid == spec->mic_switch) + ? 0x100 : 0)); + else if (nid == spec->mic_switch) + stac92xx_add_control_idx(spec, + STAC_CTL_WIDGET_IO_SWITCH, idx++, + "Mic Jack Mode", ((nid << 8) | 1)); + } + } + if (nid == cfg->input_pins[AUTO_PIN_MIC]) { + nid = cfg->input_pins[AUTO_PIN_FRONT_MIC]; + goto again; }
return 0;
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-19 22:05:02.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-20 12:17:49.000000000 +0000 @@ -668,62 +668,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2695,7 +2639,93 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + if (kcontrol->private_value & 0x100) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0x0ff; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = (kcontrol->private_value & 0x0ff); + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 1; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + + + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + if (kcontrol->private_value & 0xff) + texts[0] = "Mic In"; + else + texts[0] = "Line In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2703,7 +2733,7 @@ static int stac92xx_io_switch_get(struct struct sigmatel_spec *spec = codec->spec; int io_idx = kcontrol-> private_value & 0xff;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2713,7 +2743,7 @@ static int stac92xx_io_switch_put(struct struct sigmatel_spec *spec = codec->spec; hda_nid_t nid = kcontrol->private_value >> 8; int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -3242,7 +3272,10 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; + int def_conf; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3261,18 +3294,34 @@ static int stac92xx_auto_create_multi_ou
if (spec->line_switch) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", + "Line In Jack Mode", spec->line_switch << 8); if (err < 0) return err; }
- if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); - if (err < 0) - return err; + nid = cfg->input_pins[AUTO_PIN_MIC]; + idx = 0; +again: + if (nid) { + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + stac92xx_add_control_idx(spec, + STAC_CTL_WIDGET_DC_BIAS, idx++, + "Mic Jack Mode", nid + | ((nid == spec->mic_switch) + ? 0x100 : 0)); + else if (nid == spec->mic_switch) + stac92xx_add_control_idx(spec, + STAC_CTL_WIDGET_IO_SWITCH, idx++, + "Mic Jack Mode", ((nid << 8) | 1)); + } + } + if (nid == cfg->input_pins[AUTO_PIN_MIC]) { + nid = cfg->input_pins[AUTO_PIN_FRONT_MIC]; + goto again; }
return 0;

Hi,
sorry for the late review. Some comments below.
At Wed, 20 May 2009 12:35:41 +0000, Nickolas Lloyd wrote:
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
+{
- int i;
- static char *texts[] = {
"Mic In", "Line In", "Line Out"
- };
- if (kcontrol->private_value & 0x100)
Please avoid a magic number. Define a constant if needed.
i = 3;
- else
i = 2;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = i;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= i)
uinfo->value.enumerated.item = i-1;
Didn't checkpatch.pl complain? :)
+static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0x0ff;
Better to define a macro to retrieve a value.
- unsigned int vref = stac92xx_vref_get(codec, nid);
- if (vref == stac92xx_get_vref(codec, nid))
Well, these two functions, stac92xx_vref_get() and stac92xx_get_vref() are too confusing. We have to rename one of them, at least, or at best clean up a bit more.
@@ -3261,18 +3294,34 @@ static int stac92xx_auto_create_multi_ou
if (spec->line_switch) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
"Line In as Output Switch",
}"Line In Jack Mode", spec->line_switch << 8); if (err < 0) return err;
- if (spec->mic_switch) {
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS,
"Mic Jack Mode",
spec->mic_switch);
if (err < 0)
return err;
- nid = cfg->input_pins[AUTO_PIN_MIC];
- idx = 0;
+again:
- if (nid) {
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
if (snd_hda_query_pin_caps(codec, nid)
& (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
stac92xx_add_control_idx(spec,
STAC_CTL_WIDGET_DC_BIAS, idx++,
"Mic Jack Mode", nid
| ((nid == spec->mic_switch)
? 0x100 : 0));
else if (nid == spec->mic_switch)
stac92xx_add_control_idx(spec,
STAC_CTL_WIDGET_IO_SWITCH, idx++,
"Mic Jack Mode", ((nid << 8) | 1));
}
- }
- if (nid == cfg->input_pins[AUTO_PIN_MIC]) {
nid = cfg->input_pins[AUTO_PIN_FRONT_MIC];
}goto again;
Hmm, this code flow is too complex and hackish to follow. There must be a better way. For example, the complicated neted if checks can be put out to a function. The compiler is clever enough to inline, and here is no critical code path for speed.
Could you fix and repost please?
thanks,
Takashi

Takashi Iwai wrote:
Hi,
sorry for the late review. Some comments below.
No worries. I know you're busy, and I appreciate your time and help :)
i = 3;
- else
i = 2;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = i;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= i)
uinfo->value.enumerated.item = i-1;
Didn't checkpatch.pl complain? :)
It didn't actually. What should it have complained about, so I can fix it?
Well, these two functions, stac92xx_vref_get() and stac92xx_get_vref() are too confusing. We have to rename one of them, at least, or at best clean up a bit more.
I agree. stac92xx_vref_get() and stac92xx_vref_set() are a pair, so perhaps they should stay as they are, and stac92xx_get_vref() be renamed to stac92xx_get_default_vref() or something?
Hmm, this code flow is too complex and hackish to follow. There must be a better way. For example, the complicated neted if checks can be put out to a function. The compiler is clever enough to inline, and here is no critical code path for speed.
Could you fix and repost please?
thanks,
Takashi
I've added a function stac92xx_add_mic_jack_control() to take care of the if's and add the control. The code is much cleaner now IMO. Is this function name ok, and do you have any other thoughts?
I'll be posting the new patch soon so that you can actually look at that as well.
Thanks, Nick

This patch changes Line In as Out Switch and Mic In as Out Switch to enums for consistency, and causes all mic ports to be probed and controls to be added appropriately.
Signed-off-by: Nickolas Lloyd ultrageek.lloyd@gmail.com
Note: diffed against alsa-driver-20090526 ----
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-25 22:05:02.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-25 19:11:45.000000000 +0000 @@ -669,62 +669,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2705,15 +2649,108 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + + if (nid == spec->mic_switch) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 0; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + if (kcontrol->private_value == spec->line_switch) + texts[0] = "Line In"; + else + texts[0] = "Mic In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; + hda_nid_t nid = kcontrol->private_value >> 8; + int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2721,9 +2758,9 @@ static int stac92xx_io_switch_put(struct { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -2890,6 +2927,28 @@ static struct snd_kcontrol_new stac_inpu .put = stac92xx_mux_enum_put, };
+static inline int stac92xx_add_mic_jack_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) + return stac92xx_add_control_idx(codec->spec, control, + idx, "Mic Jack Mode" , nid); + + return 1; +} + static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3252,7 +3311,9 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3271,18 +3332,27 @@ static int stac92xx_auto_create_multi_ou
if (spec->line_switch) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); + "Line In Jack Mode", + spec->line_switch); if (err < 0) return err; }
- if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); + nid = cfg->input_pins[AUTO_PIN_MIC]; + idx = 0; + +again: + if (nid) { + err = stac92xx_add_mic_jack_control(codec, nid, idx); if (err < 0) return err; + else if (!err) + idx++; + } + + if (nid == cfg->input_pins[AUTO_PIN_MIC]) { + nid = cfg->input_pins[AUTO_PIN_FRONT_MIC]; + goto again; }
return 0;
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-25 22:05:02.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-25 19:11:45.000000000 +0000 @@ -669,62 +669,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2705,15 +2649,108 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + + if (nid == spec->mic_switch) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 0; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + if (kcontrol->private_value == spec->line_switch) + texts[0] = "Line In"; + else + texts[0] = "Mic In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; + hda_nid_t nid = kcontrol->private_value >> 8; + int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2721,9 +2758,9 @@ static int stac92xx_io_switch_put(struct { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -2890,6 +2927,28 @@ static struct snd_kcontrol_new stac_inpu .put = stac92xx_mux_enum_put, };
+static inline int stac92xx_add_mic_jack_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) + return stac92xx_add_control_idx(codec->spec, control, + idx, "Mic Jack Mode" , nid); + + return 1; +} + static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3252,7 +3311,9 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3271,18 +3332,27 @@ static int stac92xx_auto_create_multi_ou
if (spec->line_switch) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); + "Line In Jack Mode", + spec->line_switch); if (err < 0) return err; }
- if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); + nid = cfg->input_pins[AUTO_PIN_MIC]; + idx = 0; + +again: + if (nid) { + err = stac92xx_add_mic_jack_control(codec, nid, idx); if (err < 0) return err; + else if (!err) + idx++; + } + + if (nid == cfg->input_pins[AUTO_PIN_MIC]) { + nid = cfg->input_pins[AUTO_PIN_FRONT_MIC]; + goto again; }
return 0;

At Mon, 25 May 2009 19:18:44 +0000, Nickolas Lloyd wrote:
- nid = cfg->input_pins[AUTO_PIN_MIC];
- idx = 0;
+again:
- if (nid) {
if (err < 0) return err;err = stac92xx_add_mic_jack_control(codec, nid, idx);
else if (!err)
idx++;
- }
- if (nid == cfg->input_pins[AUTO_PIN_MIC]) {
nid = cfg->input_pins[AUTO_PIN_FRONT_MIC];
}goto again;
Well, a goto loop is old-fashioned as a code in 21st century :)
Also, it might be better to use auto_pin_cfg_labels[] to each unique control name instead of index. It's often more intuitive.
Takashi

Takashi Iwai wrote:
Well, a goto loop is old-fashioned as a code in 21st century :)
Also, it might be better to use auto_pin_cfg_labels[] to each unique control name instead of index. It's often more intuitive.
Takashi
Thanks for the suggestions. Indeed, using the labels array does make it much more intuitive.
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + char name[22]; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (stac92xx_get_vref(codec, nid) == AC_PINCTL_VREF_GRD + && nid == spec->line_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + else if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) { + strcpy(name, auto_pin_cfg_labels[idx]); + return stac92xx_add_control(codec->spec, control, + strcat(name, " Jack Mode"), nid); + } + + return 0; +} +
One question here is if it's possible for a Line In jack to act as a Mic Jack via the use of a DC bias.
@@ -3269,20 +3336,13 @@ static int stac92xx_auto_create_multi_ou return err; }
- if (spec->line_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); - if (err < 0) - return err; - } - - if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); - if (err < 0) - return err; + for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { + nid = cfg->input_pins[idx]; + if (nid) { + err = stac92xx_add_jack_mode_control(codec, nid, idx); + if (err < 0) + return err; + }
Do these sections look alright? And if so, should I re-up the whole thing? Also, is there anything else you think I should change, or any other suggestions you have?
Thanks, Nick

At Wed, 27 May 2009 14:14:08 +0000, Nickolas Lloyd wrote:
Takashi Iwai wrote:
Well, a goto loop is old-fashioned as a code in 21st century :)
Also, it might be better to use auto_pin_cfg_labels[] to each unique control name instead of index. It's often more intuitive.
Takashi
Thanks for the suggestions. Indeed, using the labels array does make it much more intuitive.
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
hda_nid_t nid, int idx)
+{
- int def_conf = snd_hda_codec_get_pincfg(codec, nid);
- int control = 0;
- struct sigmatel_spec *spec = codec->spec;
- char name[22];
- if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
if (stac92xx_get_vref(codec, nid) == AC_PINCTL_VREF_GRD
&& nid == spec->line_switch)
control = STAC_CTL_WIDGET_IO_SWITCH;
else if (snd_hda_query_pin_caps(codec, nid)
& (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
control = STAC_CTL_WIDGET_DC_BIAS;
else if (nid == spec->mic_switch)
control = STAC_CTL_WIDGET_IO_SWITCH;
- }
- if (control) {
strcpy(name, auto_pin_cfg_labels[idx]);
return stac92xx_add_control(codec->spec, control,
strcat(name, " Jack Mode"), nid);
- }
- return 0;
+}
One question here is if it's possible for a Line In jack to act as a Mic Jack via the use of a DC bias.
It could be certainly a use-case. I thought you can select it on Windows, too?
@@ -3269,20 +3336,13 @@ static int stac92xx_auto_create_multi_ou return err; }
- if (spec->line_switch) {
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
"Line In as Output Switch",
spec->line_switch << 8);
if (err < 0)
return err;
- }
- if (spec->mic_switch) {
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS,
"Mic Jack Mode",
spec->mic_switch);
if (err < 0)
return err;
- for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
nid = cfg->input_pins[idx];
if (nid) {
err = stac92xx_add_jack_mode_control(codec, nid, idx);
if (err < 0)
return err;
}
Do these sections look alright? And if so, should I re-up the whole thing? Also, is there anything else you think I should change, or any other suggestions you have?
That looks good. Could you complete the patch, then let's merge first? We can tune up later after the merge (if any).
thanks,
Takashi

Takashi Iwai wrote:
That looks good. Could you complete the patch, then let's merge first? We can tune up later after the merge (if any).
thanks,
Takashi
Will do. I've also changed stac92xx_get_vref() to stac92xx_get_default_vref() to hopefully avoid confusion with vref_get(). I'll be posting the (hopefully) final version of this patch shortly.
Thanks for all your help, Nick

The (hopefully) final version of the patch.
This patch changes Line In as Out Switch and Mic In as Out Switch to enums for consistency, and causes all mic and line in ports to be probed and controls to be added appropriately.
Signed-off-by: Nickolas Lloyd ultrageek.lloyd@gmail.com
Note: diffed against alsa-driver-20090529
----
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-28 18:12:15.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-29 12:53:28.000000000 +0000 @@ -670,62 +670,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2652,7 +2596,8 @@ static int stac92xx_build_pcms(struct hd return 0; }
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) +static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, + hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; @@ -2706,15 +2651,108 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + + if (nid == spec->mic_switch || nid == spec->line_switch) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_default_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_default_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 0; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + if (kcontrol->private_value == spec->line_switch) + texts[0] = "Line In"; + else + texts[0] = "Mic In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2722,9 +2760,9 @@ static int stac92xx_io_switch_put(struct { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -2733,7 +2771,7 @@ static int stac92xx_io_switch_put(struct else { unsigned int pinctl = AC_PINCTL_IN_EN; if (io_idx) /* set VREF for mic */ - pinctl |= stac92xx_get_vref(codec, nid); + pinctl |= stac92xx_get_default_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); }
@@ -2891,6 +2929,34 @@ static struct snd_kcontrol_new stac_inpu .put = stac92xx_mux_enum_put, };
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + char name[22]; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD + && nid == spec->line_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + else if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) { + strcpy(name, auto_pin_cfg_labels[idx]); + return stac92xx_add_control(codec->spec, control, + strcat(name, " Jack Mode"), nid); + } + + return 0; +} + static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3253,7 +3319,9 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3270,20 +3338,13 @@ static int stac92xx_auto_create_multi_ou return err; }
- if (spec->line_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); - if (err < 0) - return err; - } - - if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); - if (err < 0) - return err; + for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { + nid = cfg->input_pins[idx]; + if (nid) { + err = stac92xx_add_jack_mode_control(codec, nid, idx); + if (err < 0) + return err; + } }
return 0; @@ -4193,7 +4254,7 @@ static int stac92xx_init(struct hda_code unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ - pinctl = stac92xx_get_vref(codec, nid); + pinctl = stac92xx_get_default_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); } else {
--- alsa-driver/sound/pci/hda/patch_sigmatel.c 2009-05-28 18:12:15.000000000 +0000 +++ alsa-driver.a/sound/pci/hda/patch_sigmatel.c 2009-05-29 12:53:28.000000000 +0000 @@ -670,62 +670,6 @@ static unsigned int stac92xx_vref_get(st return vref; }
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref; - unsigned int error; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = AC_PINCTL_VREF_80; - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else - new_vref = AC_PINCTL_VREF_HIZ; - - if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) { - error = stac92xx_vref_set(codec, - kcontrol->private_value, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value); - if (vref == AC_PINCTL_VREF_80) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 3; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -2652,7 +2596,8 @@ static int stac92xx_build_pcms(struct hd return 0; }
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) +static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, + hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; @@ -2706,15 +2651,108 @@ static int stac92xx_hp_switch_put(struct return 1; }
-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + + if (nid == spec->mic_switch || nid == spec->line_switch) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_default_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + unsigned int error; + hda_nid_t nid = kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_default_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 0; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + if (kcontrol->private_value == spec->line_switch) + texts[0] = "Line In"; + else + texts[0] = "Mic In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +}
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; }
@@ -2722,9 +2760,9 @@ static int stac92xx_io_switch_put(struct { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; + unsigned short val = !!ucontrol->value.enumerated.item[0];
spec->io_switch[io_idx] = val;
@@ -2733,7 +2771,7 @@ static int stac92xx_io_switch_put(struct else { unsigned int pinctl = AC_PINCTL_IN_EN; if (io_idx) /* set VREF for mic */ - pinctl |= stac92xx_get_vref(codec, nid); + pinctl |= stac92xx_get_default_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); }
@@ -2891,6 +2929,34 @@ static struct snd_kcontrol_new stac_inpu .put = stac92xx_mux_enum_put, };
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + char name[22]; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD + && nid == spec->line_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + else if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) { + strcpy(name, auto_pin_cfg_labels[idx]); + return stac92xx_add_control(codec->spec, control, + strcat(name, " Jack Mode"), nid); + } + + return 0; +} + static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3253,7 +3319,9 @@ static int stac92xx_auto_create_multi_ou const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; int err; + int idx;
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3270,20 +3338,13 @@ static int stac92xx_auto_create_multi_ou return err; }
- if (spec->line_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); - if (err < 0) - return err; - } - - if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS, - "Mic Jack Mode", - spec->mic_switch); - if (err < 0) - return err; + for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { + nid = cfg->input_pins[idx]; + if (nid) { + err = stac92xx_add_jack_mode_control(codec, nid, idx); + if (err < 0) + return err; + } }
return 0; @@ -4193,7 +4254,7 @@ static int stac92xx_init(struct hda_code unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ - pinctl = stac92xx_get_vref(codec, nid); + pinctl = stac92xx_get_default_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); } else {

At Fri, 29 May 2009 16:41:38 +0000, Nickolas Lloyd wrote:
The (hopefully) final version of the patch.
This patch changes Line In as Out Switch and Mic In as Out Switch to enums for consistency, and causes all mic and line in ports to be probed and controls to be added appropriately.
Signed-off-by: Nickolas Lloyd ultrageek.lloyd@gmail.com
Thanks, applied now to sound git tree. Let me know if you find any problems with it.
Takashi
participants (2)
-
Nickolas Lloyd
-
Takashi Iwai