diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-05-10 20:52:07 +0200 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-05-10 22:50:41 +0200 |
commit | 020abf03cd659388f94cb328e1e1df0656e0d7ff (patch) | |
tree | 40d05011708ad1b4a05928d167eb120420581aa6 /sound/pci/hda | |
parent | 0ff8fbc61727c926883eec381fbd3d32d1fab504 (diff) | |
parent | 693d92a1bbc9e42681c42ed190bd42b636ca876f (diff) |
Merge tag 'v2.6.39-rc7'
in order to pull in changes in drivers/media/dvb/firewire/ and
sound/firewire/.
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 183 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_eld.c | 26 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 23 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 30 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 272 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 464 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 204 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1278 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 411 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 101 |
15 files changed, 1818 insertions, 1196 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 644e3f14f8c..759ade12e75 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -29,6 +29,7 @@ #include <sound/asoundef.h> #include <sound/tlv.h> #include <sound/initval.h> +#include <sound/jack.h> #include "hda_local.h" #include "hda_beep.h" #include <sound/hda_hwdep.h> @@ -936,6 +937,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +#ifdef SND_HDA_NEEDS_RESUME /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -952,6 +954,7 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } +#endif static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); @@ -1328,6 +1331,7 @@ static void purify_inactive_streams(struct hda_codec *codec) } } +#ifdef SND_HDA_NEEDS_RESUME /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1339,6 +1343,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } +#endif /* * amp access functions @@ -1919,6 +1924,16 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); +static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) +{ + int idx; + for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ + if (!_snd_hda_find_mixer_ctl(codec, name, idx)) + return idx; + } + return -EBUSY; +} + /** * snd_hda_ctl_add - Add a control element and assign to the codec * @codec: HD-audio codec @@ -2124,10 +2139,10 @@ int snd_hda_codec_reset(struct hda_codec *codec) * This function returns zero if successful or a negative error code. */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char **slaves) + unsigned int *tlv, const char * const *slaves) { struct snd_kcontrol *kctl; - const char **s; + const char * const *s; int err; for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) @@ -2654,8 +2669,6 @@ static struct snd_kcontrol_new dig_mixes[] = { { } /* end */ }; -#define SPDIF_MAX_IDX 4 /* 4 instances should be enough to probe */ - /** * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls * @codec: the HDA codec @@ -2673,12 +2686,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) struct snd_kcontrol_new *dig_mix; int idx; - for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { - if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch", - idx)) - break; - } - if (idx >= SPDIF_MAX_IDX) { + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); + if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); return -EBUSY; } @@ -2829,12 +2838,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) struct snd_kcontrol_new *dig_mix; int idx; - for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { - if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch", - idx)) - break; - } - if (idx >= SPDIF_MAX_IDX) { + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch"); + if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); return -EBUSY; } @@ -3660,7 +3665,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) * with the proper parameters for set up. * ops.cleanup should be called in hw_free for clean up of streams. * - * This function returns 0 if successfull, or a negative error code. + * This function returns 0 if successful, or a negative error code. */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) { @@ -3689,7 +3694,7 @@ EXPORT_SYMBOL_HDA(snd_hda_build_pcms); * If no entries are matching, the function returns a negative value. */ int snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char **models, + int num_configs, const char * const *models, const struct snd_pci_quirk *tbl) { if (codec->modelname && models) { @@ -3753,7 +3758,7 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config); * If no entries are matching, the function returns a negative value. */ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char **models, + int num_configs, const char * const *models, const struct snd_pci_quirk *tbl) { const struct snd_pci_quirk *q; @@ -3808,21 +3813,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) for (; knew->name; knew++) { struct snd_kcontrol *kctl; + int addr = 0, idx = 0; if (knew->iface == -1) /* skip this codec private value */ continue; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) { - if (!codec->addr) - return err; + for (;;) { kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; - kctl->id.device = codec->addr; + if (addr > 0) + kctl->id.device = addr; + if (idx > 0) + kctl->id.index = idx; err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) + if (!err) + break; + /* try first with another device index corresponding to + * the codec addr; if it still fails (or it's the + * primary codec), then try another control index + */ + if (!addr && codec->addr) + addr = codec->addr; + else if (!idx && !knew->index) { + idx = find_empty_mixer_ctl_idx(codec, + knew->name); + if (idx <= 0) + return err; + } else return err; } } @@ -4560,6 +4576,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } memset(cfg->hp_pins + cfg->hp_outs, 0, sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + if (!cfg->hp_outs) + cfg->line_out_type = AUTO_PIN_HP_OUT; + } /* sort by sequence */ @@ -4676,7 +4695,7 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, int check_location) { unsigned int def_conf; - static const char *mic_names[] = { + static const char * const mic_names[] = { "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", }; int attr; @@ -4836,7 +4855,7 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend); * * Returns 0 if successful. * - * This fucntion is defined only when POWER_SAVE isn't set. + * This function is defined only when POWER_SAVE isn't set. * In the power-save mode, the codec is resumed dynamically. */ int snd_hda_resume(struct hda_bus *bus) @@ -4945,5 +4964,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) } EXPORT_SYMBOL_HDA(snd_print_pcm_bits); +#ifdef CONFIG_SND_HDA_INPUT_JACK +/* + * Input-jack notification support + */ +struct hda_jack_item { + hda_nid_t nid; + int type; + struct snd_jack *jack; +}; + +static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid, + int type) +{ + switch (type) { + case SND_JACK_HEADPHONE: + return "Headphone"; + case SND_JACK_MICROPHONE: + return "Mic"; + case SND_JACK_LINEOUT: + return "Line-out"; + case SND_JACK_HEADSET: + return "Headset"; + default: + return "Misc"; + } +} + +static void hda_free_jack_priv(struct snd_jack *jack) +{ + struct hda_jack_item *jacks = jack->private_data; + jacks->nid = 0; + jacks->jack = NULL; +} + +int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type, + const char *name) +{ + struct hda_jack_item *jack; + int err; + + snd_array_init(&codec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&codec->jacks); + if (!jack) + return -ENOMEM; + + jack->nid = nid; + jack->type = type; + if (!name) + name = get_jack_default_name(codec, nid, type); + err = snd_jack_new(codec->bus->card, name, type, &jack->jack); + if (err < 0) { + jack->nid = 0; + return err; + } + jack->jack->private_data = jack; + jack->jack->private_free = hda_free_jack_priv; + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_add); + +void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_jack_item *jacks = codec->jacks.list; + int i; + + if (!jacks) + return; + + for (i = 0; i < codec->jacks.used; i++, jacks++) { + unsigned int pin_ctl; + unsigned int present; + int type; + + if (jacks->nid != nid) + continue; + present = snd_hda_jack_detect(codec, nid); + type = jacks->type; + if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) { + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + type = (pin_ctl & AC_PINCTL_HP_EN) ? + SND_JACK_HEADPHONE : SND_JACK_LINEOUT; + } + snd_jack_report(jacks->jack, present ? type : 0); + } +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_report); + +/* free jack instances manually when clearing/reconfiguring */ +void snd_hda_input_jack_free(struct hda_codec *codec) +{ + if (!codec->bus->shutdown && codec->jacks.list) { + struct hda_jack_item *jacks = codec->jacks.list; + int i; + for (i = 0; i < codec->jacks.used; i++, jacks++) { + if (jacks->jack) + snd_device_free(codec->bus->card, jacks->jack); + } + } + snd_array_free(&codec->jacks); +} +EXPORT_SYMBOL_HDA(snd_hda_input_jack_free); +#endif /* CONFIG_SND_HDA_INPUT_JACK */ + MODULE_DESCRIPTION("HDA codec core"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index fdf8d44f8b6..e46d5420a9f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -866,6 +866,11 @@ struct hda_codec { /* codec-specific additional proc output */ void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); + +#ifdef CONFIG_SND_HDA_INPUT_JACK + /* jack detection */ + struct snd_array jacks; +#endif }; /* direction */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index cb0c23a6b47..74b0560289c 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -189,6 +189,9 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->channels = GRAB_BITS(buf, 0, 0, 3); a->channels++; + a->sample_bits = 0; + a->max_bitrate = 0; + a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: @@ -198,7 +201,6 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, case AUDIO_CODING_TYPE_LPCM: val = GRAB_BITS(buf, 2, 0, 3); - a->sample_bits = 0; for (i = 0; i < 3; i++) if (val & (1 << i)) a->sample_bits |= cea_sample_sizes[i + 1]; @@ -379,7 +381,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) snd_print_pcm_rates(a->rates, buf, sizeof(buf)); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); else if (a->max_bitrate) snprintf(buf2, sizeof(buf2), ", max bitrate = %d", a->max_bitrate); @@ -598,24 +600,19 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, { int i; - pcm->rates = 0; - pcm->formats = 0; - pcm->maxbps = 0; - pcm->channels_min = -1; - pcm->channels_max = 0; + /* assume basic audio support (the basic audio flag is not in ELD; + * however, all audio capable sinks are required to support basic + * audio) */ + pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + pcm->formats = SNDRV_PCM_FMTBIT_S16_LE; + pcm->maxbps = 16; + pcm->channels_max = 2; for (i = 0; i < eld->sad_count; i++) { struct cea_sad *a = &eld->sad[i]; pcm->rates |= a->rates; - if (a->channels < pcm->channels_min) - pcm->channels_min = a->channels; if (a->channels > pcm->channels_max) pcm->channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { - if (a->sample_bits & AC_SUPPCM_BITS_16) { - pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE; - if (pcm->maxbps < 16) - pcm->maxbps = 16; - } if (a->sample_bits & AC_SUPPCM_BITS_20) { pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; if (pcm->maxbps < 20) @@ -635,7 +632,6 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, /* restrict the parameters by the values the codec provides */ pcm->rates &= codec_pars->rates; pcm->formats &= codec_pars->formats; - pcm->channels_min = max(pcm->channels_min, codec_pars->channels_min); pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index fb0582f8d72..a63c54d9d76 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -762,7 +762,8 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con /* * build output mixer controls */ -static int create_output_mixers(struct hda_codec *codec, const char **names) +static int create_output_mixers(struct hda_codec *codec, + const char * const *names) { struct hda_gspec *spec = codec->spec; int i, err; @@ -780,8 +781,8 @@ static int create_output_mixers(struct hda_codec *codec, const char **names) static int build_output_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - static const char *types_speaker[] = { "Speaker", "Headphone" }; - static const char *types_line[] = { "Front", "Headphone" }; + static const char * const types_speaker[] = { "Speaker", "Headphone" }; + static const char * const types_line[] = { "Front", "Headphone" }; switch (spec->pcm_vol_nodes) { case 1: diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 21aa9b0e28f..70a9d32f0e9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1052,9 +1052,12 @@ static void azx_init_pci(struct azx *chip) /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs + * codecs. + * The PCI register TCSEL is defined in the Intel manuals. */ - update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + if (chip->driver_type != AZX_DRIVER_ATI && + chip->driver_type != AZX_DRIVER_ATIHDMI) + update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); switch (chip->driver_type) { case AZX_DRIVER_ATI: @@ -1235,7 +1238,8 @@ static int azx_setup_periods(struct azx *chip, pos_adj = 0; } else { ofs = setup_bdle(substream, azx_dev, - &bdl, ofs, pos_adj, 1); + &bdl, ofs, pos_adj, + !substream->runtime->no_period_wakeup); if (ofs < 0) goto error; } @@ -1247,7 +1251,8 @@ static int azx_setup_periods(struct azx *chip, period_bytes - pos_adj, 0); else ofs = setup_bdle(substream, azx_dev, &bdl, ofs, - period_bytes, 1); + period_bytes, + !substream->runtime->no_period_wakeup); if (ofs < 0) goto error; } @@ -1515,7 +1520,8 @@ static struct snd_pcm_hardware azx_pcm_hw = { /* No full-resume yet implemented */ /* SNDRV_PCM_INFO_RESUME |*/ SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, @@ -2296,13 +2302,16 @@ static int azx_dev_free(struct snd_device *device) */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), @@ -2698,7 +2707,7 @@ static int __devinit azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (patch[dev]) { + if (patch[dev] && *patch[dev]) { snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", patch[dev]); err = snd_hda_load_patch(chip->bus, patch[dev]); @@ -2804,6 +2813,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { #endif /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, + /* VMware HDAudio */ + { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 46bbefe2e4a..ff5e2ac2239 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -140,7 +140,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char **slaves); + unsigned int *tlv, const char * const *slaves); int snd_hda_codec_reset(struct hda_codec *codec); /* amp value bits */ @@ -341,10 +341,10 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen); * Misc */ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, - const char **modelnames, + const char * const *modelnames, const struct snd_pci_quirk *pci_list); int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char **models, + int num_configs, const char * const *models, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); @@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec, #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); +/* + * Input-jack notification support + */ +#ifdef CONFIG_SND_HDA_INPUT_JACK +int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type, + const char *name); +void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid); +void snd_hda_input_jack_free(struct hda_codec *codec); +#else /* CONFIG_SND_HDA_INPUT_JACK */ +static inline int snd_hda_input_jack_add(struct hda_codec *codec, + hda_nid_t nid, int type, + const char *name) +{ + return 0; +} +static inline void snd_hda_input_jack_report(struct hda_codec *codec, + hda_nid_t nid) +{ +} +static inline void snd_hda_input_jack_free(struct hda_codec *codec) +{ +} +#endif /* CONFIG_SND_HDA_INPUT_JACK */ + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f025200f2a6..bfe74c2fb07 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -418,7 +418,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer, static const char *get_pwr_state(u32 state) { - static const char *buf[4] = { + static const char * const buf[4] = { "D0", "D1", "D2", "D3" }; if (state < 4) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index f7ff3f7ccb8..2942d2a9ea1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -30,10 +30,10 @@ #include "hda_beep.h" struct ad198x_spec { - struct snd_kcontrol_new *mixers[5]; + struct snd_kcontrol_new *mixers[6]; int num_mixers; unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - const struct hda_verb *init_verbs[5]; /* initialization verbs + const struct hda_verb *init_verbs[6]; /* initialization verbs * don't forget NULL termination! */ unsigned int num_init_verbs; @@ -46,6 +46,9 @@ struct ad198x_spec { unsigned int cur_eapd; unsigned int need_dac_fix; + hda_nid_t *alt_dac_nid; + struct hda_pcm_stream *stream_analog_alt_playback; + /* capture */ unsigned int num_adc_nids; hda_nid_t *adc_nids; @@ -81,8 +84,8 @@ struct ad198x_spec { #endif /* for virtual master */ hda_nid_t vmaster_nid; - const char **slave_vols; - const char **slave_sws; + const char * const *slave_vols; + const char * const *slave_sws; }; /* @@ -130,7 +133,7 @@ static int ad198x_init(struct hda_codec *codec) return 0; } -static const char *ad_slave_vols[] = { +static const char * const ad_slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -143,7 +146,7 @@ static const char *ad_slave_vols[] = { NULL }; -static const char *ad_slave_sws[] = { +static const char * const ad_slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = { NULL }; +static const char * const ad1988_6stack_fp_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "IEC958 Playback Volume", + NULL +}; + +static const char * const ad1988_6stack_fp_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "IEC958 Playback Switch", + NULL +}; static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -309,6 +331,13 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } +static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in ad198x_build_pcms */ +}; + /* * Digital out */ @@ -446,6 +475,17 @@ static int ad198x_build_pcms(struct hda_codec *codec) } } + if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { + codec->num_pcms++; + info = spec->pcm_rec + 2; + info->name = "AD198x Headphone"; + info->pcm_type = HDA_PCM_TYPE_AUDIO; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *spec->stream_analog_alt_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->alt_dac_nid[0]; + } + return 0; } @@ -666,7 +706,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), @@ -729,7 +769,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), /* HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ @@ -775,7 +815,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), { @@ -1069,7 +1109,7 @@ enum { AD1986A_MODELS }; -static const char *ad1986a_models[AD1986A_MODELS] = { +static const char * const ad1986a_models[AD1986A_MODELS] = { [AD1986A_6STACK] = "6stack", [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", @@ -1358,7 +1398,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { @@ -1515,8 +1555,8 @@ static struct snd_kcontrol_new ad1981_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { @@ -1726,8 +1766,8 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), #endif - HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { @@ -1774,7 +1814,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { @@ -1813,7 +1853,7 @@ enum { AD1981_MODELS }; -static const char *ad1981_models[AD1981_MODELS] = { +static const char * const ad1981_models[AD1981_MODELS] = { [AD1981_HP] = "hp", [AD1981_THINKPAD] = "thinkpad", [AD1981_BASIC] = "basic", @@ -2015,6 +2055,7 @@ static int patch_ad1981(struct hda_codec *codec) enum { AD1988_6STACK, AD1988_6STACK_DIG, + AD1988_6STACK_DIG_FP, AD1988_3STACK, AD1988_3STACK_DIG, AD1988_LAPTOP, @@ -2047,6 +2088,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { 0x04, 0x05, 0x0a, 0x06 }; +static hda_nid_t ad1988_alt_dac_nid[1] = { + 0x03 +}; + static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { 0x04, 0x0a, 0x06 }; @@ -2160,8 +2205,14 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), + + { } /* end */ +}; + +static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -2203,8 +2254,8 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -2232,7 +2283,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2445,6 +2496,19 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { { } }; +static struct hda_verb ad1988_6stack_fp_init_verbs[] = { + /* Headphone; unmute as default */ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Port-A front headphon path */ + {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + { } +}; + static struct hda_verb ad1988_capture_init_verbs[] = { /* mute analog mix */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -2792,7 +2856,9 @@ static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + static const char * const chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; hda_nid_t nid; int i, err; @@ -2902,7 +2968,7 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, idx = ad1988_pin_idx(pin); bnid = ad1988_boost_nids[idx]; if (bnid) { - sprintf(name, "%s Boost", ctlname); + sprintf(name, "%s Boost Volume", ctlname); return add_control(spec, AD_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT)); @@ -3074,13 +3140,13 @@ static int ad1988_auto_init(struct hda_codec *codec) return 0; } - /* */ -static const char *ad1988_models[AD1988_MODEL_LAST] = { +static const char * const ad1988_models[AD1988_MODEL_LAST] = { [AD1988_6STACK] = "6stack", [AD1988_6STACK_DIG] = "6stack-dig", + [AD1988_6STACK_DIG_FP] = "6stack-dig-fp", [AD1988_3STACK] = "3stack", [AD1988_3STACK_DIG] = "3stack-dig", [AD1988_LAPTOP] = "laptop", @@ -3140,6 +3206,7 @@ static int patch_ad1988(struct hda_codec *codec) switch (board_config) { case AD1988_6STACK: case AD1988_6STACK_DIG: + case AD1988_6STACK_DIG_FP: spec->multiout.max_channels = 8; spec->multiout.num_dacs = 4; if (is_rev2(codec)) @@ -3155,7 +3222,19 @@ static int patch_ad1988(struct hda_codec *codec) spec->mixers[1] = ad1988_6stack_mixers2; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1988_6stack_init_verbs; - if (board_config == AD1988_6STACK_DIG) { + if (board_config == AD1988_6STACK_DIG_FP) { + spec->num_mixers++; + spec->mixers[2] = ad1988_6stack_fp_mixers; + spec->num_init_verbs++; + spec->init_verbs[1] = ad1988_6stack_fp_init_verbs; + spec->slave_vols = ad1988_6stack_fp_slave_vols; + spec->slave_sws = ad1988_6stack_fp_slave_sws; + spec->alt_dac_nid = ad1988_alt_dac_nid; + spec->stream_analog_alt_playback = + &ad198x_pcm_analog_alt_playback; + } + if ((board_config == AD1988_6STACK_DIG) || + (board_config == AD1988_6STACK_DIG_FP)) { spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; spec->dig_in_nid = AD1988_SPDIF_IN; } @@ -3300,8 +3379,8 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -3399,7 +3478,7 @@ static struct hda_amp_list ad1884_loopbacks[] = { }; #endif -static const char *ad1884_slave_vols[] = { +static const char * const ad1884_slave_vols[] = { "PCM Playback Volume", "Mic Playback Volume", "Mono Playback Volume", @@ -3499,9 +3578,9 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -3560,8 +3639,8 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -3637,7 +3716,7 @@ enum { AD1984_MODELS }; -static const char *ad1984_models[AD1984_MODELS] = { +static const char * const ad1984_models[AD1984_MODELS] = { [AD1984_BASIC] = "basic", [AD1984_THINKPAD] = "thinkpad", [AD1984_DELL_DESKTOP] = "dell_desktop", @@ -3745,9 +3824,9 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -3888,9 +3967,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), { } /* end */ @@ -4126,8 +4205,8 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), { @@ -4177,6 +4256,84 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) } /* + * Precision R5500 + * 0x12 - HP/line-out + * 0x13 - speaker (mono) + * 0x15 - mic-in + */ + +static struct hda_verb ad1984a_precision_verbs[] = { + /* Unmute main output path */ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ + /* Analog mixer; mute as default */ + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Select mic as input */ + {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ + /* Configure as mic */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ + /* HP unmute */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* turn on EAPD */ + {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + /* unsolicited event for pin-sense */ + {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, + { } /* end */ +}; + +static struct snd_kcontrol_new ad1984a_precision_mixers[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), + { } /* end */ +}; + + +/* mute internal speaker if HP is plugged */ +static void ad1984a_precision_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_jack_detect(codec, 0x12); + snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + + +/* unsolicited event for HP jack sensing */ +static void ad1984a_precision_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != AD1884A_HP_EVENT) + return; + ad1984a_precision_automute(codec); +} + +/* initialize jack-sensing, too */ +static int ad1984a_precision_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1984a_precision_automute(codec); + return 0; +} + + +/* * HP Touchsmart * port-A (0x11) - front hp-out * port-B (0x14) - unused @@ -4255,8 +4412,8 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), { } /* end */ }; @@ -4305,18 +4462,21 @@ enum { AD1884A_MOBILE, AD1884A_THINKPAD, AD1984A_TOUCHSMART, + AD1984A_PRECISION, AD1884A_MODELS }; -static const char *ad1884a_models[AD1884A_MODELS] = { +static const char * const ad1884a_models[AD1884A_MODELS] = { [AD1884A_DESKTOP] = "desktop", [AD1884A_LAPTOP] = "laptop", [AD1884A_MOBILE] = "mobile", [AD1884A_THINKPAD] = "thinkpad", [AD1984A_TOUCHSMART] = "touchsmart", + [AD1984A_PRECISION] = "precision", }; static struct snd_pci_quirk ad1884a_cfg_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), @@ -4410,6 +4570,14 @@ static int patch_ad1884a(struct hda_codec *codec) codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; codec->patch_ops.init = ad1984a_thinkpad_init; break; + case AD1984A_PRECISION: + spec->mixers[0] = ad1984a_precision_mixers; + spec->init_verbs[spec->num_init_verbs++] = + ad1984a_precision_verbs; + spec->multiout.dig_out_nid = 0; + codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; + codec->patch_ops.init = ad1984a_precision_init; + break; case AD1984A_TOUCHSMART: spec->mixers[0] = ad1984a_touchsmart_mixers; spec->init_verbs[0] = ad1984a_touchsmart_verbs; @@ -4494,9 +4662,9 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = { HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), @@ -4547,7 +4715,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), { } /* end */ }; @@ -4696,7 +4864,7 @@ enum { AD1882_MODELS }; -static const char *ad1882_models[AD1986A_MODELS] = { +static const char * const ad1882_models[AD1986A_MODELS] = { [AD1882_3STACK] = "3stack", [AD1882_6STACK] = "6stack", }; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 18af38ebf75..067982f4f18 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -490,7 +490,7 @@ static int parse_digital_input(struct hda_codec *codec) * create mixer controls */ -static const char *dir_sfx[2] = { "Playback", "Capture" }; +static const char * const dir_sfx[2] = { "Playback", "Capture" }; static int add_mute(struct hda_codec *codec, const char *name, int index, unsigned int pval, int dir, struct snd_kcontrol **kctlp) @@ -1039,9 +1039,11 @@ static struct hda_verb cs_errata_init_verbs[] = { {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, {0x11, AC_VERB_SET_PROC_STATE, 0x00}, +#if 0 /* Don't to set to D3 as we are in power-up sequence */ {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */ {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */ /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */ +#endif {} /* terminator */ }; @@ -1156,7 +1158,7 @@ static int cs_parse_auto_config(struct hda_codec *codec) return 0; } -static const char *cs420x_models[CS420X_MODELS] = { +static const char * const cs420x_models[CS420X_MODELS] = { [CS420X_MBP53] = "mbp53", [CS420X_MBP55] = "mbp55", [CS420X_IMAC27] = "imac27", diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index ff60908f455..1f8bbcd0f80 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -608,7 +608,7 @@ static void cmi9880_free(struct hda_codec *codec) /* */ -static const char *cmi9880_models[CMI_MODELS] = { +static const char * const cmi9880_models[CMI_MODELS] = { [CMI_MINIMAL] = "minimal", [CMI_MIN_FP] = "min_fp", [CMI_FULL] = "full", diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 846d1ead47f..ad97d937d3a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -49,14 +49,6 @@ #define AUTO_MIC_PORTB (1 << 1) #define AUTO_MIC_PORTC (1 << 2) -struct conexant_jack { - - hda_nid_t nid; - int type; - struct snd_jack *jack; - -}; - struct pin_dac_pair { hda_nid_t pin; hda_nid_t dac; @@ -85,6 +77,7 @@ struct conexant_spec { unsigned int auto_mic; int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ unsigned int need_dac_fix; + hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; @@ -110,9 +103,6 @@ struct conexant_spec { unsigned int spdif_route; - /* jack detection */ - struct snd_array jacks; - /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; @@ -127,6 +117,7 @@ struct conexant_spec { unsigned int ideapad:1; unsigned int thinkpad:1; unsigned int hp_laptop:1; + unsigned int asus:1; unsigned int ext_mic_present; unsigned int recording; @@ -352,6 +343,8 @@ static int conexant_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } + if (spec->slave_dig_outs[0]) + codec->slave_dig_outs = spec->slave_dig_outs; } return 0; @@ -389,65 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void conexant_free_jack_priv(struct snd_jack *jack) -{ - struct conexant_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} - -static int conexant_add_jack(struct hda_codec *codec, - hda_nid_t nid, int type) -{ - struct conexant_spec *spec; - struct conexant_jack *jack; - const char *name; - int err; - - spec = codec->spec; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; - - if (!jack) - return -ENOMEM; - - jack->nid = nid; - jack->type = type; - - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) - return err; - jack->jack->private_data = jack; - jack->jack->private_free = conexant_free_jack_priv; - return 0; -} - -static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct conexant_spec *spec = codec->spec; - struct conexant_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int present; - present = snd_hda_jack_detect(codec, nid); - - present = (present) ? jacks->type : 0 ; - - snd_jack_report(jacks->jack, - present); - } - jacks++; - } - } -} - static int conexant_init_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_HDA_INPUT_JACK struct conexant_spec *spec = codec->spec; int i; @@ -459,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec) int err = 0; switch (hv->param ^ AC_USRSP_EN) { case CONEXANT_HP_EVENT: - err = conexant_add_jack(codec, hv->nid, - SND_JACK_HEADPHONE); - conexant_report_jack(codec, hv->nid); + err = snd_hda_input_jack_add(codec, hv->nid, + SND_JACK_HEADPHONE, NULL); + snd_hda_input_jack_report(codec, hv->nid); break; case CXT5051_PORTC_EVENT: case CONEXANT_MIC_EVENT: - err = conexant_add_jack(codec, hv->nid, - SND_JACK_MICROPHONE); - conexant_report_jack(codec, hv->nid); + err = snd_hda_input_jack_add(codec, hv->nid, + SND_JACK_MICROPHONE, NULL); + snd_hda_input_jack_report(codec, hv->nid); break; } if (err < 0) @@ -475,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec) ++hv; } } - return 0; - -} -#else -static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ -} - -static inline int conexant_init_jacks(struct hda_codec *codec) -{ +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -#endif static int conexant_init(struct hda_codec *codec) { @@ -501,18 +428,7 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { -#ifdef CONFIG_SND_HDA_INPUT_JACK - struct conexant_spec *spec = codec->spec; - if (spec->jacks.list) { - struct conexant_jack *jacks = spec->jacks.list; - int i; - for (i = 0; i < spec->jacks.used; i++, jacks++) { - if (jacks->jack) - snd_device_free(codec->bus->card, jacks->jack); - } - snd_array_free(&spec->jacks); - } -#endif + snd_hda_input_jack_free(codec); snd_hda_detach_beep_device(codec); kfree(codec->spec); } @@ -537,13 +453,13 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = { }; #endif -static const char *slave_vols[] = { +static const char * const slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", NULL }; -static const char *slave_sws[] = { +static const char * const slave_sws[] = { "Headphone Playback Switch", "Speaker Playback Switch", NULL @@ -869,16 +785,16 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, } static struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT), HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -910,16 +826,16 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { }; static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { - HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT), HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -947,7 +863,7 @@ static struct hda_verb cxt5045_init_verbs[] = { {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, @@ -960,7 +876,7 @@ static struct hda_verb cxt5045_init_verbs[] = { }; static struct hda_verb cxt5045_benq_init_verbs[] = { - /* Int Mic, Mic */ + /* Internal Mic, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, /* Line In,HP, Amp */ @@ -973,7 +889,7 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, @@ -1134,7 +1050,7 @@ enum { CXT5045_MODELS }; -static const char *cxt5045_models[CXT5045_MODELS] = { +static const char * const cxt5045_models[CXT5045_MODELS] = { [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", @@ -1376,7 +1292,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, static struct snd_kcontrol_new cxt5047_base_mixers[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), @@ -1579,7 +1495,7 @@ enum { CXT5047_MODELS }; -static const char *cxt5047_models[CXT5047_MODELS] = { +static const char * const cxt5047_models[CXT5047_MODELS] = { [CXT5047_LAPTOP] = "laptop", [CXT5047_LAPTOP_HP] = "laptop-hp", [CXT5047_LAPTOP_EAPD] = "laptop-eapd", @@ -1777,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, cxt5051_portc_automic(codec); break; } - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); } static struct snd_kcontrol_new cxt5051_playback_mixers[] = { @@ -1796,8 +1712,8 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = { static struct snd_kcontrol_new cxt5051_capture_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), {} @@ -1806,8 +1722,8 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = { static struct snd_kcontrol_new cxt5051_hp_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), {} }; @@ -1826,8 +1742,8 @@ static struct snd_kcontrol_new cxt5051_f700_mixers[] = { static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), {} }; @@ -1847,7 +1763,7 @@ static struct hda_verb cxt5051_init_verbs[] = { {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, @@ -1874,7 +1790,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, /* SPDIF route: PCM */ @@ -1904,7 +1820,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, @@ -1932,7 +1848,7 @@ static struct hda_verb cxt5051_f700_init_verbs[] = { {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Record selector: Int mic */ + /* Record selector: Internal mic */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, /* SPDIF route: PCM */ @@ -1949,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | event); -#ifdef CONFIG_SND_HDA_INPUT_JACK - conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); - conexant_report_jack(codec, nid); -#endif + snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL); + snd_hda_input_jack_report(codec, nid); } static struct hda_verb cxt5051_ideapad_init_verbs[] = { @@ -1995,7 +1909,7 @@ enum { CXT5051_MODELS }; -static const char *cxt5051_models[CXT5051_MODELS] = { +static const char *const cxt5051_models[CXT5051_MODELS] = { [CXT5051_LAPTOP] = "laptop", [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", @@ -2100,7 +2014,7 @@ static int patch_cxt5051(struct hda_codec *codec) static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; -#define CXT5066_SPDIF_OUT 0x21 +static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; /* OLPC's microphone port is DC coupled for use with external sensors, * therefore we use a 50% mic bias in order to center the input signal with @@ -2111,25 +2025,35 @@ static struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; +#define HP_PRESENT_PORT_A (1 << 0) +#define HP_PRESENT_PORT_D (1 << 1) +#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) +#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) + static void cxt5066_update_speaker(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; unsigned int pinctl; - snd_printdd("CXT5066: update speaker, hp_present=%d\n", - spec->hp_present); + snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", + spec->hp_present, spec->cur_eapd); /* Port A (HP) */ - pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; + pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); /* Port D (HP/LO) */ - pinctl = ((spec->hp_present & 2) && spec->cur_eapd) - ? spec->port_d_mode : 0; - /* Mute if Port A is connected on Thinkpad */ - if (spec->thinkpad && (spec->hp_present & 1)) - pinctl = 0; + pinctl = spec->cur_eapd ? spec->port_d_mode : 0; + if (spec->dell_automute || spec->thinkpad) { + /* Mute if Port A is connected */ + if (hp_port_a_present(spec)) + pinctl = 0; + } else { + /* Thinkpad/Dell doesn't give pin-D status */ + if (!hp_port_d_present(spec)) + pinctl = 0; + } snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); @@ -2137,14 +2061,6 @@ static void cxt5066_update_speaker(struct hda_codec *codec) pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); - - if (spec->dell_automute) { - /* DELL AIO Port Rule: PortA > PortD > IntSpk */ - pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) - ? PIN_OUT : 0; - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); - } } /* turn on/off EAPD (+ mute HP) as a master switch */ @@ -2310,6 +2226,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) } } + +/* toggle input of built-in digital mic and mic jack appropriately */ +static void cxt5066_asus_automic(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_jack_detect(codec, 0x1b); + snd_printdd("CXT5066: external microphone present=%d\n", present); + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, + present ? 1 : 0); +} + + /* toggle input of built-in digital mic and mic jack appropriately */ static void cxt5066_hp_laptop_automic(struct hda_codec *codec) { @@ -2378,86 +2307,62 @@ static void cxt5066_hp_automute(struct hda_codec *codec) /* Port D */ portD = snd_hda_jack_detect(codec, 0x1c); - spec->hp_present = !!(portA); - spec->hp_present |= portD ? 2 : 0; + spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; + spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", portA, portD, spec->hp_present); cxt5066_update_speaker(codec); } -/* unsolicited event for jack sensing */ -static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) +/* Dispatch the right mic autoswitch function */ +static void cxt5066_automic(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - /* ignore mic events in DC mode; we're always using the jack */ - if (!spec->dc_enable) - cxt5066_olpc_automic(codec); - break; - } -} -/* unsolicited event for jack sensing */ -static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) -{ - snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: + if (spec->dell_vostro) cxt5066_vostro_automic(codec); - break; - } -} - -/* unsolicited event for jack sensing */ -static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) -{ - snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: + else if (spec->ideapad) cxt5066_ideapad_automic(codec); - break; - } + else if (spec->thinkpad) + cxt5066_thinkpad_automic(codec); + else if (spec->hp_laptop) + cxt5066_hp_laptop_automic(codec); + else if (spec->asus) + cxt5066_asus_automic(codec); } /* unsolicited event for jack sensing */ -static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) +static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) { - snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); + struct conexant_spec *spec = codec->spec; + snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); switch (res >> 26) { case CONEXANT_HP_EVENT: cxt5066_hp_automute(codec); break; case CONEXANT_MIC_EVENT: - cxt5066_hp_laptop_automic(codec); + /* ignore mic events in DC mode; we're always using the jack */ + if (!spec->dc_enable) + cxt5066_olpc_automic(codec); break; } } /* unsolicited event for jack sensing */ -static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) +static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) { - snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); + snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); switch (res >> 26) { case CONEXANT_HP_EVENT: cxt5066_hp_automute(codec); break; case CONEXANT_MIC_EVENT: - cxt5066_thinkpad_automic(codec); + cxt5066_automic(codec); break; } } + static const struct hda_input_mux cxt5066_analog_mic_boost = { .num_items = 5, .items = { @@ -2631,6 +2536,27 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) spec->recording = 0; } +static void conexant_check_dig_outs(struct hda_codec *codec, + hda_nid_t *dig_pins, + int num_pins) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; + int i; + + for (i = 0; i < num_pins; i++, dig_pins++) { + unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) + continue; + if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) + continue; + if (spec->slave_dig_outs[0]) + nid_loc++; + else + nid_loc = spec->slave_dig_outs; + } +} + static struct hda_input_mux cxt5066_capture_source = { .num_items = 4, .items = { @@ -2727,7 +2653,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Int Mic Boost Capture Enum", + .name = "Internal Mic Boost Capture Enum", .info = cxt5066_mic_boost_mux_enum_info, .get = cxt5066_mic_boost_mux_enum_get, .put = cxt5066_mic_boost_mux_enum_put, @@ -2953,7 +2879,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ /* EAPD */ {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ @@ -3008,7 +2934,7 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* internal microphone */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ /* EAPD */ {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ @@ -3037,20 +2963,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: init\n"); conexant_init(codec); if (codec->patch_ops.unsol_event) { cxt5066_hp_automute(codec); - if (spec->dell_vostro) - cxt5066_vostro_automic(codec); - else if (spec->ideapad) - cxt5066_ideapad_automic(codec); - else if (spec->thinkpad) - cxt5066_thinkpad_automic(codec); - else if (spec->hp_laptop) - cxt5066_hp_laptop_automic(codec); + cxt5066_automic(codec); } cxt5066_set_mic_boost(codec); return 0; @@ -3078,29 +2995,35 @@ enum { CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ + CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ CXT5066_HP_LAPTOP, /* HP Laptop */ CXT5066_MODELS }; -static const char *cxt5066_models[CXT5066_MODELS] = { +static const char * const cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", [CXT5066_DELL_VOSTRO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", + [CXT5066_ASUS] = "asus", [CXT5066_HP_LAPTOP] = "hp-laptop", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", - CXT5066_DELL_LAPTOP), + SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), + SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), + SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), @@ -3108,15 +3031,13 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ {} }; @@ -3137,7 +3058,8 @@ static int patch_cxt5066(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); spec->multiout.dac_nids = cxt5066_dac_nids; - spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; + conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, + ARRAY_SIZE(cxt5066_digout_pin_nids)); spec->num_adc_nids = 1; spec->adc_nids = cxt5066_adc_nids; spec->capsrc_nids = cxt5066_capsrc_nids; @@ -3171,17 +3093,20 @@ static int patch_cxt5066(struct hda_codec *codec) spec->num_init_verbs++; spec->dell_automute = 1; break; + case CXT5066_ASUS: case CXT5066_HP_LAPTOP: codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; + codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_hp_laptop; spec->num_init_verbs++; - spec->hp_laptop = 1; + spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; + spec->asus = board_config == CXT5066_ASUS; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; spec->mixers[spec->num_mixers++] = cxt5066_mixers; /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; + if (board_config == CXT5066_HP_LAPTOP) + spec->multiout.dig_out_nid = 0; /* input source automatically selected */ spec->input_mux = NULL; spec->port_d_mode = 0; @@ -3211,7 +3136,7 @@ static int patch_cxt5066(struct hda_codec *codec) break; case CXT5066_DELL_VOSTRO: codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_vostro_event; + codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->init_verbs[0] = cxt5066_init_verbs_vostro; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; @@ -3228,7 +3153,7 @@ static int patch_cxt5066(struct hda_codec *codec) break; case CXT5066_IDEAPAD: codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_ideapad_event; + codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->init_verbs[0] = cxt5066_init_verbs_ideapad; @@ -3244,7 +3169,7 @@ static int patch_cxt5066(struct hda_codec *codec) break; case CXT5066_THINKPAD: codec->patch_ops.init = cxt5066_init; - codec->patch_ops.unsol_event = cxt5066_thinkpad_event; + codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; @@ -3393,7 +3318,7 @@ static void cx_auto_parse_output(struct hda_codec *codec) } } spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.max_channels = nums * 2; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; if (cfg->hp_outs > 0) spec->auto_mute = 1; @@ -3421,6 +3346,9 @@ static void cx_auto_hp_automute(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, present ? 0 : PIN_OUT); } + for (i = 0; !present && i < cfg->line_outs; i++) + if (snd_hda_jack_detect(codec, cfg->line_out_pins[i])) + present = 1; for (i = 0; i < cfg->speaker_outs; i++) { snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, @@ -3455,11 +3383,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) switch (res >> 26) { case CONEXANT_HP_EVENT: cx_auto_hp_automute(codec); - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); break; case CONEXANT_MIC_EVENT: cx_auto_automic(codec); - conexant_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); break; } } @@ -3709,9 +3637,9 @@ static int cx_auto_init(struct hda_codec *codec) return 0; } -static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, +static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, const char *dir, int cidx, - hda_nid_t nid, int hda_dir) + hda_nid_t nid, int hda_dir, int amp_idx) { static char name[32]; static struct snd_kcontrol_new knew[] = { @@ -3723,7 +3651,8 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, for (i = 0; i < 2; i++) { struct snd_kcontrol *kctl; - knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir); + knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, + hda_dir); knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; knew[i].index = cidx; snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); @@ -3739,6 +3668,9 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, return 0; } +#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ + cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) + #define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) @@ -3747,7 +3679,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; int i, err; int num_line = 0, num_hp = 0, num_spk = 0; - static const char *texts[3] = { "Front", "Surround", "CLFE" }; + static const char * const texts[3] = { "Front", "Surround", "CLFE" }; if (spec->dac_info_filled == 1) return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, @@ -3788,29 +3720,60 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; static const char *prev_label; - int i, err, cidx; + int i, err, cidx, conn_len; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + + int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ + int adc_nid = spec->adc_nids[0]; + + conn_len = snd_hda_get_connections(codec, adc_nid, conn, + HDA_MAX_CONNECTIONS); + if (conn_len < 0) + return conn_len; + + multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; + if (!multi_adc_volume) { + err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, + HDA_INPUT); + if (err < 0) + return err; + } - err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0], - HDA_INPUT); - if (err < 0) - return err; prev_label = NULL; cidx = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; const char *label; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + int j; + int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; + if (!pin_amp && !multi_adc_volume) continue; + label = hda_get_autocfg_input_label(codec, cfg, i); if (label == prev_label) cidx++; else cidx = 0; prev_label = label; - err = cx_auto_add_volume(codec, label, " Capture", cidx, - nid, HDA_INPUT); - if (err < 0) - return err; + + if (pin_amp) { + err = cx_auto_add_volume(codec, label, " Boost", cidx, + nid, HDA_INPUT); + if (err < 0) + return err; + } + + if (!multi_adc_volume) + continue; + for (j = 0; j < conn_len; j++) { + if (conn[j] == nid) { + err = cx_auto_add_volume_idx(codec, label, + " Capture", cidx, adc_nid, HDA_INPUT, j); + if (err < 0) + return err; + break; + } + } } return 0; } @@ -3882,6 +3845,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5066 }, { .id = 0x14f15069, .name = "CX20585", .patch = patch_cxt5066 }, + { .id = 0x14f1506e, .name = "CX20590", + .patch = patch_cxt5066 }, { .id = 0x14f15097, .name = "CX20631", .patch = patch_conexant_auto }, { .id = 0x14f15098, .name = "CX20632", @@ -3908,6 +3873,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066"); MODULE_ALIAS("snd-hda-codec-id:14f15067"); MODULE_ALIAS("snd-hda-codec-id:14f15068"); MODULE_ALIAS("snd-hda-codec-id:14f15069"); +MODULE_ALIAS("snd-hda-codec-id:14f1506e"); MODULE_ALIAS("snd-hda-codec-id:14f15097"); MODULE_ALIAS("snd-hda-codec-id:14f15098"); MODULE_ALIAS("snd-hda-codec-id:14f150a1"); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d3e49aa5b9e..715615a88a8 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -31,10 +31,15 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/moduleparam.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +static bool static_hdmi_pcm; +module_param(static_hdmi_pcm, bool, 0644); +MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); + /* * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device * could support two independent pipes, each of them can be connected to one or @@ -105,6 +110,12 @@ struct dp_audio_infoframe { u8 LFEPBL01_LSV36_DM_INH7; }; +union audio_infoframe { + struct hdmi_audio_infoframe hdmi; + struct dp_audio_infoframe dp; + u8 bytes[0]; +}; + /* * CEA speaker placement: * @@ -615,8 +626,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, int channels = substream->runtime->channels; int ca; int i; - u8 ai[max(sizeof(struct hdmi_audio_infoframe), - sizeof(struct dp_audio_infoframe))]; + union audio_infoframe ai; ca = hdmi_channel_allocation(codec, nid, channels); @@ -628,24 +638,24 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, pin_nid = spec->pin[i]; - memset(ai, 0, sizeof(ai)); + memset(&ai, 0, sizeof(ai)); if (spec->sink_eld[i].conn_type == 0) { /* HDMI */ - struct hdmi_audio_infoframe *hdmi_ai; + struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; - hdmi_ai = (struct hdmi_audio_infoframe *)ai; hdmi_ai->type = 0x84; hdmi_ai->ver = 0x01; hdmi_ai->len = 0x0a; hdmi_ai->CC02_CT47 = channels - 1; + hdmi_ai->CA = ca; hdmi_checksum_audio_infoframe(hdmi_ai); } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */ - struct dp_audio_infoframe *dp_ai; + struct dp_audio_infoframe *dp_ai = &ai.dp; - dp_ai = (struct dp_audio_infoframe *)ai; dp_ai->type = 0x84; dp_ai->len = 0x1b; dp_ai->ver = 0x11 << 2; dp_ai->CC02_CT47 = channels - 1; + dp_ai->CA = ca; } else { snd_printd("HDMI: unknown connection type at pin %d\n", pin_nid); @@ -657,7 +667,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, * sizeof(*dp_ai) to avoid partial match/update problems when * the user switches between HDMI/DP monitors. */ - if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) { + if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, + sizeof(ai))) { snd_printdd("hdmi_setup_audio_infoframe: " "cvt=%d pin=%d channels=%d\n", nid, pin_nid, @@ -665,7 +676,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, hdmi_setup_channel_mapping(codec, pin_nid, ca); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, - ai, sizeof(ai)); + ai.bytes, sizeof(ai)); hdmi_start_infoframe_trans(codec, pin_nid); } } @@ -812,6 +823,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld; struct hda_pcm_stream *codec_pars; + struct snd_pcm_runtime *runtime = substream->runtime; unsigned int idx; for (idx = 0; idx < spec->num_cvts; idx++) @@ -827,19 +839,26 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, *codec_pars = *hinfo; eld = &spec->sink_eld[idx]; - if (eld->sad_count > 0) { + if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) { hdmi_eld_update_pcm_info(eld, hinfo, codec_pars); if (hinfo->channels_min > hinfo->channels_max || !hinfo->rates || !hinfo->formats) return -ENODEV; } else { /* fallback to the codec default */ - hinfo->channels_min = codec_pars->channels_min; hinfo->channels_max = codec_pars->channels_max; hinfo->rates = codec_pars->rates; hinfo->formats = codec_pars->formats; hinfo->maxbps = codec_pars->maxbps; } + /* store the updated parameters */ + runtime->hw.channels_min = hinfo->channels_min; + runtime->hw.channels_max = hinfo->channels_max; + runtime->hw.formats = hinfo->formats; + runtime->hw.rates = hinfo->rates; + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); return 0; } @@ -905,23 +924,28 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) spec->pin[spec->num_pins] = pin_nid; spec->num_pins++; - /* - * It is assumed that converter nodes come first in the node list and - * hence have been registered and usable now. - */ return hdmi_read_pin_conn(codec, pin_nid); } static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) { + int i, found_pin = 0; struct hdmi_spec *spec = codec->spec; - if (spec->num_cvts >= MAX_HDMI_CVTS) { - snd_printk(KERN_WARNING - "HDMI: no space for converter %d\n", nid); - return -E2BIG; + for (i = 0; i < spec->num_pins; i++) + if (nid == spec->pin_cvt[i]) { + found_pin = 1; + break; + } + + if (!found_pin) { + snd_printdd("HDMI: Skipping node %d (no connection)\n", nid); + return -EINVAL; } + if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) + return -E2BIG; + spec->cvt[spec->num_cvts] = nid; spec->num_cvts++; @@ -932,6 +956,8 @@ static int hdmi_parse_codec(struct hda_codec *codec) { hda_nid_t nid; int i, nodes; + int num_tmp_cvts = 0; + hda_nid_t tmp_cvt[MAX_HDMI_CVTS]; nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (!nid || nodes < 0) { @@ -942,6 +968,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) for (i = 0; i < nodes; i++, nid++) { unsigned int caps; unsigned int type; + unsigned int config; caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); type = get_wcaps_type(caps); @@ -951,17 +978,32 @@ static int hdmi_parse_codec(struct hda_codec *codec) switch (type) { case AC_WID_AUD_OUT: - hdmi_add_cvt(codec, nid); + if (num_tmp_cvts >= MAX_HDMI_CVTS) { + snd_printk(KERN_WARNING + "HDMI: no space for converter %d\n", nid); + continue; + } + tmp_cvt[num_tmp_cvts] = nid; + num_tmp_cvts++; break; case AC_WID_PIN: caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) continue; + + config = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) + continue; + hdmi_add_pin(codec, nid); break; } } + for (i = 0; i < num_tmp_cvts; i++) + hdmi_add_cvt(codec, tmp_cvt[i]); + /* * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event * can be lost and presence sense verb will become inaccurate if the @@ -1166,11 +1208,56 @@ static int nvhdmi_7x_init(struct hda_codec *codec) return 0; } +static unsigned int channels_2_6_8[] = { + 2, 6, 8 +}; + +static unsigned int channels_2_8[] = { + 2, 8 +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = { + .count = ARRAY_SIZE(channels_2_6_8), + .list = channels_2_6_8, + .mask = 0, +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { + .count = ARRAY_SIZE(channels_2_8), + .list = channels_2_8, + .mask = 0, +}; + static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; + struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL; + + switch (codec->preset->id) { + case 0x10de0002: + case 0x10de0003: + case 0x10de0005: + case 0x10de0006: + hw_constraints_channels = &hw_constraints_2_8_channels; + break; + case 0x10de0007: + hw_constraints_channels = &hw_constraints_2_6_8_channels; + break; + default: + break; + } + + if (hw_constraints_channels != NULL) { + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + hw_constraints_channels); + } else { + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + } + return snd_hda_multi_out_dig_open(codec, &spec->multiout); } @@ -1193,6 +1280,39 @@ static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo, stream_tag, format, substream); } +static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec, + int channels) +{ + unsigned int chanmask; + int chan = channels ? (channels - 1) : 1; + + switch (channels) { + default: + case 0: + case 2: + chanmask = 0x00; + break; + case 4: + chanmask = 0x08; + break; + case 6: + chanmask = 0x0b; + break; + case 8: + chanmask = 0x13; + break; + } + + /* Set the audio infoframe channel allocation and checksum fields. The + * channel count is computed implicitly by the hardware. */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Channel_Allocation, chanmask); + + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Info_Frame_Checksum, + (0x71 - chan - chanmask)); +} + static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -1211,6 +1331,10 @@ static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, AC_VERB_SET_STREAM_FORMAT, 0); } + /* The audio hardware sends a channel count of 0x7 (8ch) when all the + * streams are disabled. */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + return snd_hda_multi_out_dig_close(codec, &spec->multiout); } @@ -1221,37 +1345,16 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { int chs; - unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; + unsigned int dataDCC1, dataDCC2, channel_id; int i; mutex_lock(&codec->spdif_mutex); chs = substream->runtime->channels; - chan = chs ? (chs - 1) : 1; - switch (chs) { - default: - case 0: - case 2: - chanmask = 0x00; - break; - case 4: - chanmask = 0x08; - break; - case 6: - chanmask = 0x0b; - break; - case 8: - chanmask = 0x13; - break; - } dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; dataDCC2 = 0x2; - /* set the Audio InforFrame Channel Allocation */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Channel_Allocation, chanmask); - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, @@ -1326,10 +1429,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, } } - /* set the Audio Info Frame Checksum */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Info_Frame_Checksum, - (0x71 - chan - chanmask)); + nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs); mutex_unlock(&codec->spdif_mutex); return 0; @@ -1425,6 +1525,11 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) spec->multiout.max_channels = 8; spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x; codec->patch_ops = nvhdmi_patch_ops_8ch_7x; + + /* Initialize the audio infoframe channel mask and checksum to something + * valid */ + nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8); + return 0; } @@ -1533,7 +1638,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, -{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, +{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, @@ -1551,6 +1656,9 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +/* 17 is known to be absent */ { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, @@ -1593,6 +1701,8 @@ MODULE_ALIAS("snd-hda-codec-id:10de0011"); MODULE_ALIAS("snd-hda-codec-id:10de0012"); MODULE_ALIAS("snd-hda-codec-id:10de0013"); MODULE_ALIAS("snd-hda-codec-id:10de0014"); +MODULE_ALIAS("snd-hda-codec-id:10de0015"); +MODULE_ALIAS("snd-hda-codec-id:10de0016"); MODULE_ALIAS("snd-hda-codec-id:10de0018"); MODULE_ALIAS("snd-hda-codec-id:10de0019"); MODULE_ALIAS("snd-hda-codec-id:10de001a"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8fddc9d0872..c82979a8cd0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -231,7 +231,6 @@ enum { ALC888_ACER_ASPIRE_8930G, ALC888_ACER_ASPIRE_7730G, ALC883_MEDION, - ALC883_MEDION_MD2, ALC883_MEDION_WIM2160, ALC883_LAPTOP_EAPD, ALC883_LENOVO_101E_2ch, @@ -283,12 +282,6 @@ struct alc_mic_route { unsigned char amix_idx; }; -struct alc_jack { - hda_nid_t nid; - int type; - struct snd_jack *jack; -}; - #define MUX_IDX_UNDEF ((unsigned char)-1) struct alc_customize_define { @@ -304,6 +297,8 @@ struct alc_customize_define { unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ }; +struct alc_fixup; + struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -365,9 +360,6 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - /* jack detection */ - struct snd_array jacks; - /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct alc_customize_define cdefine; @@ -393,6 +385,7 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int single_input_src:1; int init_amp; int codec_variant; /* flag for other variants */ @@ -405,6 +398,11 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; + + /* fix-up list */ + int fixup_id; + const struct alc_fixup *fixup_list; + const char *fixup_name; }; /* @@ -551,7 +549,7 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, /* * Control the mode of pin widget settings via the mixer. "pc" is used - * instead of "%" to avoid consequences of accidently treating the % as + * instead of "%" to avoid consequences of accidentally treating the % as * being part of a format specifier. Maximum allowed length of a value is * 63 characters plus NULL terminator. * @@ -1026,94 +1024,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void alc_free_jack_priv(struct snd_jack *jack) -{ - struct alc_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} - -static int alc_add_jack(struct hda_codec *codec, - hda_nid_t nid, int type) -{ - struct alc_spec *spec; - struct alc_jack *jack; - const char *name; - int err; - - spec = codec->spec; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - if (!jack) - return -ENOMEM; - - jack->nid = nid; - jack->type = type; - name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; - - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) - return err; - jack->jack->private_data = jack; - jack->jack->private_free = alc_free_jack_priv; - return 0; -} - -static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - struct alc_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int present; - present = snd_hda_jack_detect(codec, nid); - - present = (present) ? jacks->type : 0; - - snd_jack_report(jacks->jack, present); - } - jacks++; - } - } -} - static int alc_init_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_HDA_INPUT_JACK struct alc_spec *spec = codec->spec; int err; unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int mic_nid = spec->ext_mic.pin; if (hp_nid) { - err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE); + err = snd_hda_input_jack_add(codec, hp_nid, + SND_JACK_HEADPHONE, NULL); if (err < 0) return err; - alc_report_jack(codec, hp_nid); + snd_hda_input_jack_report(codec, hp_nid); } if (mic_nid) { - err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE); + err = snd_hda_input_jack_add(codec, mic_nid, + SND_JACK_MICROPHONE, NULL); if (err < 0) return err; - alc_report_jack(codec, mic_nid); + snd_hda_input_jack_report(codec, mic_nid); } - +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } -#else -static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ -} - -static inline int alc_init_jacks(struct hda_codec *codec) -{ - return 0; -} -#endif static void alc_automute_speaker(struct hda_codec *codec, int pinctl) { @@ -1127,11 +1063,8 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl) nid = spec->autocfg.hp_pins[i]; if (!nid) break; - if (snd_hda_jack_detect(codec, nid)) { - spec->jack_present = 1; - break; - } - alc_report_jack(codec, spec->autocfg.hp_pins[i]); + snd_hda_input_jack_report(codec, nid); + spec->jack_present |= snd_hda_jack_detect(codec, nid); } mute = spec->jack_present ? HDA_AMP_MUTE : 0; @@ -1237,7 +1170,7 @@ static void alc_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, alive->mux_idx); } - alc_report_jack(codec, spec->ext_mic.pin); + snd_hda_input_jack_report(codec, spec->ext_mic.pin); /* FIXME: analog mixer */ } @@ -1332,6 +1265,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0660: case 0x10ec0662: case 0x10ec0663: + case 0x10ec0665: case 0x10ec0862: case 0x10ec0889: set_eapd(codec, 0x14, 1); @@ -1356,7 +1290,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0883: case 0x10ec0885: case 0x10ec0887: - case 0x10ec0889: + /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ alc889_coef_init(codec); break; case 0x10ec0888: @@ -1678,48 +1612,139 @@ struct alc_pincfg { u32 val; }; +struct alc_model_fixup { + const int id; + const char *name; +}; + struct alc_fixup { - unsigned int sku; - const struct alc_pincfg *pins; - const struct hda_verb *verbs; + int type; + bool chained; + int chain_id; + union { + unsigned int sku; + const struct alc_pincfg *pins; + const struct hda_verb *verbs; + void (*func)(struct hda_codec *codec, + const struct alc_fixup *fix, + int action); + } v; }; -static void alc_pick_fixup(struct hda_codec *codec, - const struct snd_pci_quirk *quirk, - const struct alc_fixup *fix, - int pre_init) -{ - const struct alc_pincfg *cfg; - struct alc_spec *spec; +enum { + ALC_FIXUP_INVALID, + ALC_FIXUP_SKU, + ALC_FIXUP_PINS, + ALC_FIXUP_VERBS, + ALC_FIXUP_FUNC, +}; - quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (!quirk) - return; - fix += quirk->value; - cfg = fix->pins; - if (pre_init && fix->sku) { +enum { + ALC_FIXUP_ACT_PRE_PROBE, + ALC_FIXUP_ACT_PROBE, + ALC_FIXUP_ACT_INIT, +}; + +static void alc_apply_fixup(struct hda_codec *codec, int action) +{ + struct alc_spec *spec = codec->spec; + int id = spec->fixup_id; #ifdef CONFIG_SND_DEBUG_VERBOSE - snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n", - codec->chip_name, quirk->name); + const char *modelname = spec->fixup_name; #endif - spec = codec->spec; - spec->cdefine.sku_cfg = fix->sku; - spec->cdefine.fixup = 1; + int depth = 0; + + if (!spec->fixup_list) + return; + + while (id >= 0) { + const struct alc_fixup *fix = spec->fixup_list + id; + const struct alc_pincfg *cfg; + + switch (fix->type) { + case ALC_FIXUP_SKU: + if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku) + break;; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply sku override for %s\n", + codec->chip_name, modelname); + spec->cdefine.sku_cfg = fix->v.sku; + spec->cdefine.fixup = 1; + break; + case ALC_FIXUP_PINS: + cfg = fix->v.pins; + if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply pincfg for %s\n", + codec->chip_name, modelname); + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, + cfg->val); + break; + case ALC_FIXUP_VERBS: + if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply fix-verbs for %s\n", + codec->chip_name, modelname); + add_verb(codec->spec, fix->v.verbs); + break; + case ALC_FIXUP_FUNC: + if (!fix->v.func) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply fix-func for %s\n", + codec->chip_name, modelname); + fix->v.func(codec, fix, action); + break; + default: + snd_printk(KERN_ERR "hda_codec: %s: " + "Invalid fixup type %d\n", + codec->chip_name, fix->type); + break; + } + if (!fix->chained) + break; + if (++depth > 10) + break; + id = fix->chain_id; } - if (pre_init && cfg) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n", - codec->chip_name, quirk->name); -#endif - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); +} + +static void alc_pick_fixup(struct hda_codec *codec, + const struct alc_model_fixup *models, + const struct snd_pci_quirk *quirk, + const struct alc_fixup *fixlist) +{ + struct alc_spec *spec = codec->spec; + int id = -1; + const char *name = NULL; + + if (codec->modelname && models) { + while (models->name) { + if (!strcmp(codec->modelname, models->name)) { + id = models->id; + name = models->name; + break; + } + models++; + } } - if (!pre_init && fix->verbs) { + if (id < 0) { + quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); + if (quirk) { + id = quirk->value; #ifdef CONFIG_SND_DEBUG_VERBOSE - snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n", - codec->chip_name, quirk->name); + name = quirk->name; #endif - add_verb(codec->spec, fix->verbs); + } + } + + spec->fixup_id = id; + if (id >= 0) { + spec->fixup_list = fixlist; + spec->fixup_name = name; } } @@ -1981,6 +2006,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; @@ -2120,17 +2146,17 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { { .num_items = 5, .items = { - { "Ext Mic", 0x0 }, + { "Mic", 0x0 }, { "Line In", 0x2 }, { "CD", 0x4 }, { "Input Mix", 0xa }, - { "Int Mic", 0xb }, + { "Internal Mic", 0xb }, }, }, { .num_items = 4, .items = { - { "Ext Mic", 0x0 }, + { "Mic", 0x0 }, { "Line In", 0x2 }, { "CD", 0x4 }, { "Input Mix", 0xa }, @@ -2187,7 +2213,29 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -2205,7 +2253,7 @@ static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -2796,10 +2844,10 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, 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, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -2820,7 +2868,7 @@ static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { /* * slave controls for virtual master */ -static const char *alc_slave_vols[] = { +static const char * const alc_slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -2834,7 +2882,7 @@ static const char *alc_slave_vols[] = { NULL, }; -static const char *alc_slave_sws[] = { +static const char * const alc_slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -3307,7 +3355,7 @@ static struct hda_verb alc880_beep_init_verbs[] = { }; /* auto-toggle front mic */ -static void alc880_uniwill_mic_automute(struct hda_codec *codec) +static void alc88x_simple_mic_automute(struct hda_codec *codec) { unsigned int present; unsigned char bits; @@ -3329,7 +3377,7 @@ static void alc880_uniwill_setup(struct hda_codec *codec) static void alc880_uniwill_init_hook(struct hda_codec *codec) { alc_automute_amp(codec); - alc880_uniwill_mic_automute(codec); + alc88x_simple_mic_automute(codec); } static void alc880_uniwill_unsol_event(struct hda_codec *codec, @@ -3340,7 +3388,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, */ switch (res >> 28) { case ALC880_MIC_EVENT: - alc880_uniwill_mic_automute(codec); + alc88x_simple_mic_automute(codec); break; default: alc_automute_amp_unsol_event(codec, res); @@ -3801,6 +3849,8 @@ static struct hda_amp_list alc880_lg_loopbacks[] = { * Common callbacks */ +static void alc_init_special_input_src(struct hda_codec *codec); + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -3811,10 +3861,13 @@ static int alc_init(struct hda_codec *codec) for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); + alc_init_special_input_src(codec); if (spec->init_hook) spec->init_hook(codec); + alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); + hda_call_check_power_status(codec, 0x01); return 0; } @@ -4164,6 +4217,7 @@ static void alc_free(struct hda_codec *codec) return; alc_shutup(codec); + snd_hda_input_jack_free(codec); alc_free_kctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); @@ -4187,6 +4241,7 @@ static void alc_power_eapd(struct hda_codec *codec) case 0x10ec0660: case 0x10ec0662: case 0x10ec0663: + case 0x10ec0665: case 0x10ec0862: case 0x10ec0889: set_eapd(codec, 0x14, 0); @@ -4513,7 +4568,7 @@ static struct hda_verb alc880_test_init_verbs[] = { /* */ -static const char *alc880_models[ALC880_MODEL_LAST] = { +static const char * const alc880_models[ALC880_MODEL_LAST] = { [ALC880_3ST] = "3stack", [ALC880_TCL_S700] = "tcl", [ALC880_3ST_DIG] = "3stack-digout", @@ -4582,7 +4637,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), @@ -4595,6 +4650,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), @@ -5022,13 +5078,35 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, return 0; } +static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, + bool can_be_master) +{ + if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master) + return "Master"; + + switch (cfg->line_out_type) { + case AUTO_PIN_SPEAKER_OUT: + if (cfg->line_outs == 1) + return "Speaker"; + break; + case AUTO_PIN_HP_OUT: + return "Headphone"; + default: + if (cfg->line_outs == 1) + return "PCM"; + break; + } + return NULL; +} + /* add playback controls from the parsed DAC table */ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - static const char *chname[4] = { + static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + const char *pfx = alc_get_line_out_pfx(cfg, false); hda_nid_t nid; int i, err; @@ -5036,7 +5114,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, if (!spec->multiout.dac_nids[i]) continue; nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); - if (i == 2) { + if (!pfx && i == 2) { /* Center/LFE */ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Center", @@ -5063,18 +5141,20 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, if (err < 0) return err; } else { - const char *pfx; - if (cfg->line_outs == 1 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - else - pfx = chname[i]; - err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); if (err < 0) @@ -5154,7 +5234,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx, type, type_idx = 0; + int i, err, idx, type_idx = 0; + const char *prev_label = NULL; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t pin; @@ -5164,12 +5245,13 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, if (!alc_is_input_pin(codec, pin)) continue; - type = cfg->inputs[i].type; - if (i > 0 && type == cfg->inputs[i - 1].type) + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) type_idx++; else type_idx = 0; - label = hda_get_autocfg_input_label(codec, cfg, i); + prev_label = label; + if (mixer) { idx = get_connection_index(codec, mixer, pin); if (idx >= 0) { @@ -5443,6 +5525,7 @@ static void fixup_single_adc(struct hda_codec *codec) spec->capsrc_nids += i; spec->adc_nids += i; spec->num_adc_nids = 1; + spec->single_input_src = 1; } } @@ -5454,6 +5537,16 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) init_capsrc_for_pin(codec, spec->int_mic.pin); } +/* initialize some special cases for input sources */ +static void alc_init_special_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + if (spec->dual_adc_switch) + fixup_dual_adc_switch(codec); + else if (spec->single_input_src) + init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin); +} + static void set_capture_mixer(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -5469,7 +5562,7 @@ static void set_capture_mixer(struct hda_codec *codec) int mux = 0; int num_adcs = spec->num_adc_nids; if (spec->dual_adc_switch) - fixup_dual_adc_switch(codec); + num_adcs = 1; else if (spec->auto_mic) fixup_automic_adc(codec); else if (spec->input_mux) { @@ -5478,8 +5571,6 @@ static void set_capture_mixer(struct hda_codec *codec) else if (spec->input_mux->num_items == 1) fixup_single_adc(codec); } - if (spec->dual_adc_switch) - num_adcs = 1; spec->cap_mixer = caps[mux][num_adcs - 1]; } } @@ -5554,6 +5645,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, static struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -7022,7 +7114,8 @@ enum { static const struct alc_fixup alc260_fixups[] = { [PINFIX_HP_DC5750] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x11, 0x90130110 }, /* speaker */ { } } @@ -7037,7 +7130,7 @@ static struct snd_pci_quirk alc260_fixup_tbl[] = { /* * ALC260 configurations */ -static const char *alc260_models[ALC260_MODEL_LAST] = { +static const char * const alc260_models[ALC260_MODEL_LAST] = { [ALC260_BASIC] = "basic", [ALC260_HP] = "hp", [ALC260_HP_3013] = "hp-3013", @@ -7233,8 +7326,10 @@ static int patch_alc260(struct hda_codec *codec) board_config = ALC260_AUTO; } - if (board_config == ALC260_AUTO) - alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1); + if (board_config == ALC260_AUTO) { + alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } if (board_config == ALC260_AUTO) { /* automatic parse from the BIOS config */ @@ -7282,8 +7377,7 @@ static int patch_alc260(struct hda_codec *codec) set_capture_mixer(codec); set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); - if (board_config == ALC260_AUTO) - alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); spec->vmaster_nid = 0x08; @@ -7405,7 +7499,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { .num_items = 4, .items = { { "Mic", 0x0 }, - { "Int Mic", 0x1 }, + { "Internal Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, }, @@ -7415,7 +7509,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { .num_items = 2, .items = { { "Mic", 0x0 }, - { "Int Mic", 0x1 }, + { "Internal Mic", 0x1 }, }, }; @@ -7850,10 +7944,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -7877,8 +7971,8 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), { } /* end */ }; @@ -7895,8 +7989,8 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), { } /* end */ }; @@ -7911,7 +8005,7 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = { HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), { } /* end */ }; @@ -7930,7 +8024,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -7945,10 +8039,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -7968,7 +8062,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; @@ -7981,7 +8075,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -8762,10 +8856,10 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8776,11 +8870,11 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8790,11 +8884,11 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8807,10 +8901,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8830,10 +8924,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8854,10 +8948,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -8878,10 +8972,10 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -8901,10 +8995,10 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8925,7 +9019,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -8938,20 +9032,20 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8962,7 +9056,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8975,21 +9069,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -9036,7 +9117,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -9049,7 +9130,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -9071,10 +9152,10 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -9095,8 +9176,8 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = { HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), /* Boost mixers */ - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), /* Input mixers */ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), @@ -9110,7 +9191,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = { HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -9140,7 +9221,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), { } /* end */ }; @@ -9181,16 +9262,6 @@ static void alc883_mitac_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x17; } -/* auto-toggle front mic */ -/* -static void alc883_mitac_mic_automute(struct hda_codec *codec) -{ - unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); -} -*/ - static struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -9434,18 +9505,8 @@ static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, alc888_lenovo_ms7195_rca_automute(codec); } -static struct hda_verb alc883_medion_md2_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_setup(struct hda_codec *codec) +static void alc883_lenovo_nb0763_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -9457,15 +9518,6 @@ static void alc883_medion_md2_setup(struct hda_codec *codec) #define alc883_targa_init_hook alc882_targa_init_hook #define alc883_targa_unsol_event alc882_targa_unsol_event -static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x18); - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - static void alc883_clevo_m720_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -9477,7 +9529,7 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec) static void alc883_clevo_m720_init_hook(struct hda_codec *codec) { alc_automute_amp(codec); - alc883_clevo_m720_mic_automute(codec); + alc88x_simple_mic_automute(codec); } static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, @@ -9485,7 +9537,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, { switch (res >> 26) { case ALC880_MIC_EVENT: - alc883_clevo_m720_mic_automute(codec); + alc88x_simple_mic_automute(codec); break; default: alc_automute_amp_unsol_event(codec, res); @@ -9701,7 +9753,7 @@ static hda_nid_t alc1200_slave_dig_outs[] = { /* * configuration and preset */ -static const char *alc882_models[ALC882_MODEL_LAST] = { +static const char * const alc882_models[ALC882_MODEL_LAST] = { [ALC882_3ST_DIG] = "3stack-dig", [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", @@ -9730,7 +9782,6 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", [ALC883_MEDION] = "medion", - [ALC883_MEDION_MD2] = "medion-md2", [ALC883_MEDION_WIM2160] = "medion-wim2160", [ALC883_LAPTOP_EAPD] = "laptop-eapd", [ALC883_LENOVO_101E_2ch] = "lenovo-101e", @@ -9786,7 +9837,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), - SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), @@ -10278,7 +10329,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc_automute_amp, }, [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_base_mixer, + .mixers = { alc888_acer_aspire_4930g_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, alc888_acer_aspire_4930g_verbs }, @@ -10378,19 +10429,6 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, }, - [ALC883_MEDION_MD2] = { - .mixers = { alc883_medion_md2_mixer}, - .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs}, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_medion_md2_setup, - .init_hook = alc_automute_amp, - }, [ALC883_MEDION_WIM2160] = { .mixers = { alc883_medion_wim2160_mixer }, .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs }, @@ -10467,7 +10505,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_medion_md2_setup, + .setup = alc883_lenovo_nb0763_setup, .init_hook = alc_automute_amp, }, [ALC888_LENOVO_MS7195_DIG] = { @@ -10660,32 +10698,45 @@ static struct alc_config_preset alc882_presets[] = { */ enum { PINFIX_ABIT_AW9D_MAX, + PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, }; static const struct alc_fixup alc882_fixups[] = { [PINFIX_ABIT_AW9D_MAX] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x15, 0x01080104 }, /* side */ { 0x16, 0x01011012 }, /* rear */ { 0x17, 0x01016011 }, /* clfe */ { } } }, + [PINFIX_LENOVO_Y530] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x15, 0x99130112 }, /* rear int speakers */ + { 0x16, 0x99130111 }, /* subwoofer */ + { } + } + }, [PINFIX_PB_M5210] = { - .verbs = (const struct hda_verb[]) { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, {} } }, [PINFIX_ACER_ASPIRE_7736] = { - .sku = ALC_FIXUP_SKU_IGNORE, + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, }, }; static struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210), + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), {} @@ -10738,23 +10789,28 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin, dac; int i; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - pin = spec->autocfg.hp_pins[i]; - if (!pin) - break; - dac = spec->multiout.hp_nid; - if (!dac) - dac = spec->multiout.dac_nids[0]; /* to front */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + pin = spec->autocfg.hp_pins[i]; + if (!pin) + break; + dac = spec->multiout.hp_nid; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); + } } - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - pin = spec->autocfg.speaker_pins[i]; - if (!pin) - break; - dac = spec->multiout.extra_out_nid[0]; - if (!dac) - dac = spec->multiout.dac_nids[0]; /* to front */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + pin = spec->autocfg.speaker_pins[i]; + if (!pin) + break; + dac = spec->multiout.extra_out_nid[0]; + if (!dac) + dac = spec->multiout.dac_nids[0]; /* to front */ + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); + } } } @@ -10830,17 +10886,29 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int i, err; + int type_idx = 0; hda_nid_t nid; + const char *prev_label = NULL; for (i = 0; i < cfg->num_inputs; i++) { if (cfg->inputs[i].type > AUTO_PIN_MIC) break; nid = cfg->inputs[i].pin; if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char label[32]; - snprintf(label, sizeof(label), "%s Boost", - hda_get_autocfg_input_label(codec, cfg, i)); - err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0, + const char *label; + char boost_label[32]; + + label = hda_get_autocfg_input_label(codec, cfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", label); + err = add_control(spec, ALC_CTL_WIDGET_VOL, + boost_label, type_idx, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) return err; @@ -10954,8 +11022,10 @@ static int patch_alc882(struct hda_codec *codec) board_config = ALC882_AUTO; } - if (board_config == ALC882_AUTO) - alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1); + if (board_config == ALC882_AUTO) { + alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } alc_auto_parse_customize_define(codec); @@ -11031,8 +11101,7 @@ static int patch_alc882(struct hda_codec *codec) if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - if (board_config == ALC882_AUTO) - alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); spec->vmaster_nid = 0x0c; @@ -11082,10 +11151,10 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), @@ -11186,10 +11255,10 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11211,7 +11280,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { HDA_OUTPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -11222,7 +11291,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; @@ -11242,7 +11311,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; @@ -11349,10 +11418,10 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -11366,10 +11435,10 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -11437,10 +11506,10 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -11624,7 +11693,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -11679,7 +11748,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, - { "Int Mic", 0x1 }, + { "Internal Mic", 0x1 }, { "CD", 0x4 }, }, }; @@ -11831,12 +11900,12 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -11867,12 +11936,12 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { }, HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -11881,10 +11950,10 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -11910,8 +11979,8 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = { HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT), { } /* end */ }; @@ -12081,13 +12150,8 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, spec->multiout.dac_nids = spec->private_dac_nids; spec->multiout.dac_nids[0] = 2; - if (!cfg->speaker_pins[0] && !cfg->hp_pins[0]) - pfx = "Master"; - else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - else if (cfg->line_out_type == AUTO_PIN_HP_OUT) - pfx = "Headphone"; - else + pfx = alc_get_line_out_pfx(cfg, true); + if (!pfx) pfx = "Front"; for (i = 0; i < 2; i++) { err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i); @@ -12427,19 +12491,14 @@ enum { static const struct alc_fixup alc262_fixups[] = { [PINFIX_FSC_H270] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0221142f }, /* front HP */ { 0x1b, 0x0121141f }, /* rear HP */ { } } }, - [PINFIX_PB_M5210] = { - .verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, - {} - } - }, }; static struct snd_pci_quirk alc262_fixup_tbl[] = { @@ -12529,7 +12588,7 @@ static void alc262_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char *alc262_models[ALC262_MODEL_LAST] = { +static const char * const alc262_models[ALC262_MODEL_LAST] = { [ALC262_BASIC] = "basic", [ALC262_HIPPO] = "hippo", [ALC262_HIPPO_1] = "hippo_1", @@ -12557,6 +12616,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { ALC262_HP_BPC), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series", ALC262_HP_BPC), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series", + ALC262_HP_BPC), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), @@ -12870,8 +12931,10 @@ static int patch_alc262(struct hda_codec *codec) board_config = ALC262_AUTO; } - if (board_config == ALC262_AUTO) - alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1); + if (board_config == ALC262_AUTO) { + alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } if (board_config == ALC262_AUTO) { /* automatic parse from the BIOS config */ @@ -12941,8 +13004,7 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - if (board_config == ALC262_AUTO) - alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); spec->vmaster_nid = 0x0c; @@ -12988,9 +13050,9 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; @@ -12999,9 +13061,9 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; @@ -13105,9 +13167,9 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { .put = alc268_acer_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; @@ -13123,8 +13185,8 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { .put = alc268_acer_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT), { } }; @@ -13216,8 +13278,8 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = { HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } }; @@ -13250,8 +13312,8 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT), - HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } }; @@ -13699,6 +13761,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) } #define alc268_auto_init_analog_input alc882_auto_init_analog_input +#define alc268_auto_init_input_src alc882_auto_init_input_src /* init callback for auto-configuration model -- overriding the default init */ static void alc268_auto_init(struct hda_codec *codec) @@ -13708,6 +13771,7 @@ static void alc268_auto_init(struct hda_codec *codec) alc268_auto_init_hp_out(codec); alc268_auto_init_mono_speaker_out(codec); alc268_auto_init_analog_input(codec); + alc268_auto_init_input_src(codec); alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); @@ -13716,7 +13780,7 @@ static void alc268_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char *alc268_models[ALC268_MODEL_LAST] = { +static const char * const alc268_models[ALC268_MODEL_LAST] = { [ALC267_QUANTA_IL1] = "quanta-il1", [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", @@ -13995,7 +14059,6 @@ static int patch_alc268(struct hda_codec *codec) if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); - int i; spec->capsrc_nids = alc268_capsrc_nids; /* get type */ @@ -14015,13 +14078,6 @@ static int patch_alc268(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); add_mixer(spec, alc268_capture_mixer); } - /* set default input source */ - for (i = 0; i < spec->num_adc_nids; i++) - snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i], - 0, AC_VERB_SET_CONNECT_SEL, - i < spec->num_mux_defs ? - spec->input_mux[i].items[0].index : - spec->input_mux->items[0].index); } spec->vmaster_nid = 0x02; @@ -14061,7 +14117,7 @@ static hda_nid_t alc269vb_capsrc_nids[1] = { }; static hda_nid_t alc269_adc_candidates[] = { - 0x08, 0x09, 0x07, + 0x08, 0x09, 0x07, 0x11, }; #define alc269_modes alc260_modes @@ -14074,10 +14130,10 @@ static struct snd_kcontrol_new alc269_base_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), { } /* end */ @@ -14097,10 +14153,10 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } }; @@ -14118,13 +14174,13 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT), { } }; @@ -14154,30 +14210,30 @@ static struct snd_kcontrol_new alc269_asus_mixer[] = { static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), { } /* end */ }; @@ -14398,7 +14454,7 @@ static void alc269_speaker_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, HDA_AMP_MUTE, bits); - alc_report_jack(codec, nid); + snd_hda_input_jack_report(codec, nid); } /* unsolicited event for HP jack sensing */ @@ -14710,11 +14766,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) fillup_priv_adc_nids(codec, alc269_adc_candidates, sizeof(alc269_adc_candidates)); - /* set default input source */ - if (!spec->dual_adc_switch) - select_or_unmute_capsrc(codec, spec->capsrc_nids[0], - spec->input_mux->items[0].index); - err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -14728,6 +14779,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) #define alc269_auto_init_multi_out alc268_auto_init_multi_out #define alc269_auto_init_hp_out alc268_auto_init_hp_out #define alc269_auto_init_analog_input alc882_auto_init_analog_input +#define alc269_auto_init_input_src alc882_auto_init_input_src /* init callback for auto-configuration model -- overriding the default init */ @@ -14737,6 +14789,8 @@ static void alc269_auto_init(struct hda_codec *codec) alc269_auto_init_multi_out(codec); alc269_auto_init_hp_out(codec); alc269_auto_init_analog_input(codec); + if (!spec->dual_adc_switch) + alc269_auto_init_input_src(codec); alc_auto_init_digital(codec); if (spec->unsol_event) alc_inithook(codec); @@ -14796,31 +14850,117 @@ static int alc269_resume(struct hda_codec *codec) } #endif /* SND_HDA_NEEDS_RESUME */ +static void alc269_fixup_hweq(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + int coef; + + if (action != ALC_FIXUP_ACT_INIT) + return; + coef = alc_read_coef_idx(codec, 0x1e); + alc_write_coef_idx(codec, 0x1e, coef | 0x80); +} + +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); +} + enum { ALC269_FIXUP_SONY_VAIO, + ALC275_FIXUP_SONY_VAIO_GPIO2, ALC269_FIXUP_DELL_M101Z, + ALC269_FIXUP_SKU_IGNORE, + ALC269_FIXUP_ASUS_G73JW, + ALC269_FIXUP_LENOVO_EAPD, + ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, }; static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { - .verbs = (const struct hda_verb[]) { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, {} } }, + [ALC275_FIXUP_SONY_VAIO_GPIO2] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_SONY_VAIO + }, [ALC269_FIXUP_DELL_M101Z] = { - .verbs = (const struct hda_verb[]) { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { /* Enables internal speaker */ {0x20, AC_VERB_SET_COEF_INDEX, 13}, {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, {} } }, + [ALC269_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, + [ALC269_FIXUP_ASUS_G73JW] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x17, 0x99130111 }, /* subwoofer */ + { } + } + }, + [ALC269_FIXUP_LENOVO_EAPD] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC275_FIXUP_SONY_HWEQ] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc269_fixup_hweq, + .chained = true, + .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, }; static struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), + SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), + SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), {} }; @@ -14828,7 +14968,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = { /* * configuration and preset */ -static const char *alc269_models[ALC269_MODEL_LAST] = { +static const char * const alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", [ALC269_AMIC] = "laptop-amic", @@ -14852,7 +14992,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC), SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC), SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC), SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC), SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC), SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC), @@ -15070,28 +15210,29 @@ static int patch_alc269(struct hda_codec *codec) alc_auto_parse_customize_define(codec); - coef = alc_read_coef_idx(codec, 0); - if ((coef & 0x00f0) == 0x0010) { - if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) { - alc_codec_rename(codec, "ALC271X"); - spec->codec_variant = ALC269_TYPE_ALC271X; - } else if ((coef & 0xf000) == 0x1000) { - spec->codec_variant = ALC269_TYPE_ALC270; - } else if ((coef & 0xf000) == 0x2000) { - alc_codec_rename(codec, "ALC259"); - spec->codec_variant = ALC269_TYPE_ALC259; - } else if ((coef & 0xf000) == 0x3000) { - alc_codec_rename(codec, "ALC258"); - spec->codec_variant = ALC269_TYPE_ALC258; - } else { - alc_codec_rename(codec, "ALC269VB"); - spec->codec_variant = ALC269_TYPE_ALC269VB; - } - } else - alc_fix_pll_init(codec, 0x20, 0x04, 15); - - alc269_fill_coef(codec); + if (codec->vendor_id == 0x10ec0269) { + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { + if (codec->bus->pci->subsystem_vendor == 0x1025 && + spec->cdefine.platform_type == 1) { + alc_codec_rename(codec, "ALC271X"); + spec->codec_variant = ALC269_TYPE_ALC271X; + } else if ((coef & 0xf000) == 0x1000) { + spec->codec_variant = ALC269_TYPE_ALC270; + } else if ((coef & 0xf000) == 0x2000) { + alc_codec_rename(codec, "ALC259"); + spec->codec_variant = ALC269_TYPE_ALC259; + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + spec->codec_variant = ALC269_TYPE_ALC258; + } else { + alc_codec_rename(codec, "ALC269VB"); + spec->codec_variant = ALC269_TYPE_ALC269VB; + } + } else + alc_fix_pll_init(codec, 0x20, 0x04, 15); + alc269_fill_coef(codec); + } board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, alc269_models, @@ -15103,8 +15244,10 @@ static int patch_alc269(struct hda_codec *codec) board_config = ALC269_AUTO; } - if (board_config == ALC269_AUTO) - alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1); + if (board_config == ALC269_AUTO) { + alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } if (board_config == ALC269_AUTO) { /* automatic parse from the BIOS config */ @@ -15165,8 +15308,7 @@ static int patch_alc269(struct hda_codec *codec) if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - if (board_config == ALC269_AUTO) - alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); spec->vmaster_nid = 0x02; @@ -15854,41 +15996,33 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec, return 0; } -static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx, - hda_nid_t nid, unsigned int chs) +static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, + return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } +#define alc861_create_out_sw(codec, pfx, nid, chs) \ + __alc861_create_out_sw(codec, pfx, nid, 0, chs) + /* add playback controls from the parsed DAC table */ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - static const char *chname[4] = { + static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + const char *pfx = alc_get_line_out_pfx(cfg, true); hda_nid_t nid; int i, err; - if (cfg->line_outs == 1) { - const char *pfx = NULL; - if (!cfg->hp_outs) - pfx = "Master"; - else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - if (pfx) { - nid = spec->multiout.dac_nids[0]; - return alc861_create_out_sw(codec, pfx, nid, 3); - } - } - for (i = 0; i < cfg->line_outs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; - if (i == 2) { + if (!pfx && i == 2) { /* Center/LFE */ err = alc861_create_out_sw(codec, "Center", nid, 1); if (err < 0) @@ -15897,7 +16031,13 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, if (err < 0) return err; } else { - err = alc861_create_out_sw(codec, chname[i], nid, 3); + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc861_create_out_sw(codec, name, nid, index, 3); if (err < 0) return err; } @@ -16080,7 +16220,7 @@ static struct hda_amp_list alc861_loopbacks[] = { /* * configuration and preset */ -static const char *alc861_models[ALC861_MODEL_LAST] = { +static const char * const alc861_models[ALC861_MODEL_LAST] = { [ALC861_3ST] = "3stack", [ALC660_3ST] = "3stack-660", [ALC861_3ST_DIG] = "3stack-dig", @@ -16230,7 +16370,8 @@ enum { static const struct alc_fixup alc861_fixups[] = { [PINFIX_FSC_AMILO_PI1505] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x0b, 0x0221101f }, /* HP */ { 0x0f, 0x90170310 }, /* speaker */ { } @@ -16265,8 +16406,10 @@ static int patch_alc861(struct hda_codec *codec) board_config = ALC861_AUTO; } - if (board_config == ALC861_AUTO) - alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1); + if (board_config == ALC861_AUTO) { + alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ @@ -16303,8 +16446,7 @@ static int patch_alc861(struct hda_codec *codec) spec->vmaster_nid = 0x03; - if (board_config == ALC861_AUTO) - alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) { @@ -16369,8 +16511,8 @@ static struct hda_input_mux alc861vd_capture_source = { static struct hda_input_mux alc861vd_dallas_capture_source = { .num_items = 2, .items = { - { "Ext Mic", 0x0 }, - { "Int Mic", 0x1 }, + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, }, }; @@ -16449,11 +16591,11 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), @@ -16472,11 +16614,11 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), @@ -16496,11 +16638,11 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), @@ -16511,19 +16653,19 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { }; /* Pin assignment: Speaker=0x14, HP = 0x15, - * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d + * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d */ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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 Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -16688,18 +16830,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {} }; -static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_jack_detect(codec, 0x18); - bits = present ? HDA_AMP_MUTE : 0; - - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, - HDA_AMP_MUTE, bits); -} - static void alc861vd_lenovo_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -16710,7 +16840,7 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec) static void alc861vd_lenovo_init_hook(struct hda_codec *codec) { alc_automute_amp(codec); - alc861vd_lenovo_mic_automute(codec); + alc88x_simple_mic_automute(codec); } static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, @@ -16718,7 +16848,7 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, { switch (res >> 26) { case ALC880_MIC_EVENT: - alc861vd_lenovo_mic_automute(codec); + alc88x_simple_mic_automute(codec); break; default: alc_automute_amp_unsol_event(codec, res); @@ -16793,7 +16923,7 @@ static void alc861vd_dallas_setup(struct hda_codec *codec) /* * configuration and preset */ -static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { +static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", [ALC660VD_3ST_DIG] = "3stack-660-digout", [ALC660VD_ASUS_V1S] = "asus-v1s", @@ -17013,7 +17143,10 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; + static const char * const chname[4] = { + "Front", "Surround", "CLFE", "Side" + }; + const char *pfx = alc_get_line_out_pfx(cfg, true); hda_nid_t nid_v, nid_s; int i, err; @@ -17027,7 +17160,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, alc880_dac_to_idx( spec->multiout.dac_nids[i])); - if (i == 2) { + if (!pfx && i == 2) { /* Center/LFE */ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Center", @@ -17054,24 +17187,20 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, if (err < 0) return err; } else { - const char *pfx; - if (cfg->line_outs == 1 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - if (!cfg->hp_pins) - pfx = "Speaker"; - else - pfx = "PCM"; - } else - pfx = chname[i]; - err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + name, index, HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - if (cfg->line_outs == 1 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, + err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + name, index, HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); if (err < 0) @@ -17204,7 +17333,8 @@ enum { /* reset GPIO1 */ static const struct alc_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .verbs = (const struct hda_verb[]) { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, @@ -17239,8 +17369,10 @@ static int patch_alc861vd(struct hda_codec *codec) board_config = ALC861VD_AUTO; } - if (board_config == ALC861VD_AUTO) - alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1); + if (board_config == ALC861VD_AUTO) { + alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } if (board_config == ALC861VD_AUTO) { /* automatic parse from the BIOS config */ @@ -17288,8 +17420,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->vmaster_nid = 0x02; - if (board_config == ALC861VD_AUTO) - alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); codec->patch_ops = alc_patch_ops; @@ -17535,13 +17666,13 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, 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("i-Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -17685,8 +17816,8 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -17697,8 +17828,8 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), { } /* end */ @@ -18531,13 +18662,13 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -18548,13 +18679,13 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, 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("Mic Boost Volume", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -18572,7 +18703,7 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = { /* * configuration and preset */ -static const char *alc662_models[ALC662_MODEL_LAST] = { +static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_3ST_2ch_DIG] = "3stack-dig", [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC662_3ST_6ch] = "3stack-6ch", @@ -18677,6 +18808,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ALC662_3ST_6ch_DIG), SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E), {} }; @@ -19059,20 +19191,24 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec, return 0; } -static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, - hda_nid_t nid, unsigned int chs) +static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } -static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, - hda_nid_t nid, unsigned int chs) +static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, + hda_nid_t nid, int idx, unsigned int chs) { - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); } +#define alc662_add_vol_ctl(spec, pfx, nid, chs) \ + __alc662_add_vol_ctl(spec, pfx, nid, 0, chs) +#define alc662_add_sw_ctl(spec, pfx, nid, chs) \ + __alc662_add_sw_ctl(spec, pfx, nid, 0, chs) #define alc662_add_stereo_vol(spec, pfx, nid) \ alc662_add_vol_ctl(spec, pfx, nid, 3) #define alc662_add_stereo_sw(spec, pfx, nid) \ @@ -19083,9 +19219,10 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - static const char *chname[4] = { + static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + const char *pfx = alc_get_line_out_pfx(cfg, true); hda_nid_t nid, mix; int i, err; @@ -19096,7 +19233,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid); if (!mix) continue; - if (i == 2) { + if (!pfx && i == 2) { /* Center/LFE */ err = alc662_add_vol_ctl(spec, "Center", nid, 1); if (err < 0) @@ -19111,22 +19248,16 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, if (err < 0) return err; } else { - const char *pfx; - if (cfg->line_outs == 1 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - if (cfg->hp_outs) - pfx = "Speaker"; - else - pfx = "PCM"; - } else - pfx = chname[i]; - err = alc662_add_vol_ctl(spec, pfx, nid, 3); + const char *name = pfx; + int index = i; + if (!name) { + name = chname[i]; + index = 0; + } + err = __alc662_add_vol_ctl(spec, name, nid, index, 3); if (err < 0) return err; - if (cfg->line_outs == 1 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - err = alc662_add_sw_ctl(spec, pfx, mix, 3); + err = __alc662_add_sw_ctl(spec, name, mix, index, 3); if (err < 0) return err; } @@ -19323,34 +19454,75 @@ static void alc662_auto_init(struct hda_codec *codec) alc_inithook(codec); } +static void alc272_fixup_mario(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + if (action != ALC_FIXUP_ACT_PROBE) + return; + if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, + (0x3b << AC_AMPCAP_OFFSET_SHIFT) | + (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT))) + printk(KERN_WARNING + "hda_codec: failed to override amp caps for NID 0x2\n"); +} + enum { ALC662_FIXUP_ASPIRE, ALC662_FIXUP_IDEAPAD, + ALC272_FIXUP_MARIO, + ALC662_FIXUP_CZC_P10T, + ALC662_FIXUP_SKU_IGNORE, }; static const struct alc_fixup alc662_fixups[] = { [ALC662_FIXUP_ASPIRE] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x15, 0x99130112 }, /* subwoofer */ { } } }, [ALC662_FIXUP_IDEAPAD] = { - .pins = (const struct alc_pincfg[]) { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { { 0x17, 0x99130112 }, /* subwoofer */ { } } }, + [ALC272_FIXUP_MARIO] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc272_fixup_mario, + }, + [ALC662_FIXUP_CZC_P10T] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC662_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, }; static struct snd_pci_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), {} }; +static const struct alc_model_fixup alc662_fixup_models[] = { + {.id = ALC272_FIXUP_MARIO, .name = "mario"}, + {} +}; static int patch_alc662(struct hda_codec *codec) @@ -19389,7 +19561,9 @@ static int patch_alc662(struct hda_codec *codec) } if (board_config == ALC662_AUTO) { - alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1); + alc_pick_fixup(codec, alc662_fixup_models, + alc662_fixup_tbl, alc662_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc662_parse_auto_config(codec); if (err < 0) { @@ -19447,11 +19621,11 @@ static int patch_alc662(struct hda_codec *codec) } spec->vmaster_nid = 0x02; + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; - if (board_config == ALC662_AUTO) { + if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; - alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0); - } alc_init_jacks(codec); @@ -19577,9 +19751,9 @@ static struct snd_kcontrol_new alc680_base_mixer[] = { HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT), { } }; @@ -19839,7 +20013,7 @@ static void alc680_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char *alc680_models[ALC680_MODEL_LAST] = { +static const char * const alc680_models[ALC680_MODEL_LAST] = { [ALC680_BASE] = "base", [ALC680_AUTO] = "auto", }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index efa4225f5fd..94d19c03a7f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -180,18 +180,16 @@ struct sigmatel_event { int data; }; -struct sigmatel_jack { - hda_nid_t nid; - int type; - struct snd_jack *jack; -}; - struct sigmatel_mic_route { hda_nid_t pin; signed char mux_idx; signed char dmux_idx; }; +#define MAX_PINS_NUM 16 +#define MAX_ADCS_NUM 4 +#define MAX_DMICS_NUM 4 + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -229,9 +227,6 @@ struct sigmatel_spec { hda_nid_t *pwr_nids; hda_nid_t *dac_list; - /* jack detection */ - struct snd_array jacks; - /* events */ struct snd_array events; @@ -266,7 +261,7 @@ struct sigmatel_spec { struct sigmatel_mic_route int_mic; struct sigmatel_mic_route dock_mic; - const char **spdif_labels; + const char * const *spdif_labels; hda_nid_t dig_in_nid; hda_nid_t mono_nid; @@ -309,6 +304,17 @@ struct sigmatel_spec { struct hda_input_mux private_imux; struct hda_input_mux private_smux; struct hda_input_mux private_mono_mux; + + /* auto spec */ + unsigned auto_pin_cnt; + hda_nid_t auto_pin_nids[MAX_PINS_NUM]; + unsigned auto_adc_cnt; + hda_nid_t auto_adc_nids[MAX_ADCS_NUM]; + hda_nid_t auto_mux_nids[MAX_ADCS_NUM]; + hda_nid_t auto_dmux_nids[MAX_ADCS_NUM]; + unsigned long auto_capvols[MAX_ADCS_NUM]; + unsigned auto_dmic_cnt; + hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; }; static hda_nid_t stac9200_adc_nids[1] = { @@ -364,14 +370,6 @@ static unsigned long stac92hd73xx_capvols[] = { #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_mux_nids[2] = { - 0x17, 0x18, -}; - -static hda_nid_t stac92hd83xxx_adc_nids[2] = { - 0x15, 0x16, -}; - static hda_nid_t stac92hd83xxx_pwr_nids[4] = { 0xa, 0xb, 0xd, 0xe, }; @@ -384,23 +382,10 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; -#define STAC92HD83XXX_NUM_DMICS 2 -static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { - 0x11, 0x20, 0 -}; - -#define STAC92HD87B_NUM_DMICS 1 -static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = { - 0x11, 0 +static hda_nid_t stac92hd83xxx_dmic_nids[] = { + 0x11, 0x20, }; -#define STAC92HD83XXX_NUM_CAPS 2 -static unsigned long stac92hd83xxx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT), -}; -#define stac92hd83xxx_capsws stac92hd83xxx_capvols - static hda_nid_t stac92hd71bxx_pwr_nids[3] = { 0x0a, 0x0d, 0x0f }; @@ -521,7 +506,7 @@ static unsigned long stac927x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), }; -static const char *stac927x_spdif_labels[5] = { +static const char * const stac927x_spdif_labels[5] = { "Digital Playback", "ADAT", "Analog Mux 1", "Analog Mux 2", "Analog Mux 3" }; @@ -578,16 +563,6 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = { 0x14, 0x22, 0x23 }; -static hda_nid_t stac92hd83xxx_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x1f, 0x20, -}; - -static hda_nid_t stac92hd88xxx_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, - 0x0f, 0x11, 0x1f, 0x20, -}; - #define STAC92HD71BXX_NUM_PINS 13 static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, @@ -749,7 +724,7 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); const struct hda_input_mux *imux = spec->input_mux; - unsigned int idx, prev_idx; + unsigned int idx, prev_idx, didx; idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) @@ -761,7 +736,8 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, imux->items[idx].index); - if (prev_idx >= spec->num_analog_muxes) { + if (prev_idx >= spec->num_analog_muxes && + spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) { imux = spec->dinput_mux; /* 0 = analog */ snd_hda_codec_write_cache(codec, @@ -771,9 +747,13 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e } } else { imux = spec->dinput_mux; + /* first dimux item is hardcoded to select analog imux, + * so lets skip it + */ + didx = idx - spec->num_analog_muxes + 1; snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx - 1].index); + imux->items[didx].index); } spec->cur_mux[adc_idx] = idx; return 1; @@ -1059,7 +1039,7 @@ static struct snd_kcontrol_new stac_smux_mixer = { .put = stac92xx_smux_enum_put, }; -static const char *slave_vols[] = { +static const char * const slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -1070,7 +1050,7 @@ static const char *slave_vols[] = { NULL }; -static const char *slave_sws[] = { +static const char * const slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -1351,7 +1331,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_9200_PANASONIC] = ref9200_pin_configs, }; -static const char *stac9200_models[STAC_9200_MODELS] = { +static const char * const stac9200_models[STAC_9200_MODELS] = { [STAC_AUTO] = "auto", [STAC_REF] = "ref", [STAC_9200_OQO] = "oqo", @@ -1497,7 +1477,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { [STAC_M6] = stac925xM6_pin_configs, }; -static const char *stac925x_models[STAC_925x_MODELS] = { +static const char * const stac925x_models[STAC_925x_MODELS] = { [STAC_925x_AUTO] = "auto", [STAC_REF] = "ref", [STAC_M1] = "m1", @@ -1571,7 +1551,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs, }; -static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { +static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_AUTO] = "auto", [STAC_92HD73XX_NO_JD] = "no-jd", [STAC_92HD73XX_REF] = "ref", @@ -1657,7 +1637,7 @@ static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, }; -static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { +static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_AUTO] = "auto", [STAC_92HD83XXX_REF] = "ref", [STAC_92HD83XXX_PWR_REF] = "mic-ref", @@ -1719,7 +1699,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_HP_DV4_1222NR] = NULL, }; -static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { +static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_92HD71BXX_AUTO] = "auto", [STAC_92HD71BXX_REF] = "ref", [STAC_DELL_M4_1] = "dell-m4-1", @@ -1912,7 +1892,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, }; -static const char *stac922x_models[STAC_922X_MODELS] = { +static const char * const stac922x_models[STAC_922X_MODELS] = { [STAC_922X_AUTO] = "auto", [STAC_D945_REF] = "ref", [STAC_D945GTP5] = "5stack", @@ -2074,7 +2054,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_927X_VOLKNOB] = NULL, }; -static const char *stac927x_models[STAC_927X_MODELS] = { +static const char * const stac927x_models[STAC_927X_MODELS] = { [STAC_927X_AUTO] = "auto", [STAC_D965_REF_NO_JD] = "ref-no-jd", [STAC_D965_REF] = "ref", @@ -2177,7 +2157,7 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_EAPD] = NULL, }; -static const char *stac9205_models[STAC_9205_MODELS] = { +static const char * const stac9205_models[STAC_9205_MODELS] = { [STAC_9205_AUTO] = "auto", [STAC_9205_REF] = "ref", [STAC_9205_DELL_M42] = "dell-m42", @@ -2495,7 +2475,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; - /* check to be sure that the ports are upto date with + /* check to be sure that the ports are up to date with * switch changes */ stac_issue_unsol_event(codec, nid); @@ -3120,7 +3100,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, int type) { struct sigmatel_spec *spec = codec->spec; - static const char *chname[4] = { + static const char * const chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid; @@ -3253,7 +3233,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, } /* labels for mono mux outputs */ -static const char *stac92xx_mono_labels[4] = { +static const char * const stac92xx_mono_labels[4] = { "DAC0", "DAC1", "Mixer", "DAC2" }; @@ -3377,7 +3357,7 @@ static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) return 0; }; -static const char *stac92xx_spdif_labels[3] = { +static const char * const stac92xx_spdif_labels[3] = { "Digital Playback", "Analog Mux 1", "Analog Mux 2", }; @@ -3385,7 +3365,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *spdif_mux = &spec->private_smux; - const char **labels = spec->spdif_labels; + const char * const *labels = spec->spdif_labels; int i, num_cons; hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; @@ -3406,21 +3386,44 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) } /* labels for dmic mux inputs */ -static const char *stac92xx_dmic_labels[5] = { +static const char * const stac92xx_dmic_labels[5] = { "Analog Inputs", "Digital Mic 1", "Digital Mic 2", "Digital Mic 3", "Digital Mic 4" }; +static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, + int idx) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int nums; + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + if (idx >= 0 && idx < nums) + return conn[idx]; + return 0; +} + static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid) { hda_nid_t conn[HDA_MAX_NUM_INPUTS]; int i, nums; + if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST)) + return -1; + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); for (i = 0; i < nums; i++) if (conn[i] == nid) return i; + + for (i = 0; i < nums; i++) { + unsigned int wid_caps = get_wcaps(codec, conn[i]); + unsigned int wid_type = get_wcaps_type(wid_caps); + + if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX) + if (get_connection_index(codec, conn[i], nid) >= 0) + return i; + } return -1; } @@ -3481,6 +3484,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, label = hda_get_input_pin_label(codec, nid, 1); snd_hda_add_imux_item(dimux, label, index, &type_idx); + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) + snd_hda_add_imux_item(imux, label, index, &type_idx); err = create_elem_capture_vol(codec, nid, label, type_idx, HDA_INPUT); @@ -3491,10 +3496,17 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, type_idx, HDA_OUTPUT); if (err < 0) return err; + if (!err) { + nid = get_connected_node(codec, + spec->dmux_nids[0], index); + if (nid) + err = create_elem_capture_vol(codec, + nid, label, + type_idx, HDA_INPUT); + if (err < 0) + return err; + } } - - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) - snd_hda_add_imux_item(imux, label, index, NULL); } return 0; @@ -3592,7 +3604,7 @@ static int stac_check_auto_mic(struct hda_codec *codec) if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext, &dock)) return 0; - if (!fixed && !ext && !dock) + if (!fixed || (!ext && !dock)) return 0; /* no input to switch */ if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) return 0; /* no unsol support */ @@ -4047,21 +4059,10 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } -#ifdef CONFIG_SND_HDA_INPUT_JACK -static void stac92xx_free_jack_priv(struct snd_jack *jack) -{ - struct sigmatel_jack *jacks = jack->private_data; - jacks->nid = 0; - jacks->jack = NULL; -} -#endif - static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { #ifdef CONFIG_SND_HDA_INPUT_JACK - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jack; int def_conf = snd_hda_codec_get_pincfg(codec, nid); int connectivity = get_defcfg_connect(def_conf); char name[32]; @@ -4070,26 +4071,15 @@ static int stac92xx_add_jack(struct hda_codec *codec, if (connectivity && connectivity != AC_JACK_PORT_FIXED) return 0; - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - if (!jack) - return -ENOMEM; - jack->nid = nid; - jack->type = type; - snprintf(name, sizeof(name), "%s at %s %s Jack", snd_hda_get_jack_type(def_conf), snd_hda_get_jack_connectivity(def_conf), snd_hda_get_jack_location(def_conf)); - err = snd_jack_new(codec->bus->card, name, type, &jack->jack); - if (err < 0) { - jack->nid = 0; + err = snd_hda_input_jack_add(codec, nid, type, name); + if (err < 0) return err; - } - jack->jack->private_data = jack; - jack->jack->private_free = stac92xx_free_jack_priv; -#endif +#endif /* CONFIG_SND_HDA_INPUT_JACK */ return 0; } @@ -4392,23 +4382,6 @@ static int stac92xx_init(struct hda_codec *codec) return 0; } -static void stac92xx_free_jacks(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_HDA_INPUT_JACK - /* free jack instances manually when clearing/reconfiguring */ - struct sigmatel_spec *spec = codec->spec; - if (!codec->bus->shutdown && spec->jacks.list) { - struct sigmatel_jack *jacks = spec->jacks.list; - int i; - for (i = 0; i < spec->jacks.used; i++, jacks++) { - if (jacks->jack) - snd_device_free(codec->bus->card, jacks->jack); - } - } - snd_array_free(&spec->jacks); -#endif -} - static void stac92xx_free_kctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -4442,7 +4415,7 @@ static void stac92xx_free(struct hda_codec *codec) return; stac92xx_shutup(codec); - stac92xx_free_jacks(codec); + snd_hda_input_jack_free(codec); snd_array_free(&spec->events); kfree(spec); @@ -4660,33 +4633,6 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); } -static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int pin_ctl = - snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - int type = jacks->type; - if (type == (SND_JACK_LINEOUT - | SND_JACK_HEADPHONE)) - type = (pin_ctl & AC_PINCTL_HP_EN) - ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; - snd_jack_report(jacks->jack, - get_pin_presence(codec, nid) - ? type : 0); - } - jacks++; - } - } -} - /* get the pin connection (fixed, none, etc) */ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) { @@ -4775,7 +4721,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) case STAC_PWR_EVENT: if (spec->num_pwrs > 0) stac92xx_pin_sense(codec, event->nid); - stac92xx_report_jack(codec, event->nid); + snd_hda_input_jack_report(codec, event->nid); switch (codec->subsystem_id) { case 0x103c308f: @@ -5331,7 +5277,7 @@ again: return 0; } -static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec) +static int hp_bnb2011_with_dock(struct hda_codec *codec) { if (codec->vendor_id != 0x111d7605 && codec->vendor_id != 0x111d76d1) @@ -5346,10 +5292,6 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec) case 0x103c161d: case 0x103c161e: case 0x103c161f: - case 0x103c1620: - case 0x103c1621: - case 0x103c1622: - case 0x103c1623: case 0x103c162a: case 0x103c162b: @@ -5358,41 +5300,9 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec) case 0x103c1631: case 0x103c1633: - + case 0x103c1634: case 0x103c1635: - case 0x103c164f: - - case 0x103c1676: - case 0x103c1677: - case 0x103c1678: - case 0x103c1679: - case 0x103c167a: - case 0x103c167b: - case 0x103c167c: - case 0x103c167d: - case 0x103c167e: - case 0x103c167f: - case 0x103c1680: - case 0x103c1681: - case 0x103c1682: - case 0x103c1683: - case 0x103c1684: - case 0x103c1685: - case 0x103c1686: - case 0x103c1687: - case 0x103c1688: - case 0x103c1689: - case 0x103c168a: - case 0x103c168b: - case 0x103c168c: - case 0x103c168d: - case 0x103c168e: - case 0x103c168f: - case 0x103c1690: - case 0x103c1691: - case 0x103c1692: - case 0x103c3587: case 0x103c3588: case 0x103c3589: @@ -5400,13 +5310,112 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec) case 0x103c3667: case 0x103c3668: - /* set BTL amp level to 13.43dB for louder speaker output */ - return snd_hda_codec_write_cache(codec, codec->afg, 0, - 0x7F4, 0x14); + case 0x103c3669: + + return 1; } return 0; } +static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int i; + + spec->auto_pin_nids[spec->auto_pin_cnt] = nid; + spec->auto_pin_cnt++; + + if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN && + get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) { + for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) { + if (nid == stac92hd83xxx_dmic_nids[i]) { + spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid; + spec->auto_dmic_cnt++; + } + } + } +} + +static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + + spec->auto_adc_nids[spec->auto_adc_cnt] = nid; + spec->auto_adc_cnt++; +} + +static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid) +{ + int i, j; + struct sigmatel_spec *spec = codec->spec; + + for (i = 0; i < spec->auto_adc_cnt; i++) { + if (get_connection_index(codec, + spec->auto_adc_nids[i], nid) >= 0) { + /* mux and volume for adc_nids[i] */ + if (!spec->auto_mux_nids[i]) { + spec->auto_mux_nids[i] = nid; + /* 92hd codecs capture volume is in mux */ + spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid, + 3, 0, HDA_OUTPUT); + } + for (j = 0; j < spec->auto_dmic_cnt; j++) { + if (get_connection_index(codec, nid, + spec->auto_dmic_nids[j]) >= 0) { + /* dmux for adc_nids[i] */ + if (!spec->auto_dmux_nids[i]) + spec->auto_dmux_nids[i] = nid; + break; + } + } + break; + } + } +} + +static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) +{ + hda_nid_t nid, end_nid; + unsigned int wid_caps, wid_type; + struct sigmatel_spec *spec = codec->spec; + + end_nid = codec->start_nid + codec->num_nodes; + + for (nid = codec->start_nid; nid < end_nid; nid++) { + wid_caps = get_wcaps(codec, nid); + wid_type = get_wcaps_type(wid_caps); + + if (wid_type == AC_WID_PIN) + stac92hd8x_add_pin(codec, nid); + + if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL)) + stac92hd8x_add_adc(codec, nid); + } + + for (nid = codec->start_nid; nid < end_nid; nid++) { + wid_caps = get_wcaps(codec, nid); + wid_type = get_wcaps_type(wid_caps); + + if (wid_type == AC_WID_AUD_SEL) + stac92hd8x_add_mux(codec, nid); + } + + spec->pin_nids = spec->auto_pin_nids; + spec->num_pins = spec->auto_pin_cnt; + spec->adc_nids = spec->auto_adc_nids; + spec->num_adcs = spec->auto_adc_cnt; + spec->capvols = spec->auto_capvols; + spec->capsws = spec->auto_capvols; + spec->num_caps = spec->auto_adc_cnt; + spec->mux_nids = spec->auto_mux_nids; + spec->num_muxes = spec->auto_adc_cnt; + spec->dmux_nids = spec->auto_dmux_nids; + spec->num_dmuxes = spec->auto_adc_cnt; + spec->dmic_nids = spec->auto_dmic_nids; + spec->num_dmics = spec->auto_dmic_cnt; +} + static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5418,31 +5427,27 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + if (hp_bnb2011_with_dock(codec)) { + snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); + snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); + } + /* reset pin power-down; Windows may leave these bits after reboot */ snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0); snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0); codec->no_trigger_sense = 1; codec->spec = spec; - spec->linear_tone_beep = 1; + + stac92hd8x_fill_auto_spec(codec); + + spec->linear_tone_beep = 0; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; - spec->dmic_nids = stac92hd83xxx_dmic_nids; - spec->dmux_nids = stac92hd83xxx_mux_nids; - spec->mux_nids = stac92hd83xxx_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); - spec->adc_nids = stac92hd83xxx_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->multiout.dac_nids = spec->dac_nids; - spec->init = stac92hd83xxx_core_init; - spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); - spec->pin_nids = stac92hd83xxx_pin_nids; - spec->num_caps = STAC92HD83XXX_NUM_CAPS; - spec->capvols = stac92hd83xxx_capvols; - spec->capsws = stac92hd83xxx_capsws; spec->board_config = snd_hda_check_board_config(codec, STAC_92HD83XXX_MODELS, @@ -5459,21 +5464,12 @@ again: switch (codec->vendor_id) { case 0x111d76d1: case 0x111d76d9: - spec->dmic_nids = stac92hd87b_dmic_nids; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd87b_dmic_nids, - STAC92HD87B_NUM_DMICS); - /* Fall through */ + case 0x111d76e5: case 0x111d7666: case 0x111d7667: case 0x111d7668: case 0x111d7669: - spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); - spec->pin_nids = stac92hd88xxx_pin_nids; - spec->mono_nid = 0; - spec->digbeep_nid = 0; - spec->num_pwrs = 0; - break; + case 0x111d76e3: case 0x111d7604: case 0x111d76d4: case 0x111d7605: @@ -5482,9 +5478,6 @@ again: if (spec->board_config == STAC_92HD83XXX_PWR_REF) break; spec->num_pwrs = 0; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd83xxx_dmic_nids, - STAC92HD83XXX_NUM_DMICS); break; } @@ -5538,8 +5531,6 @@ again: AC_VERB_SET_CONNECT_SEL, num_dacs); } - stac92hd83xxx_set_system_btl_amp(codec); - codec->proc_widget_hook = stac92hd_proc_hook; return 0; @@ -6262,7 +6253,7 @@ static unsigned int stac9872_vaio_pin_configs[9] = { 0x90a7013e }; -static const char *stac9872_models[STAC_9872_MODELS] = { +static const char * const stac9872_models[STAC_9872_MODELS] = { [STAC_9872_AUTO] = "auto", [STAC_9872_VAIO] = "vaio", }; @@ -6412,6 +6403,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index d1c3f8defc4..0997031c48d 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -159,6 +159,7 @@ struct via_spec { #endif }; +static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); static struct via_spec * via_new_spec(struct hda_codec *codec) { struct via_spec *spec; @@ -169,6 +170,10 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) codec->spec = spec; spec->codec = codec; + spec->codec_type = get_codec_type(codec); + /* VT1708BCE & VT1708S are almost same */ + if (spec->codec_type == VT1708BCE) + spec->codec_type = VT1708S; return spec; } @@ -263,8 +268,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec) return; snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, !spec->vt1708_jack_detectect); - cancel_delayed_work(&spec->vt1708_hp_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&spec->vt1708_hp_work); } @@ -568,7 +572,7 @@ static void via_auto_init_analog_input(struct hda_codec *codec) hda_nid_t nid = cfg->inputs[i].pin; if (spec->smart51_enabled && is_smart51_pins(spec, nid)) ctl = PIN_OUT; - else if (i == AUTO_PIN_MIC) + else if (cfg->inputs[i].type == AUTO_PIN_MIC) ctl = PIN_VREF50; else ctl = PIN_IN; @@ -1102,6 +1106,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int ret; if (!spec->mux_nids[adc_idx]) return -EINVAL; @@ -1110,12 +1115,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - /* update jack power state */ - set_jack_power_state(codec); - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); + /* update jack power state */ + set_jack_power_state(codec); + + return ret; } static int via_independent_hp_info(struct snd_kcontrol *kcontrol, @@ -1189,8 +1196,16 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, /* Get Independent Mode index of headphone pin widget */ spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel ? 1 : 0; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); + if (spec->codec_type == VT1718S) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0); + else + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_CONNECT_SEL, pinsel); if (spec->multiout.hp_nid && spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, @@ -1209,6 +1224,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, activate_ctl(codec, "Headphone Playback Switch", spec->hp_independent_mode); } + /* update jack power state */ + set_jack_power_state(codec); return 0; } @@ -1249,9 +1266,12 @@ static int via_hp_build(struct hda_codec *codec) break; } - nums = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); - if (nums <= 1) - return 0; + if (spec->codec_type != VT1708) { + nums = snd_hda_get_connections(codec, nid, + conn, HDA_MAX_CONNECTIONS); + if (nums <= 1) + return 0; + } knew = via_clone_control(spec, &via_hp_mixer[0]); if (knew == NULL) @@ -1272,14 +1292,18 @@ static void notify_aa_path_ctls(struct hda_codec *codec) { int i; struct snd_ctl_elem_id id; - const char *labels[] = {"Mic", "Front Mic", "Line"}; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; for (i = 0; i < ARRAY_SIZE(labels); i++) { sprintf(id.name, "%s Playback Volume", labels[i]); - snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, - &id); + ctl = snd_hda_find_mixer_ctl(codec, id.name); + if (ctl) + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &ctl->id); } } @@ -1311,6 +1335,11 @@ static void mute_aa_path(struct hda_codec *codec, int mute) start_idx = 2; end_idx = 4; break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; default: return; } @@ -2186,10 +2215,6 @@ static int via_init(struct hda_codec *codec) for (i = 0; i < spec->num_iverbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); - spec->codec_type = get_codec_type(codec); - if (spec->codec_type == VT1708BCE) - spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost - same */ /* Lydia Add for EAPD enable */ if (!spec->dig_in_nid) { /* No Digital In connection */ if (spec->dig_in_pin) { @@ -2282,7 +2307,9 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; int i, err; @@ -2371,7 +2398,7 @@ static void create_hp_imux(struct via_spec *spec) { int i; struct hda_input_mux *imux = &spec->private_imux[1]; - static const char *texts[] = { "OFF", "ON", NULL}; + static const char * const texts[] = { "OFF", "ON", NULL}; /* for hp mode select */ for (i = 0; texts[i]; i++) @@ -2437,7 +2464,14 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, else type_idx = 0; label = hda_get_autocfg_input_label(codec, cfg, i); - err = via_new_analog_input(spec, label, type_idx, idx, cap_nid); + if (spec->codec_type == VT1708S || + spec->codec_type == VT1702 || + spec->codec_type == VT1716S) + err = via_new_analog_input(spec, label, type_idx, + idx+1, cap_nid); + else + err = via_new_analog_input(spec, label, type_idx, + idx, cap_nid); if (err < 0) return err; snd_hda_add_imux_item(imux, label, idx, NULL); @@ -2891,7 +2925,9 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; int i, err; @@ -3434,7 +3470,9 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; hda_nid_t nid, nid_vol = 0; int i, err; @@ -3862,7 +3900,9 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; hda_nid_t nid, nid_vol, nid_mute; @@ -4140,6 +4180,11 @@ static int patch_vt1708S(struct hda_codec *codec) spec->stream_name_analog = "VT1708BCE Analog"; spec->stream_name_digital = "VT1708BCE Digital"; } + /* correct names for VT1818S */ + if (codec->vendor_id == 0x11060440) { + spec->stream_name_analog = "VT1818S Analog"; + spec->stream_name_digital = "VT1818S Digital"; + } return 0; } @@ -4305,7 +4350,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { int err, i; struct hda_input_mux *imux; - static const char *texts[] = { "ON", "OFF", NULL}; + static const char * const texts[] = { "ON", "OFF", NULL}; if (!pin) return 0; spec->multiout.hp_nid = 0x1D; @@ -4616,7 +4661,9 @@ static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + static const char * const chname[4] = { + "Front", "Surround", "C/LFE", "Side" + }; hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; hda_nid_t nid, nid_vol, nid_mute = 0; @@ -5065,7 +5112,9 @@ static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char *chname[3] = { "Front", "Surround", "C/LFE" }; + static const char * const chname[3] = { + "Front", "Surround", "C/LFE" + }; hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; hda_nid_t nid, nid_vol, nid_mute; |