From b1353258603bff115f24b64fee5a98fa936b646c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 May 2009 16:31:14 +0200 Subject: [PATCH] --- yaml --- r: 148415 b: refs/heads/master c: 9da29271bea5d831d745f3ceb7f6f6b2def13a5b h: refs/heads/master i: 148413: c8ecf30b5facac5899a71a08bef9af47b17e5b73 148411: 34c584888a1d05208074d02420fba87a642f1989 148407: fa6a4286df9a516b406352e88a63c29f23aed3e8 148399: bc5e852ec0f345916c95fd9cc7155efb013e2fd8 148383: 579e61297e639ab6302996a07d830375014840f1 148351: b8d7b38ede0a9fcaefa9a248382c6cc9b1fbc2b3 v: v3 --- [refs] | 2 +- .../sound/alsa/HD-Audio-Models.txt | 11 +- trunk/sound/pci/hda/Kconfig | 13 - trunk/sound/pci/hda/Makefile | 4 - trunk/sound/pci/hda/hda_codec.c | 122 +- trunk/sound/pci/hda/hda_codec.h | 1 - trunk/sound/pci/hda/hda_intel.c | 34 +- trunk/sound/pci/hda/patch_ca0110.c | 573 ------ trunk/sound/pci/hda/patch_realtek.c | 1645 ++++++++++------- trunk/sound/pci/hda/patch_sigmatel.c | 44 +- trunk/sound/pci/hda/patch_via.c | 111 +- 11 files changed, 1046 insertions(+), 1514 deletions(-) delete mode 100644 trunk/sound/pci/hda/patch_ca0110.c diff --git a/[refs] b/[refs] index b4ac65b35e7d..2af61881195d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 01f2bd48d08c6bbde12d86b66c760612e33e49a9 +refs/heads/master: 9da29271bea5d831d745f3ceb7f6f6b2def13a5b diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt index 92c9d3a3e990..8eec05bc079e 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt @@ -36,7 +36,6 @@ ALC260 acer Acer TravelMate will Will laptops (PB V7900) replacer Replacer 672V - favorit100 Maxdata Favorit 100XS basic fixed pin assignment (old default model) test for testing/debugging purpose, almost all controls can adjusted. Appearing only when compiled with @@ -86,11 +85,10 @@ ALC269 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 fujitsu FSC Amilo - lifebook Fujitsu Lifebook S6420 auto auto-config reading BIOS (default) -ALC662/663/272 -============== +ALC662/663 +========== 3stack-dig 3-stack (2-channel) with SPDIF 3stack-6ch 3-stack (6-channel) 3stack-6ch-dig 3-stack (6-channel) with SPDIF @@ -109,8 +107,6 @@ ALC662/663/272 asus-mode4 ASUS asus-mode5 ASUS asus-mode6 ASUS - dell Dell with ALC272 - dell-zm1 Dell ZM1 with ALC272 auto auto-config reading BIOS (default) ALC882/885 @@ -122,7 +118,6 @@ ALC882/885 asus-a7j ASUS A7J asus-a7m ASUS A7M macpro MacPro support - mb5 Macbook 5,1 mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC @@ -155,7 +150,6 @@ ALC883/888 fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards - asus-p5q ASUS P5Q-EM boards auto auto-config reading BIOS (default) ALC861/660 @@ -353,7 +347,6 @@ STAC92HD71B* hp-m4 HP mini 1000 hp-dv5 HP dv series hp-hdx HP HDX series - hp-dv4-1222nr HP dv4-1222nr (with LED support) auto BIOS setup (default) STAC92HD73* diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index c710150d5065..eb2a19b894a0 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -139,19 +139,6 @@ config SND_HDA_CODEC_CONEXANT snd-hda-codec-conexant. This module is automatically loaded at probing. -config SND_HDA_CODEC_CA0110 - bool "Build Creative CA0110-IBG codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Creative CA0110-IBG codec support in - snd-hda-intel driver, found on some Creative X-Fi cards. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0110. - This module is automatically loaded at probing. - config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index e3081d4586cc..50f9d0967251 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -13,7 +13,6 @@ snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-atihdmi-objs := patch_atihdmi.o -snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o @@ -41,9 +40,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_ATIHDMI obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o endif -ifdef CONFIG_SND_HDA_CODEC_CA0110 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o -endif ifdef CONFIG_SND_HDA_CODEC_CONEXANT obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o endif diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index b91f6ed5cc58..8820faf6c9d8 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -48,7 +48,6 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1095, "Silicon Image" }, { 0x10de, "Nvidia" }, { 0x10ec, "Realtek" }, - { 0x1102, "Creative" }, { 0x1106, "VIA" }, { 0x111d, "IDT" }, { 0x11c1, "LSI" }, @@ -175,23 +174,14 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, unsigned int verb, unsigned int parm) { struct hda_bus *bus = codec->bus; - unsigned int cmd, res; - int repeated = 0; + unsigned int res; - cmd = make_codec_cmd(codec, nid, direct, verb, parm); + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); - again: - if (!bus->ops.command(bus, cmd)) { + if (!bus->ops.command(bus, res)) res = bus->ops.get_response(bus); - if (res == -1 && bus->rirb_error) { - if (repeated++ < 1) { - snd_printd(KERN_WARNING "hda_codec: " - "Trying verb 0x%08x again\n", cmd); - goto again; - } - } - } else + else res = (unsigned int)-1; mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); @@ -1065,8 +1055,6 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* FIXME: more better hash key? */ #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) -#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) -#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) #define INFO_AMP_CAPS (1<<0) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) @@ -1157,32 +1145,19 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, } EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); -static unsigned int -query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, - unsigned int (*func)(struct hda_codec *, hda_nid_t)) +u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) { struct hda_amp_info *info; - info = get_alloc_amp_hash(codec, key); + info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); if (!info) return 0; if (!info->head.val) { + info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); info->head.val |= INFO_AMP_CAPS; - info->amp_caps = func(codec, nid); } return info->amp_caps; } - -static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); -} - -u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), - read_pin_cap); -} EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); /* @@ -1457,8 +1432,6 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.index = idx; - if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) - return NULL; strcpy(id.name, name); return snd_ctl_find_id(codec->bus->card, &id); } @@ -2348,8 +2321,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, if (wcaps & AC_WCAP_POWER) { unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (power_state == AC_PWRST_D3 && - wid_type == AC_WID_PIN) { + if (wid_type == AC_WID_PIN) { unsigned int pincap; /* * don't power down the widget if it controls @@ -2361,7 +2333,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, nid, 0, AC_VERB_GET_EAPD_BTLENABLE, 0); eapd &= 0x02; - if (eapd) + if (power_state == AC_PWRST_D3 && eapd) continue; } } @@ -2572,41 +2544,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); -static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val = 0; - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (!val || val == -1) - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - if (!val || val == -1) - return 0; - return val; -} - -static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), - get_pcm_param); -} - -static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (!streams || streams == -1) - streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (!streams || streams == -1) - return 0; - return streams; -} - -static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), - get_stream_param); -} - /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats * @codec: the HDA codec @@ -2625,8 +2562,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, { unsigned int i, val, wcaps; + val = 0; wcaps = get_wcaps(codec, nid); - val = query_pcm_param(codec, nid); + if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (val == -1) + return -EIO; + } + if (!val) + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); if (ratesp) { u32 rates = 0; @@ -2648,9 +2592,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u64 formats = 0; unsigned int streams, bps; - streams = query_stream_param(codec, nid); - if (!streams) + streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (streams == -1) return -EIO; + if (!streams) { + streams = snd_hda_param_read(codec, codec->afg, + AC_PAR_STREAM); + if (streams == -1) + return -EIO; + } bps = 0; if (streams & AC_SUPFMT_PCM) { @@ -2724,9 +2674,17 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, int i; unsigned int val = 0, rate, stream; - val = query_pcm_param(codec, nid); - if (!val) - return 0; + if (nid != codec->afg && + (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (val == -1) + return 0; + } + if (!val) { + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + if (val == -1) + return 0; + } rate = format & 0xff00; for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) @@ -2738,8 +2696,12 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, if (i >= AC_PAR_PCM_RATE_BITS) return 0; - stream = query_stream_param(codec, nid); - if (!stream) + stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (stream == -1) + return 0; + if (!stream && nid != codec->afg) + stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); + if (!stream || stream == -1) return 0; if (stream & AC_SUPFMT_PCM) { diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index cd8979c7670b..2fdecf4b0eb6 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -623,7 +623,6 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; unsigned int shutdown :1; /* being unloaded */ - unsigned int rirb_error:1; /* error in codec communication */ }; /* diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 04f19f8cad84..21e99cfa8c49 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -606,7 +606,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (!chip->rirb.cmds) { smp_rmb(); - bus->rirb_error = 0; return chip->rirb.res; /* the last value */ } if (time_after(jiffies, timeout)) @@ -626,10 +625,8 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) chip->irq = -1; pci_disable_msi(chip->pci); chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) { - bus->rirb_error = 1; + if (azx_acquire_irq(chip, 1) < 0) return -1; - } goto again; } @@ -649,12 +646,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) return -1; } - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout (ERROR): " - "last cmd=0x%08x\n", chip->last_cmd); - spin_lock_irq(&chip->reg_lock); - chip->rirb.cmds = 0; /* reset the index */ - bus->rirb_error = 1; - spin_unlock_irq(&chip->reg_lock); + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " + "switching to single_cmd mode: last cmd=0x%08x\n", + chip->last_cmd); + chip->rirb.rp = azx_readb(chip, RIRBWP); + chip->rirb.cmds = 0; + /* switch to single_cmd mode */ + chip->single_cmd = 1; + azx_free_cmd_io(chip); return -1; } @@ -1831,7 +1830,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, &pcm); if (err < 0) return err; - strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); + strcpy(pcm->name, cpcm->name); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; @@ -2359,11 +2358,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } strcpy(card->driver, "HDA-Intel"); - strlcpy(card->shortname, driver_short_names[chip->driver_type], - sizeof(card->shortname)); - snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx irq %i", - card->shortname, chip->addr, chip->irq); + strcpy(card->shortname, driver_short_names[chip->driver_type]); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -2516,11 +2513,6 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, - /* Creative X-Fi (CA0110-IBG) */ - { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), - .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, - .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, /* AMD 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/trunk/sound/pci/hda/patch_ca0110.c b/trunk/sound/pci/hda/patch_ca0110.c deleted file mode 100644 index 392d108c3558..000000000000 --- a/trunk/sound/pci/hda/patch_ca0110.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * HD audio interface patch for Creative X-Fi CA0110-IBG chip - * - * Copyright (c) 2008 Takashi Iwai - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -/* - */ - -struct ca0110_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - const char *input_labels[AUTO_PIN_LAST]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* - * PCM callbacks - */ -static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); - return 0; -} - -/* - */ - -static char *dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) - -static int ca0110_build_controls(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static char *prefix[AUTO_CFG_MAX_OUTS] = { - "Front", "Surround", NULL, "Side", "Multi" - }; - hda_nid_t mutenid; - int i, err; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) - mutenid = spec->out_pins[i]; - else - mutenid = spec->multiout.dac_nids[i]; - if (!prefix[i]) { - err = add_mono_switch(codec, mutenid, - "Center", 1); - if (err < 0) - return err; - err = add_mono_switch(codec, mutenid, - "LFE", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "Center", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "LFE", 1); - if (err < 0) - return err; - } else { - err = add_out_switch(codec, mutenid, - prefix[i]); - if (err < 0) - return err; - err = add_out_volume(codec, spec->multiout.dac_nids[i], - prefix[i]); - if (err < 0) - return err; - } - } - if (cfg->hp_outs) { - if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) - mutenid = cfg->hp_pins[0]; - else - mutenid = spec->multiout.dac_nids[i]; - - err = add_out_switch(codec, mutenid, "Headphone"); - if (err < 0) - return err; - if (spec->hp_dac) { - err = add_out_volume(codec, spec->hp_dac, "Headphone"); - if (err < 0) - return err; - } - } - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) - mutenid = spec->input_pins[i]; - else - mutenid = spec->adcs[i]; - err = add_in_switch(codec, mutenid, label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - -/* - */ -static struct hda_pcm_stream ca0110_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .ops = { - .open = ca0110_playback_pcm_open, - .prepare = ca0110_playback_pcm_prepare, - .cleanup = ca0110_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0110_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0110_capture_pcm_prepare, - .cleanup = ca0110_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0110_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0110_dig_playback_pcm_open, - .close = ca0110_dig_playback_pcm_close, - .prepare = ca0110_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream ca0110_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int ca0110_build_pcms(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0110 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0110 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0110_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0110_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static int ca0110_init(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - init_input(codec, cfg->dig_in_pin, spec->dig_in); - return 0; -} - -static void ca0110_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static struct hda_codec_ops ca0110_patch_ops = { - .build_controls = ca0110_build_controls, - .build_pcms = ca0110_build_pcms, - .init = ca0110_init, - .free = ca0110_free, -}; - - -static void parse_line_outs(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n; - unsigned int def_conf; - hda_nid_t nid; - - n = 0; - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) - continue; /* invalid pin */ - if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) - continue; - spec->out_pins[n++] = nid; - } - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = n; - spec->multiout.max_channels = n * 2; -} - -static void parse_hp_out(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - unsigned int def_conf; - hda_nid_t nid, dac; - - if (!cfg->hp_outs) - return; - nid = cfg->hp_pins[0]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) { - cfg->hp_outs = 0; - return; - } - if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) - return; - - for (i = 0; i < cfg->line_outs; i++) - if (dac == spec->dacs[i]) - break; - if (i >= cfg->line_outs) { - spec->hp_dac = dac; - spec->multiout.hp_nid = dac; - } -} - -static void parse_input(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, pin; - int n, i, j; - - n = 0; - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; - if (type != AC_WID_AUD_IN) - continue; - if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) - continue; - if (pin == cfg->dig_in_pin) { - spec->dig_in = nid; - continue; - } - for (j = 0; j < AUTO_PIN_LAST; j++) - if (cfg->input_pins[j] == pin) - break; - if (j >= AUTO_PIN_LAST) - continue; - spec->input_pins[n] = pin; - spec->input_labels[n] = auto_pin_cfg_labels[j]; - spec->adcs[n] = nid; - n++; - } - spec->num_inputs = n; -} - -static void parse_digital(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], - &spec->dig_out, 1) == 1) - spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; -} - -static int ca0110_parse_auto_config(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - - parse_line_outs(codec); - parse_hp_out(codec); - parse_digital(codec); - parse_input(codec); - return 0; -} - - -int patch_ca0110(struct hda_codec *codec) -{ - struct ca0110_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->bus->needs_damn_long_delay = 1; - - err = ca0110_parse_auto_config(codec); - if (err < 0) - goto error; - - codec->patch_ops = ca0110_patch_ops; - - return 0; - - error: - kfree(codec->spec); - codec->spec = NULL; - return err; -} - - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_ca0110[] = { - { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:1102000a"); -MODULE_ALIAS("snd-hda-codec-id:1102000b"); -MODULE_ALIAS("snd-hda-codec-id:1102000d"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); - -static struct hda_codec_preset_list ca0110_list = { - .preset = snd_hda_preset_ca0110, - .owner = THIS_MODULE, -}; - -static int __init patch_ca0110_init(void) -{ - return snd_hda_add_codec_preset(&ca0110_list); -} - -static void __exit patch_ca0110_exit(void) -{ - snd_hda_delete_codec_preset(&ca0110_list); -} - -module_init(patch_ca0110_init) -module_exit(patch_ca0110_exit) diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index db896121535a..b8a0d3e79272 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -205,7 +205,6 @@ enum { ALC882_ASUS_A7M, ALC885_MACPRO, ALC885_MBP3, - ALC885_MB5, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -254,15 +253,6 @@ enum { /* for GPIO Poll */ #define GPIO_MASK 0x03 -/* extra amp-initialization sequence types */ -enum { - ALC_INIT_NONE, - ALC_INIT_DEFAULT, - ALC_INIT_GPIO1, - ALC_INIT_GPIO2, - ALC_INIT_GPIO3, -}; - struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -332,7 +322,6 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ - int init_amp; /* for virtual master */ hda_nid_t vmaster_nid; @@ -926,26 +915,20 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -static void alc_automute_pin(struct hda_codec *codec) +static void alc_sku_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int present; - unsigned int nid = spec->autocfg.hp_pins[0]; - int i; + unsigned int hp_nid = spec->autocfg.hp_pins[0]; + unsigned int sp_nid = spec->autocfg.speaker_pins[0]; /* need to execute and sync at first */ - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, + snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; - if (!nid) - break; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->jack_present ? 0 : PIN_OUT); - } + spec->jack_present = (present & 0x80000000) != 0; + snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->jack_present ? 0 : PIN_OUT); } #if 0 /* it's broken in some acses -- temporarily disabled */ @@ -980,19 +963,16 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 28; else res >>= 26; - switch (res) { - case ALC880_HP_EVENT: - alc_automute_pin(codec); - break; - case ALC880_MIC_EVENT: + if (res == ALC880_HP_EVENT) + alc_sku_automute(codec); + + if (res == ALC880_MIC_EVENT) alc_mic_automute(codec); - break; - } } static void alc_inithook(struct hda_codec *codec) { - alc_automute_pin(codec); + alc_sku_automute(codec); alc_mic_automute(codec); } @@ -1014,21 +994,69 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } -static void alc_auto_init_amp(struct hda_codec *codec, int type) +/* 32-bit subsystem ID for BIOS loading in HD Audio codec. + * 31 ~ 16 : Manufacture ID + * 15 ~ 8 : SKU ID + * 7 ~ 0 : Assembly ID + * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 + */ +static void alc_subsystem_id(struct hda_codec *codec, + unsigned int porta, unsigned int porte, + unsigned int portd) { - unsigned int tmp; + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; + + ass = codec->subsystem_id & 0xffff; + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; - switch (type) { - case ALC_INIT_GPIO1: + /* + * 31~30 : port conetcivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + if (!(ass & 1) && !(ass & 0x100000)) + return; + if ((ass >> 30) != 1) /* no physical connection */ + return; + + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return; +do_sku: + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ + tmp = (ass & 0x38) >> 3; /* external Amp control */ + switch (tmp) { + case 1: snd_hda_sequence_write(codec, alc_gpio1_init_verbs); break; - case ALC_INIT_GPIO2: + case 3: snd_hda_sequence_write(codec, alc_gpio2_init_verbs); break; - case ALC_INIT_GPIO3: + case 7: snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; - case ALC_INIT_DEFAULT: + case 5: /* set EAPD output high */ switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x0f, 0, @@ -1082,7 +1110,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) tmp | 0x2010); break; case 0x10ec0888: - alc888_coef_init(codec); + /*alc888_coef_init(codec);*/ /* called in alc_init() */ break; case 0x10ec0267: case 0x10ec0268: @@ -1097,107 +1125,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) tmp | 0x3000); break; } - break; - } -} - -static void alc_init_auto_hp(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec->autocfg.hp_pins[0]) - return; - - if (!spec->autocfg.speaker_pins[0]) { - if (spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - spec->autocfg.speaker_pins[0] = - spec->autocfg.line_out_pins[0]; - else - return; - } - - snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - spec->autocfg.hp_pins[0]); - snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC880_HP_EVENT); - spec->unsol_event = alc_sku_unsol_event; -} - -/* check subsystem ID and set up device-specific initialization; - * return 1 if initialized, 0 if invalid SSID - */ -/* 32-bit subsystem ID for BIOS loading in HD Audio codec. - * 31 ~ 16 : Manufacture ID - * 15 ~ 8 : SKU ID - * 7 ~ 0 : Assembly ID - * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 - */ -static int alc_subsystem_id(struct hda_codec *codec, - hda_nid_t porta, hda_nid_t porte, - hda_nid_t portd) -{ - unsigned int ass, tmp, i; - unsigned nid; - struct alc_spec *spec = codec->spec; - - ass = codec->subsystem_id & 0xffff; - if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) - goto do_sku; - - /* invalid SSID, check the special NID pin defcfg instead */ - /* - * 31~30 : port conetcivity - * 29~21 : reserve - * 20 : PCBEEP input - * 19~16 : Check sum (15:1) - * 15~1 : Custom - * 0 : override - */ - nid = 0x1d; - if (codec->vendor_id == 0x10ec0260) - nid = 0x17; - ass = snd_hda_codec_get_pincfg(codec, nid); - snd_printd("realtek: No valid SSID, " - "checking pincfg 0x%08x for NID 0x%x\n", - ass, nid); - if (!(ass & 1) && !(ass & 0x100000)) - return 0; - if ((ass >> 30) != 1) /* no physical connection */ - return 0; - - /* check sum */ - tmp = 0; - for (i = 1; i < 16; i++) { - if ((ass >> i) & 1) - tmp++; - } - if (((ass >> 16) & 0xf) != tmp) - return 0; -do_sku: - snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", - ass & 0xffff, codec->vendor_id); - /* - * 0 : override - * 1 : Swap Jack - * 2 : 0 --> Desktop, 1 --> Laptop - * 3~5 : External Amplifier control - * 7~6 : Reserved - */ - tmp = (ass & 0x38) >> 3; /* external Amp control */ - switch (tmp) { - case 1: - spec->init_amp = ALC_INIT_GPIO1; - break; - case 3: - spec->init_amp = ALC_INIT_GPIO2; - break; - case 7: - spec->init_amp = ALC_INIT_GPIO3; - break; - case 5: - spec->init_amp = ALC_INIT_DEFAULT; + default: break; } @@ -1205,7 +1133,7 @@ static int alc_subsystem_id(struct hda_codec *codec, * when the external headphone out jack is plugged" */ if (!(ass & 0x8000)) - return 1; + return; /* * 10~8 : Jack location * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered @@ -1213,6 +1141,14 @@ static int alc_subsystem_id(struct hda_codec *codec, * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ + if (!spec->autocfg.speaker_pins[0]) { + if (spec->autocfg.line_out_pins[0]) + spec->autocfg.speaker_pins[0] = + spec->autocfg.line_out_pins[0]; + else + return; + } + if (!spec->autocfg.hp_pins[0]) { tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1222,23 +1158,23 @@ static int alc_subsystem_id(struct hda_codec *codec, else if (tmp == 2) spec->autocfg.hp_pins[0] = portd; else - return 1; + return; } + if (spec->autocfg.hp_pins[0]) + snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); - alc_init_auto_hp(codec); - return 1; -} +#if 0 /* it's broken in some acses -- temporarily disabled */ + if (spec->autocfg.input_pins[AUTO_PIN_MIC] && + spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) + snd_hda_codec_write(codec, + spec->autocfg.input_pins[AUTO_PIN_MIC], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); +#endif /* disabled */ -static void alc_ssid_check(struct hda_codec *codec, - hda_nid_t porta, hda_nid_t porte, hda_nid_t portd) -{ - if (!alc_subsystem_id(codec, porta, porte, portd)) { - struct alc_spec *spec = codec->spec; - snd_printd("realtek: " - "Enable default setup for auto mode as fallback\n"); - spec->init_amp = ALC_INIT_DEFAULT; - alc_init_auto_hp(codec); - } + spec->unsol_event = alc_sku_unsol_event; } /* @@ -1373,58 +1309,32 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { {} }; -static void alc_automute_amp(struct hda_codec *codec) +static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - unsigned int val, mute; - hda_nid_t nid; - int i; - - spec->jack_present = 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - nid = spec->autocfg.hp_pins[i]; - if (!nid) - break; - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (val & AC_PINSENSE_PRESENCE) { - spec->jack_present = 1; - break; - } - } - - mute = spec->jack_present ? HDA_AMP_MUTE : 0; + unsigned int present; + unsigned int bits; + /* Line out presence */ + present = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* HP out presence */ + present = present || snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; /* Toggle internal speakers muting */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; - if (!nid) - break; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + /* Toggle internal bass muting */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } -static void alc_automute_amp_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, + unsigned int res) { - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - if (res == ALC880_HP_EVENT) - alc_automute_amp(codec); + if (res >> 26 == ALC880_HP_EVENT) + alc888_fujitsu_xa3530_automute(codec); } -static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x17; /* line-out */ - spec->autocfg.hp_pins[1] = 0x1b; /* hp */ - spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ - spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - alc_automute_amp(codec); -} /* * ALC888 Acer Aspire 4930G model @@ -1491,13 +1401,22 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned int bits; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if (res >> 26 == ALC880_HP_EVENT) + alc888_acer_aspire_4930g_automute(codec); } /* @@ -2465,6 +2384,21 @@ static struct hda_verb alc880_beep_init_verbs[] = { { } }; +/* toggle speaker-output according to the hp-jack state */ +static void alc880_uniwill_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + /* auto-toggle front mic */ static void alc880_uniwill_mic_automute(struct hda_codec *codec) { @@ -2477,14 +2411,9 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } -static void alc880_uniwill_init_hook(struct hda_codec *codec) +static void alc880_uniwill_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - alc_automute_amp(codec); + alc880_uniwill_hp_automute(codec); alc880_uniwill_mic_automute(codec); } @@ -2495,22 +2424,24 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, * definition. 4bit tag is placed at 28 bit! */ switch (res >> 28) { + case ALC880_HP_EVENT: + alc880_uniwill_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc880_uniwill_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } -static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) +static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -2532,10 +2463,10 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, /* Looks like the unsol event is incompatible with the standard * definition. 4bit tag is placed at 28 bit! */ + if ((res >> 28) == ALC880_HP_EVENT) + alc880_uniwill_p53_hp_automute(codec); if ((res >> 28) == ALC880_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); - else - alc_automute_amp_unsol_event(codec, res); } /* @@ -2767,18 +2698,30 @@ static struct hda_verb alc880_lg_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_init_hook(struct hda_codec *codec) +static void alc880_lg_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x17; - alc_automute_amp(codec); +static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_automute(codec); } /* @@ -2852,21 +2795,33 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_init_hook(struct hda_codec *codec) +static void alc880_lg_lw_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); -} + unsigned int present; + unsigned char bits; -static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_lw_automute(codec); +} + +static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -2910,10 +2865,16 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc880_medion_rim_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); - /* toggle EAPD */ - if (spec->jack_present) + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + if (present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); else snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); @@ -2929,15 +2890,6 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, alc880_medion_rim_automute(codec); } -static void alc880_medion_rim_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc880_medion_rim_automute(codec); -} - #ifdef CONFIG_SND_HDA_POWER_SAVE static struct hda_amp_list alc880_loopbacks[] = { { 0x0b, HDA_INPUT, 0 }, @@ -2966,7 +2918,8 @@ static int alc_init(struct hda_codec *codec) unsigned int i; alc_fix_pll(codec); - alc_auto_init_amp(codec, spec->init_amp); + if (codec->vendor_id == 0x10ec0888) + alc888_coef_init(codec); for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); @@ -3796,7 +3749,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -3873,7 +3826,7 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_unsol_event, - .init_hook = alc880_uniwill_init_hook, + .init_hook = alc880_uniwill_automute, }, [ALC880_UNIWILL_P53] = { .mixers = { alc880_uniwill_p53_mixer }, @@ -3885,7 +3838,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -3899,7 +3852,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -3924,8 +3877,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_init_hook, + .unsol_event = alc880_lg_unsol_event, + .init_hook = alc880_lg_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -3940,8 +3893,8 @@ static struct alc_config_preset alc880_presets[] = { .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_lw_init_hook, + .unsol_event = alc880_lg_lw_unsol_event, + .init_hook = alc880_lg_lw_automute, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -3955,7 +3908,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_medion_rim_capture_source, .unsol_event = alc880_medion_rim_unsol_event, - .init_hook = alc880_medion_rim_init_hook, + .init_hook = alc880_medion_rim_automute, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { @@ -4240,6 +4193,7 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -4344,8 +4298,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -5721,6 +5673,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t nid; + alc_subsystem_id(codec, 0x10, 0x15, 0x0f); nid = spec->autocfg.line_out_pins[0]; if (nid) { int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -5830,8 +5783,6 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - alc_ssid_check(codec, 0x10, 0x15, 0x0f); - return 1; } @@ -6158,16 +6109,6 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; - -static struct hda_input_mux mb5_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - /* * 2ch mode */ @@ -6297,20 +6238,6 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), { } /* end */ }; - -static struct snd_kcontrol_new alc885_mb5_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, 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, 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), - { } /* end */ -}; static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -6538,38 +6465,6 @@ static struct hda_verb alc882_macpro_init_verbs[] = { { } }; -/* Macbook 5,1 */ -static struct hda_verb alc885_mb5_init_verbs[] = { - /* Front mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LineOut mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: output 0 (0x0d) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* HP Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; - /* Macbook Pro rev3 */ static struct hda_verb alc885_mbp3_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ @@ -6659,23 +6554,45 @@ static struct hda_verb alc885_imac24_init_verbs[] = { }; /* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_automute_init_hook(struct hda_codec *codec) +static void alc885_imac24_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc885_mbp3_init_hook(struct hda_codec *codec) +/* Processes unsolicited events. */ +static void alc885_imac24_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_imac24_automute(codec); +} + +static void alc885_mbp3_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +} +static void alc885_mbp3_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mbp3_automute(codec); } @@ -6700,25 +6617,24 @@ static struct hda_verb alc882_targa_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc882_targa_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); - snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - spec->jack_present ? 1 : 3); -} - -static void alc882_targa_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc882_targa_automute(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 26 bit! + */ + if (((res >> 26) == ALC880_HP_EVENT)) { alc882_targa_automute(codec); + } } static struct hda_verb alc882_asus_a7j_verbs[] = { @@ -6800,7 +6716,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc885_imac24_automute_init_hook(codec); + alc885_imac24_automute(codec); } /* @@ -6893,7 +6809,6 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_ASUS_A7J] = "asus-a7j", [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", - [ALC885_MB5] = "mb5", [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", @@ -6971,20 +6886,8 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc885_mbp3_init_hook, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mbp_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mbp3_unsol_event, + .init_hook = alc885_mbp3_automute, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -7008,7 +6911,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc885_imac24_unsol_event, .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { @@ -7025,7 +6928,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, .unsol_event = alc882_targa_unsol_event, - .init_hook = alc882_targa_init_hook, + .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, @@ -7105,6 +7008,7 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -7291,9 +7195,6 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b3800: /* MacbookPro4,1 - latter revision */ board_config = ALC885_MBP3; break; - case 0x106b3f00: /* Macbook 5,1 */ - board_config = ALC885_MB5; - break; default: /* ALC889A is handled better as ALC888-compatible */ if (codec->revision_id == 0x100101 || @@ -7875,6 +7776,8 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -8023,14 +7926,16 @@ static struct hda_verb alc883_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_init_hook(struct hda_codec *codec) +static void alc883_mitac_hp_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* auto-toggle front mic */ @@ -8047,6 +7952,25 @@ static void alc883_mitac_mic_automute(struct hda_codec *codec) } */ +static void alc883_mitac_automute(struct hda_codec *codec) +{ + alc883_mitac_hp_automute(codec); + /* alc883_mitac_mic_automute(codec); */ +} + +static void alc883_mitac_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_mitac_hp_automute(codec); + break; + case ALC880_MIC_EVENT: + /* alc883_mitac_mic_automute(codec); */ + break; + } +} + static struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -8164,15 +8088,29 @@ static struct hda_verb alc888_6st_dell_verbs[] = { { } }; -static void alc888_3st_hp_init_hook(struct hda_codec *codec) +static void alc888_3st_hp_front_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present, bits; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x18; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc888_3st_hp_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc888_3st_hp_front_automute(codec); + break; + } } static struct hda_verb alc888_3st_hp_verbs[] = { @@ -8269,18 +8207,56 @@ static struct hda_verb alc883_medion_md2_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_init_hook(struct hda_codec *codec) +static void alc883_medion_md2_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); +static void alc883_medion_md2_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_medion_md2_automute(codec); } /* toggle speaker-output according to the hp-jack state */ -#define alc883_tagra_init_hook alc882_targa_init_hook -#define alc883_tagra_unsol_event alc882_targa_unsol_event +static void alc883_tagra_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); +} + +static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_tagra_automute(codec); +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_clevo_m720_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) { @@ -8292,13 +8268,9 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +static void alc883_clevo_m720_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); + alc883_clevo_m720_hp_automute(codec); alc883_clevo_m720_mic_automute(codec); } @@ -8306,32 +8278,52 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_clevo_m720_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc883_clevo_m720_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } /* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) +static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); +static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_2ch_fujitsu_pi2515_automute(codec); } -static void alc883_haier_w66_init_hook(struct hda_codec *codec) +static void alc883_haier_w66_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0x80 : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + 0x80, bits); +} - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc883_haier_w66_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_haier_w66_automute(codec); } static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) @@ -8370,14 +8362,23 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_init_hook(struct hda_codec *codec) +static void alc883_acer_aspire_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[1] = 0x16; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + +static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_acer_aspire_automute(codec); } static struct hda_verb alc883_acer_eapd_verbs[] = { @@ -8398,29 +8399,75 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static void alc888_6st_dell_init_hook(struct hda_codec *codec) +static void alc888_6st_dell_front_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) +static void alc888_6st_dell_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; + switch (res >> 26) { + case ALC880_HP_EVENT: + /* printk(KERN_DEBUG "hp_event\n"); */ + alc888_6st_dell_front_automute(codec); + break; + } +} - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->autocfg.speaker_pins[4] = 0x1a; - alc_automute_amp(codec); +static void alc888_lenovo_sky_front_automute(struct hda_codec *codec) +{ + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc888_lenovo_sky_front_automute(codec); } /* @@ -8508,33 +8555,39 @@ static void alc883_nb_mic_automute(struct hda_codec *codec) 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); } -static void alc883_M90V_init_hook(struct hda_codec *codec) +static void alc883_M90V_speaker_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - alc_automute_pin(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); } static void alc883_mode2_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_M90V_speaker_automute(codec); + break; case ALC880_MIC_EVENT: alc883_nb_mic_automute(codec); break; - default: - alc_sku_unsol_event(codec, res); - break; } } static void alc883_mode2_inithook(struct hda_codec *codec) { - alc883_M90V_init_hook(codec); + alc883_M90V_speaker_automute(codec); alc883_nb_mic_automute(codec); } @@ -8551,13 +8604,32 @@ static struct hda_verb alc888_asus_eee1601_verbs[] = { { } /* end */ }; -static void alc883_eee1601_inithook(struct hda_codec *codec) +static void alc883_eee1601_speaker_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc_automute_pin(codec); +static void alc883_eee1601_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_eee1601_speaker_automute(codec); + break; + } +} + +static void alc883_eee1601_inithook(struct hda_codec *codec) +{ + alc883_eee1601_speaker_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -8770,7 +8842,7 @@ static struct alc_config_preset alc883_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_init_hook, + .init_hook = alc883_tagra_automute, }, [ALC883_TARGA_2ch_DIG] = { .mixers = { alc883_tagra_2ch_mixer}, @@ -8784,7 +8856,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_init_hook, + .init_hook = alc883_tagra_automute, }, [ALC883_ACER] = { .mixers = { alc883_base_mixer }, @@ -8809,8 +8881,8 @@ static struct alc_config_preset alc883_presets[] = { .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, - .init_hook = alc883_acer_aspire_init_hook, + .unsol_event = alc883_acer_aspire_unsol_event, + .init_hook = alc883_acer_aspire_automute, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_base_mixer, @@ -8829,8 +8901,8 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_acer_aspire_4930g_init_hook, + .unsol_event = alc888_acer_aspire_4930g_unsol_event, + .init_hook = alc888_acer_aspire_4930g_automute, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -8854,8 +8926,8 @@ static struct alc_config_preset alc883_presets[] = { .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, - .init_hook = alc883_medion_md2_init_hook, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -8876,7 +8948,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_clevo_m720_unsol_event, - .init_hook = alc883_clevo_m720_init_hook, + .init_hook = alc883_clevo_m720_automute, }, [ALC883_LENOVO_101E_2ch] = { .mixers = { alc883_lenovo_101e_2ch_mixer}, @@ -8900,8 +8972,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_medion_md2_init_hook, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -8925,8 +8997,8 @@ static struct alc_config_preset alc883_presets[] = { .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, - .init_hook = alc883_haier_w66_init_hook, + .unsol_event = alc883_haier_w66_unsol_event, + .init_hook = alc883_haier_w66_automute, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -8937,8 +9009,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_3st_hp_init_hook, + .unsol_event = alc888_3st_hp_unsol_event, + .init_hook = alc888_3st_hp_front_automute, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -8950,8 +9022,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_6st_dell_init_hook, + .unsol_event = alc888_6st_dell_unsol_event, + .init_hook = alc888_6st_dell_front_automute, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -8961,8 +9033,8 @@ static struct alc_config_preset alc883_presets[] = { .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, - .init_hook = alc883_mitac_init_hook, + .unsol_event = alc883_mitac_unsol_event, + .init_hook = alc883_mitac_automute, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -8974,8 +9046,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, + .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, + .init_hook = alc883_2ch_fujitsu_pi2515_automute, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -8992,8 +9064,8 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_fujitsu_xa3530_init_hook, + .unsol_event = alc888_fujitsu_xa3530_unsol_event, + .init_hook = alc888_fujitsu_xa3530_automute, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -9005,8 +9077,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_lenovo_sky_init_hook, + .unsol_event = alc883_lenovo_sky_unsol_event, + .init_hook = alc888_lenovo_sky_front_automute, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9034,7 +9106,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_asus_eee1601_capture_source, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc883_eee1601_unsol_event, .init_hook = alc883_eee1601_inithook, }, [ALC1200_ASUS_P5Q] = { @@ -9077,6 +9149,7 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -9239,7 +9312,6 @@ static int patch_alc883(struct hda_codec *codec) if (!spec->capsrc_nids) spec->capsrc_nids = alc883_capsrc_nids; spec->capture_style = CAPT_MIX; /* matrix-style capture */ - spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ break; case 0x10ec0889: spec->stream_name_analog = "ALC889 Analog"; @@ -9335,6 +9407,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 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("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + /* update HP, line and mono-out pins according to the master switch */ static void alc262_hp_master_update(struct hda_codec *codec) { @@ -9390,7 +9480,14 @@ static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, alc262_hp_wildwest_automute(codec); } -#define alc262_hp_master_sw_get alc260_hp_master_sw_get +static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + *ucontrol->value.integer.value = spec->master_sw; + return 0; +} static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -9406,17 +9503,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } -#define ALC262_HP_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hp_master_sw_get, \ - .put = alc262_hp_master_sw_put, \ - } - static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - ALC262_HP_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -9440,7 +9534,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { }; static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - ALC262_HP_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9467,13 +9567,32 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_init_hook(struct hda_codec *codec) +static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) { struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ - alc_automute_amp(codec); + if (force || !spec->sense_updated) { + unsigned int present; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->sense_updated = 1; + } + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, + spec->jack_present ? HDA_AMP_MUTE : 0); +} + +static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hp_t5735_automute(codec, 1); +} + +static void alc262_hp_t5735_init_hook(struct hda_codec *codec) +{ + alc262_hp_t5735_automute(codec, 1); } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -9519,139 +9638,53 @@ static struct hda_verb alc262_hp_rp5700_verbs[] = { {} }; -static struct hda_input_mux alc262_hp_rp5700_capture_source = { - .num_items = 1, - .items = { - { "Line", 0x1 }, - }, -}; - -/* bind hp and internal speaker mute (with plug check) as master switch */ -static void alc262_hippo_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; - hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; - unsigned int mute; - - /* HP */ - mute = spec->master_sw ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute internal speaker per jack sense */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - if (line_nid) - snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - if (speaker_nid && speaker_nid != line_nid) - snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - -#define alc262_hippo_master_sw_get alc262_hp_master_sw_get - -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hippo_master_update(codec); - return 1; -} - -#define ALC262_HIPPO_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hippo_master_sw_get, \ - .put = alc262_hippo_master_sw_put, \ - } - -static struct snd_kcontrol_new alc262_hippo_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 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("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc262_hippo1_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 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), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - unsigned int present; - - /* need to execute and sync at first */ - snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, hp_nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - alc262_hippo_master_update(codec); -} - -static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec); -} - -static void alc262_hippo_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); -} +static struct hda_input_mux alc262_hp_rp5700_capture_source = { + .num_items = 1, + .items = { + { "Line", 0x1 }, + }, +}; -static void alc262_hippo1_init_hook(struct hda_codec *codec) +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct alc_spec *spec = codec->spec; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); + /* change hp mute */ + change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) { + /* change speaker according to HP jack state */ + struct alc_spec *spec = codec->spec; + unsigned int mute; + if (spec->jack_present) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, + HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } + return change; } - static struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, 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("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -9660,8 +9693,8 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { }; static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), 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), @@ -9702,15 +9735,34 @@ static struct hda_verb alc262_tyan_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc262_tyan_init_hook(struct hda_codec *codec) +static void alc262_tyan_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute line output on ATX panel */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute line output if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } } +static void alc262_tyan_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_tyan_automute(codec); +} #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -9865,25 +9917,99 @@ static void alc262_dmic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); } +/* toggle speaker-output according to the hp-jack state */ +static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, bits); +} + + /* unsolicited event for HP jack sensing */ static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, unsigned int res) { + if ((res >> 26) == ALC880_HP_EVENT) + alc262_toshiba_s06_speaker_automute(codec); if ((res >> 26) == ALC880_MIC_EVENT) alc262_dmic_automute(codec); - else - alc_sku_unsol_event(codec, res); + } static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) +{ + alc262_toshiba_s06_speaker_automute(codec); + alc262_dmic_automute(codec); +} + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); - alc262_dmic_automute(codec); + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_hippo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo_automute(codec); +} + +static void alc262_hippo1_automute(struct hda_codec *codec) +{ + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_hippo1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo1_automute(codec); } /* @@ -10153,7 +10279,14 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, 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), @@ -10704,8 +10837,6 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x14, 0x1b); - return 1; } @@ -10808,7 +10939,7 @@ static struct alc_config_preset alc262_presets[] = { .input_mux = &alc262_capture_source, }, [ALC262_HIPPO] = { - .mixers = { alc262_hippo_mixer }, + .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -10818,7 +10949,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -10830,8 +10961,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo1_init_hook, + .unsol_event = alc262_hippo1_unsol_event, + .init_hook = alc262_hippo1_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -10893,7 +11024,7 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc262_hp_t5735_unsol_event, .init_hook = alc262_hp_t5735_init_hook, }, [ALC262_HP_RP5700] = { @@ -10925,7 +11056,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -10937,7 +11068,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -11002,7 +11133,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -11014,8 +11145,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc262_tyan_init_hook, + .unsol_event = alc262_tyan_unsol_event, + .init_hook = alc262_tyan_automute, }, }; @@ -11159,17 +11290,6 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_toshiba_mixer[] = { - /* output mixer control */ - 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), - { } -}; - /* bind Beep switches of both NID 0x0f and 0x10 */ static struct hda_bind_ctls alc268_bind_beep_sw = { .ops = &snd_hda_bind_sw, @@ -11193,6 +11313,8 @@ static struct hda_verb alc268_eapd_verbs[] = { }; /* Toshiba specific */ +#define alc268_toshiba_automute alc262_hippo_automute + static struct hda_verb alc268_toshiba_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } /* end */ @@ -11328,8 +11450,13 @@ static struct hda_verb alc268_acer_verbs[] = { }; /* unsolicited event for HP jack sensing */ -#define alc268_toshiba_unsol_event alc262_hippo_unsol_event -#define alc268_toshiba_init_hook alc262_hippo_init_hook +static void alc268_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_toshiba_automute(codec); +} static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) @@ -11404,15 +11531,30 @@ static struct hda_verb alc268_dell_verbs[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_init_hook(struct hda_codec *codec) +static void alc268_dell_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned int mute; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); + if (present & 0x80000000) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); +static void alc268_dell_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_dell_automute(codec); } +#define alc268_dell_init_hook alc268_dell_automute + static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -11431,6 +11573,16 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { { } }; +static void alc267_quanta_il1_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + present ? 0 : PIN_OUT); +} + static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -11442,13 +11594,9 @@ static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) present ? 0x00 : 0x01); } -static void alc267_quanta_il1_init_hook(struct hda_codec *codec) +static void alc267_quanta_il1_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); + alc267_quanta_il1_hp_automute(codec); alc267_quanta_il1_mic_automute(codec); } @@ -11456,12 +11604,12 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc267_quanta_il1_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc267_quanta_il1_mic_automute(codec); break; - default: - alc_sku_unsol_event(codec, res); - break; } } @@ -11935,7 +12083,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc267_quanta_il1_unsol_event, - .init_hook = alc267_quanta_il1_init_hook, + .init_hook = alc267_quanta_il1_automute, }, [ALC268_3ST] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -11953,7 +12101,7 @@ static struct alc_config_preset alc268_presets[] = { .input_mux = &alc268_capture_source, }, [ALC268_TOSHIBA] = { - .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, alc268_beep_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_toshiba_verbs }, @@ -11967,7 +12115,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook, + .init_hook = alc268_toshiba_automute, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -12030,7 +12178,7 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x02, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc268_dell_unsol_event, .init_hook = alc268_dell_init_hook, .input_mux = &alc268_capture_source, }, @@ -12050,7 +12198,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook + .init_hook = alc268_toshiba_automute }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -13772,6 +13920,7 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -13854,8 +14003,6 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); set_capture_mixer(spec); - alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); - return 1; } @@ -14464,6 +14611,19 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {} }; +/* toggle speaker-output according to the hp-jack state */ +static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -14476,13 +14636,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); } -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +static void alc861vd_lenovo_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); + alc861vd_lenovo_hp_automute(codec); alc861vd_lenovo_mic_automute(codec); } @@ -14490,12 +14646,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc861vd_lenovo_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc861vd_lenovo_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } @@ -14545,13 +14701,20 @@ static struct hda_verb alc861vd_dallas_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_init_hook(struct hda_codec *codec) +static void alc861vd_dallas_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc861vd_dallas_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -14665,7 +14828,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_init_hook, + .init_hook = alc861vd_lenovo_automute, }, [ALC861VD_DALLAS] = { .mixers = { alc861vd_dallas_mixer }, @@ -14675,8 +14838,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -14687,8 +14850,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -14703,7 +14866,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_init_hook, + .init_hook = alc861vd_lenovo_automute, }, }; @@ -14721,6 +14884,7 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -14938,8 +15102,6 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -15259,8 +15421,10 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { }; 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_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -15273,11 +15437,15 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { }; static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), @@ -15785,25 +15953,51 @@ static void alc662_eeepc_mic_automute(struct hda_codec *codec) static void alc662_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { + if ((res >> 26) == ALC880_HP_EVENT) + alc262_hippo1_automute( codec ); + if ((res >> 26) == ALC880_MIC_EVENT) alc662_eeepc_mic_automute(codec); - else - alc262_hippo_unsol_event(codec, res); } static void alc662_eeepc_inithook(struct hda_codec *codec) { - alc262_hippo1_init_hook(codec); + alc262_hippo1_automute( codec ); alc662_eeepc_mic_automute(codec); } -static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) +static void alc662_eeepc_ep20_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc262_hippo_master_update(codec); +/* unsolicited event for HP jack sensing */ +static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc662_eeepc_ep20_automute(codec); +} + +static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) +{ + alc662_eeepc_ep20_automute(codec); } static void alc663_m51va_speaker_automute(struct hda_codec *codec) @@ -16137,9 +16331,35 @@ static void alc663_g50v_inithook(struct hda_codec *codec) alc662_eeepc_mic_automute(codec); } +/* bind hp and internal speaker mute (with plug check) */ +static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc262_hippo1_automute(codec); + return change; +} + static struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc662_ecs_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -16184,8 +16404,6 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC663_ASUS_MODE4] = "asus-mode4", [ALC663_ASUS_MODE5] = "asus-mode5", [ALC663_ASUS_MODE6] = "asus-mode6", - [ALC272_DELL] = "dell", - [ALC272_DELL_ZM1] = "dell-zm1", [ALC662_AUTO] = "auto", }; @@ -16333,7 +16551,7 @@ static struct alc_config_preset alc662_presets[] = { .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc662_eeepc_ep20_unsol_event, .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { @@ -16708,6 +16926,7 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -16804,8 +17023,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index ecf53f755a09..03b3646018a1 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -100,7 +100,6 @@ enum { STAC_HP_M4, STAC_HP_DV5, STAC_HP_HDX, - STAC_HP_DV4_1222NR, STAC_92HD71BXX_MODELS }; @@ -1837,7 +1836,6 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = NULL, [STAC_HP_DV5] = NULL, [STAC_HP_HDX] = NULL, - [STAC_HP_DV4_1222NR] = NULL, }; static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { @@ -1849,7 +1847,6 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = "hp-m4", [STAC_HP_DV5] = "hp-dv5", [STAC_HP_HDX] = "hp-hdx", - [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", }; static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { @@ -1858,8 +1855,6 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_92HD71BXX_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, - "HP dv4-1222nr", STAC_HP_DV4_1222NR), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, @@ -4530,38 +4525,27 @@ static int stac92xx_resume(struct hda_codec *codec) return 0; } + /* - * using power check for controlling mute led of HP notebooks + * using power check for controlling mute led of HP HDX notebooks * check for mute state only on Speakers (nid = 0x10) * * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise * the LED is NOT working properly ! - * - * Changed name to reflect that it now works for any designated - * model, not just HP HDX. */ #ifdef CONFIG_SND_HDA_POWER_SAVE -static int stac92xx_hp_check_power_status(struct hda_codec *codec, +static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; - unsigned int gpio_bit = 0; /* gets rid of compiler warning */ - - switch (spec->board_config) { - case STAC_HP_DV4_1222NR: - gpio_bit = 0x01; - break; - case STAC_HP_HDX: - gpio_bit = 0x08; - } if (nid == 0x10) { if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) - spec->gpio_data &= ~gpio_bit; /* orange */ + spec->gpio_data &= ~0x08; /* orange */ else - spec->gpio_data |= gpio_bit; /* white */ + spec->gpio_data |= 0x08; /* white */ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, @@ -5240,22 +5224,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_smuxes = 0; spec->num_dmuxes = 1; break; - case STAC_HP_DV4_1222NR: - spec->num_dmics = 1; - /* I don't know if it needs 1 or 2 smuxes - will wait for - * bug reports to fix if needed - */ - spec->num_smuxes = 1; - spec->num_dmuxes = 1; -#ifdef CONFIG_SND_HDA_POWER_SAVE - /* This controls MUTE LED */ - spec->gpio_mask |= 0x01; - spec->gpio_dir |= 0x01; - spec->gpio_data |= 0x01; - codec->patch_ops.check_power_status = - stac92xx_hp_check_power_status; -#endif - /* fallthrough */ case STAC_HP_DV5: snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); @@ -5276,7 +5244,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) /* register check_power_status callback. */ codec->patch_ops.check_power_status = - stac92xx_hp_check_power_status; + stac92xx_hp_hdx_check_power_status; #endif break; }; diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index b25a5cc637d6..8e004fb6961a 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -205,7 +205,7 @@ struct via_spec { /* playback */ struct hda_multi_out multiout; - hda_nid_t extra_dig_out_nid; + hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; @@ -731,21 +731,6 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_dig_close(codec, &spec->multiout); } -/* setup SPDIF output stream */ -static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, - unsigned int stream_tag, unsigned int format) -{ - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - /* turn on again (if needed) */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); -} - static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -753,19 +738,16 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - hda_nid_t nid; - - /* 1st or 2nd S/PDIF */ - if (substream->number == 0) - nid = spec->multiout.dig_out_nid; - else if (substream->number == 1) - nid = spec->extra_dig_out_nid; - else - return -1; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} - mutex_lock(&codec->spdif_mutex); - setup_dig_playback_stream(codec, nid, stream_tag, format); - mutex_unlock(&codec->spdif_mutex); +static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); return 0; } @@ -842,7 +824,8 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -874,13 +857,6 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; spec->multiout.share_spdif = 1; - - if (spec->extra_dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->extra_dig_out_nid); - if (err < 0) - return err; - } } if (spec->dig_in_nid) { err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); @@ -1013,10 +989,6 @@ static void via_unsol_event(struct hda_codec *codec, via_gpio_control(codec); } -static hda_nid_t slave_dig_outs[] = { - 0, -}; - static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1051,8 +1023,9 @@ static int via_init(struct hda_codec *codec) snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); - /* no slave outs */ - codec->slave_dig_outs = slave_dig_outs; + /* assign slave outs */ + if (spec->slave_dig_outs[0]) + codec->slave_dig_outs = spec->slave_dig_outs; return 0; } @@ -2134,7 +2107,8 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -2589,14 +2563,15 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { }; static struct hda_pcm_stream vt1708S_pcm_digital_playback = { - .substreams = 2, + .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -2805,14 +2780,37 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, return 0; } +/* fill out digital output widgets; one for master and one for slave outputs */ +static void fill_dig_outs(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t nid; + int conn; + + nid = spec->autocfg.dig_out_pins[i]; + if (!nid) + continue; + conn = snd_hda_get_connections(codec, nid, &nid, 1); + if (conn < 1) + continue; + if (!spec->multiout.dig_out_nid) + spec->multiout.dig_out_nid = nid; + else { + spec->slave_dig_outs[0] = nid; + break; /* at most two dig outs */ + } + } +} + static int vt1708S_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; - static hda_nid_t vt1708s_ignore[] = {0x21, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - vt1708s_ignore); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); @@ -2833,10 +2831,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; - - spec->extra_dig_out_nid = 0x15; + fill_dig_outs(codec); if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; @@ -3000,7 +2995,8 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -3128,10 +3124,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; - static hda_nid_t vt1702_ignore[] = {0x1C, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - vt1702_ignore); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); @@ -3152,10 +3146,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; - - spec->extra_dig_out_nid = 0x1B; + fill_dig_outs(codec); if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list;