diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-02 13:08:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-02 13:08:49 -0700 |
commit | f27f0a045b79de5729d064497e21a70871f1d6fe (patch) | |
tree | 078416852de43b76e297224b57a9c5b9f67dfb56 /sound/pci/hda | |
parent | 6e0dd741a89be35defa05bd79f4211c5a2762825 (diff) | |
parent | c2f60c523aa34cf6d4913d6efc670890bd456fd5 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (28 commits)
[ALSA] Kconfig SND_SEQUENCER_OSS help text fix
[ALSA] Add Aux input switch control for Aureon Universe
[ALSA] pcxhr - Fix the crash with REV01 board
[ALSA] sound/pci/hda: use create_singlethread_workqueue()
[ALSA] hda-intel - Add support of ATI SB600
[ALSA] cs4281 - Fix the check of timeout in probe
[ALSA] cs4281 - Fix the check of right channel
[ALSA] Test volume resolution of usb audio at initialization
[ALSA] maestro3.c: fix BUG, optimization
[ALSA] HDA/Realtek: multiple input mux definitions and pin mode additions
[ALSA] AdLib FM card driver
[ALSA] Fix / clean up PCM-OSS setup hooks
[ALSA] Clean up PCM codes (take 2)
[ALSA] Tiny clean up of PCM codes
[ALSA] ISA drivers bailing on first !enable[i]
[ALSA] Remove obsolete kfree_nocheck call
[ALSA] Remove obsolete kfree_nocheck call
[ALSA] Add snd-als300 driver for Avance Logic ALS300/ALS300+ soundcards
[ALSA] Add snd-riptide driver for Conexant Riptide chip
[ALSA] hda-codec - Fix noisy output wtih AD1986A 3stack model
...
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 9 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 298 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 53 |
5 files changed, 288 insertions, 76 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b42dff7ceed..5bee3b53647 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -295,7 +295,7 @@ static int init_unsol_queue(struct hda_bus *bus) snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); return -ENOMEM; } - unsol->workq = create_workqueue("hda_codec"); + unsol->workq = create_singlethread_workqueue("hda_codec"); if (! unsol->workq) { snd_printk(KERN_ERR "hda_codec: can't create workqueue\n"); kfree(unsol); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c096606970f..0ad60ae2901 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -81,6 +81,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ESB2}," "{Intel, ICH8}," "{ATI, SB450}," + "{ATI, SB600}," "{VIA, VT8251}," "{VIA, VT8237A}," "{SiS, SIS966}," @@ -1619,6 +1620,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */ { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ + { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 32401bd8c22..2bfe37e8543 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -44,6 +44,7 @@ struct ad198x_spec { * dig_out_nid and hp_nid are optional */ unsigned int cur_eapd; + unsigned int need_dac_fix; /* capture */ unsigned int num_adc_nids; @@ -836,10 +837,14 @@ static int patch_ad1986a(struct hda_codec *codec) case AD1986A_3STACK: spec->num_mixers = 2; spec->mixers[1] = ad1986a_3st_mixers; - spec->num_init_verbs = 2; + spec->num_init_verbs = 3; spec->init_verbs[1] = ad1986a_3st_init_verbs; + spec->init_verbs[2] = ad1986a_ch2_init; spec->channel_mode = ad1986a_modes; spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); + spec->need_dac_fix = 1; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; break; case AD1986A_LAPTOP: spec->mixers[0] = ad1986a_laptop_mixers; @@ -1555,6 +1560,8 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, &spec->multiout.max_channels); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4c6c9ec8ea5..66bbdb60f50 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -52,6 +52,7 @@ enum { ALC880_CLEVO, ALC880_TCL_S700, ALC880_LG, + ALC880_LG_LW, #ifdef CONFIG_SND_DEBUG ALC880_TEST, #endif @@ -131,6 +132,7 @@ struct alc_spec { hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture source */ + unsigned int num_mux_defs; const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; @@ -172,6 +174,7 @@ struct alc_config_preset { hda_nid_t dig_in_nid; unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; + unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); void (*init_hook)(struct hda_codec *); @@ -185,7 +188,10 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); + unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); + if (mux_idx >= spec->num_mux_defs) + mux_idx = 0; + return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); } static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -203,7 +209,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; + return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol, spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); } @@ -245,7 +252,8 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these * are requested. Therefore order this list so that this behaviour will not * cause problems when mixer clients move through the enum sequentially. - * NIDs 0x0f and 0x10 have been observed to have this behaviour. + * NIDs 0x0f and 0x10 have been observed to have this behaviour as of + * March 2006. */ static char *alc_pin_mode_names[] = { "Mic 50pc bias", "Mic 80pc bias", @@ -255,19 +263,27 @@ static unsigned char alc_pin_mode_values[] = { PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, }; /* The control can present all 5 options, or it can limit the options based - * in the pin being assumed to be exclusively an input or an output pin. + * in the pin being assumed to be exclusively an input or an output pin. In + * addition, "input" pins may or may not process the mic bias option + * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to + * accept requests for bias as of chip versions up to March 2006) and/or + * wiring in the computer. */ -#define ALC_PIN_DIR_IN 0x00 -#define ALC_PIN_DIR_OUT 0x01 -#define ALC_PIN_DIR_INOUT 0x02 +#define ALC_PIN_DIR_IN 0x00 +#define ALC_PIN_DIR_OUT 0x01 +#define ALC_PIN_DIR_INOUT 0x02 +#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 +#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 -/* Info about the pin modes supported by the three different pin directions. +/* Info about the pin modes supported by the different pin direction modes. * For each direction the minimum and maximum values are given. */ -static signed char alc_pin_mode_dir_info[3][2] = { +static signed char alc_pin_mode_dir_info[5][2] = { { 0, 2 }, /* ALC_PIN_DIR_IN */ { 3, 4 }, /* ALC_PIN_DIR_OUT */ { 0, 4 }, /* ALC_PIN_DIR_INOUT */ + { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ + { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ }; #define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) #define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) @@ -329,9 +345,10 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v * input modes. * * Dynamically switching the input/output buffers probably - * reduces noise slightly, particularly on input. However, - * havingboth input and output buffers enabled - * simultaneously doesn't seem to be problematic. + * reduces noise slightly (particularly on input) so we'll + * do it. However, having both input and output buffers + * enabled simultaneously doesn't seem to be problematic if + * this turns out to be necessary in the future. */ if (val <= 2) { snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE, @@ -483,6 +500,9 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset * spec->multiout.dig_out_nid = preset->dig_out_nid; spec->multiout.hp_nid = preset->hp_nid; + spec->num_mux_defs = preset->num_mux_defs; + if (! spec->num_mux_defs) + spec->num_mux_defs = 1; spec->input_mux = preset->input_mux; spec->num_adc_nids = preset->num_adc_nids; @@ -1427,6 +1447,82 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) } /* + * LG LW20 + * + * Pin assignment: + * Speaker-out: 0x14 + * Mic-In: 0x18 + * Built-in Mic-In: 0x19 (?) + * HP-Out: 0x1b + * SPDIF-Out: 0x1e + */ + +/* seems analog CD is not working */ +static struct hda_input_mux alc880_lg_lw_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; + +static struct snd_kcontrol_new alc880_lg_lw_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + { } /* end */ +}; + +static struct hda_verb alc880_lg_lw_init_verbs[] = { + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + /* speaker-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* jack sense */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_lw_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + 0x80, present ? 0x80 : 0); +} + +static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_lw_automute(codec); +} + +/* * Common callbacks */ @@ -2078,6 +2174,9 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "lg", .config = ALC880_LG }, { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, + { .modelname = "lg-lw", .config = ALC880_LG_LW }, + { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, + #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, #endif @@ -2268,6 +2367,19 @@ static struct alc_config_preset alc880_presets[] = { .unsol_event = alc880_lg_unsol_event, .init_hook = alc880_lg_automute, }, + [ALC880_LG_LW] = { + .mixers = { alc880_lg_lw_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_lw_init_verbs }, + .num_dacs = 1, + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_lg_lw_capture_source, + .unsol_event = alc880_lg_lw_unsol_event, + .init_hook = alc880_lg_lw_automute, + }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { .mixers = { alc880_test_mixer }, @@ -2593,6 +2705,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; return 1; @@ -2722,30 +2835,56 @@ static struct hda_input_mux alc260_capture_source = { }; /* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, - * headphone jack and the internal CD lines. + * headphone jack and the internal CD lines since these are the only pins at + * which audio can appear. For flexibility, also allow the option of + * recording the mixer output on the second ADC (ADC0 doesn't have a + * connection to the mixer output). */ -static struct hda_input_mux alc260_fujitsu_capture_source = { - .num_items = 3, - .items = { - { "Mic/Line", 0x0 }, - { "CD", 0x4 }, - { "Headphone", 0x2 }, +static struct hda_input_mux alc260_fujitsu_capture_sources[2] = { + { + .num_items = 3, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + }, }, + { + .num_items = 4, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + { "Mixer", 0x5 }, + }, + }, + }; -/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to - * the Fujitsu S702x, but jacks are marked differently. We won't allow - * retasking the Headphone jack, so it won't be available here. +/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to + * the Fujitsu S702x, but jacks are marked differently. */ -static struct hda_input_mux alc260_acer_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, +static struct hda_input_mux alc260_acer_capture_sources[2] = { + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x5 }, + }, + }, + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x6 }, + { "Mixer", 0x5 }, + }, }, }; - /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer @@ -2806,6 +2945,9 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { { } /* end */ }; +/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, + * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. + */ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), @@ -2822,9 +2964,28 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { { } /* end */ }; +/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current + * versions of the ALC260 don't act on requests to enable mic bias from NID + * 0x0f (used to drive the headphone jack in these laptops). The ALC260 + * datasheet doesn't mention this restriction. At this stage it's not clear + * whether this behaviour is intentional or is a hardware bug in chip + * revisions available in early 2006. Therefore for now allow the + * "Headphone Jack Mode" control to span all choices, but if it turns out + * that the lack of mic bias for this NID is intentional we could change the + * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 + * don't appear to make the mic bias available from the "line" jack, even + * though the NID used for this jack (0x14) can supply it. The theory is + * that perhaps Acer have included blocking capacitors between the ALC260 + * and the output jack. If this turns out to be the case for all such + * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT + * to ALC_PIN_DIR_INOUT_NOMICBIAS. + */ static struct snd_kcontrol_new alc260_acer_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), @@ -3038,7 +3199,8 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { }; /* Initialisation sequence for ALC260 as configured in Fujitsu S702x - * laptops. + * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD + * audio = 0x16, internal speaker = 0x10. */ static struct hda_verb alc260_fujitsu_init_verbs[] = { /* Disable all GPIOs */ @@ -3185,10 +3347,10 @@ static struct hda_verb alc260_acer_init_verbs[] = { {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Do similar with the second ADC: mute capture input amp and - * set ADC connection to line (on line1 pin) + * set ADC connection to mic to match ALSA's default state. */ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mute all inputs to mixer widget (even unconnected ones) */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ @@ -3213,26 +3375,35 @@ static hda_nid_t alc260_test_dac_nids[1] = { static hda_nid_t alc260_test_adc_nids[2] = { 0x04, 0x05, }; -/* This is a bit messy since the two input muxes in the ALC260 have slight - * variations in their signal assignments. The ideal way to deal with this - * is to extend alc_spec.input_mux to allow a different input MUX for each - * ADC. For the purposes of the test model it's sufficient to just list - * both options for affected signal indices. The separate input mux - * functionality only needs to be considered if a model comes along which - * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to - * record. +/* For testing the ALC260, each input MUX needs its own definition since + * the signal assignments are different. This assumes that the first ADC + * is NID 0x04. */ -static struct hda_input_mux alc260_test_capture_source = { - .num_items = 8, - .items = { - { "MIC1 pin", 0x0 }, - { "MIC2 pin", 0x1 }, - { "LINE1 pin", 0x2 }, - { "LINE2 pin", 0x3 }, - { "CD pin", 0x4 }, - { "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 }, - { "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 }, - { "HP-OUT pin (cap2 only)", 0x7 }, +static struct hda_input_mux alc260_test_capture_sources[2] = { + { + .num_items = 7, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "LINE-OUT pin", 0x5 }, + { "HP-OUT pin", 0x6 }, + }, + }, + { + .num_items = 8, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "Mixer", 0x5 }, + { "LINE-OUT pin", 0x6 }, + { "HP-OUT pin", 0x7 }, + }, }, }; static struct snd_kcontrol_new alc260_test_mixer[] = { @@ -3244,7 +3415,17 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), - /* Modes for retasking pin widgets */ + /* Modes for retasking pin widgets + * Note: the ALC260 doesn't seem to act on requests to enable mic + * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't + * mention this restriction. At this stage it's not clear whether + * this behaviour is intentional or is a hardware bug in chip + * revisions available at least up until early 2006. Therefore for + * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all + * choices, but if it turns out that the lack of mic bias for these + * NIDs is intentional we could change their modes from + * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + */ ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), @@ -3606,6 +3787,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; /* check whether NID 0x04 is valid */ @@ -3711,7 +3893,8 @@ static struct alc_config_preset alc260_presets[] = { .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, - .input_mux = &alc260_fujitsu_capture_source, + .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), + .input_mux = alc260_fujitsu_capture_sources, }, [ALC260_ACER] = { .mixers = { alc260_acer_mixer, @@ -3723,7 +3906,8 @@ static struct alc_config_preset alc260_presets[] = { .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, - .input_mux = &alc260_acer_capture_source, + .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), + .input_mux = alc260_acer_capture_sources, }, #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = { @@ -3736,7 +3920,8 @@ static struct alc_config_preset alc260_presets[] = { .adc_nids = alc260_test_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, - .input_mux = &alc260_test_capture_source, + .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), + .input_mux = alc260_test_capture_sources, }, #endif }; @@ -3828,7 +4013,6 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; - #define alc882_mux_enum_info alc_mux_enum_info #define alc882_mux_enum_get alc_mux_enum_get @@ -4730,6 +4914,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; return 1; @@ -5406,6 +5591,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; spec->adc_nids = alc861_adc_nids; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b56ca401939..abe9493f0a2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -534,6 +534,22 @@ static int stac92xx_build_pcms(struct hda_codec *codec) return 0; } +static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_param_read(codec, nid, + AC_PAR_PIN_CAP); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + if (pincap & AC_PINCAP_VREF_100) + return AC_PINCTL_VREF_100; + if (pincap & AC_PINCAP_VREF_80) + return AC_PINCTL_VREF_80; + if (pincap & AC_PINCAP_VREF_50) + return AC_PINCTL_VREF_50; + if (pincap & AC_PINCAP_VREF_GRD) + return AC_PINCTL_VREF_GRD; + return 0; +} + static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) { @@ -571,9 +587,12 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (val) stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - else - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN); - + else { + unsigned int pinctl = AC_PINCTL_IN_EN; + if (io_idx) /* set VREF for mic */ + pinctl |= stac92xx_get_vref(codec, nid); + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } return 1; } @@ -767,13 +786,8 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin return 0; wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) { - /* Enable unsolicited responses on the HP widget */ - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - STAC_UNSOL_ENABLE); + if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; - } nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; for (i = 0; i < cfg->line_outs; i++) { @@ -896,13 +910,8 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, return 0; wid_caps = get_wcaps(codec, pin); - if (wid_caps & AC_WCAP_UNSOL_CAP) { - /* Enable unsolicited responses on the HP widget */ - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - STAC_UNSOL_ENABLE); + if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; - } return 0; } @@ -944,6 +953,10 @@ static int stac92xx_init(struct hda_codec *codec) /* set up pins */ if (spec->hp_detect) { + /* Enable unsolicited responses on the HP widget */ + snd_hda_codec_write(codec, cfg->hp_pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + STAC_UNSOL_ENABLE); /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { @@ -951,9 +964,13 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_init_hp_out(codec); } for (i = 0; i < AUTO_PIN_LAST; i++) { - if (cfg->input_pins[i]) - stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], - AC_PINCTL_IN_EN); + hda_nid_t nid = cfg->input_pins[i]; + if (nid) { + unsigned int pinctl = AC_PINCTL_IN_EN; + if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) + pinctl |= stac92xx_get_vref(codec, nid); + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } } if (cfg->dig_out_pin) stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, |