diff --git a/[refs] b/[refs] index 178ba97b4988..87ed0bdb4103 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 44c76a960a62fcc46cbcaa0a22a34e666a729329 +refs/heads/master: 0d6df67583bb40fdc365210740bcce0bd27420f7 diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 9af64c508ab4..936699e4f04b 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -860,8 +860,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. [Multiple options for each card instance] model - force the model name - position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF, - 3 = VIACOMBO, 4 = COMBO) + position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) When the bit 8 (0x100) is set, the lower 8 bits are used as the "fixed" codec slots; i.e. the driver probes the @@ -926,11 +925,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. (Usually SD_LPIB register is more accurate than the position buffer.) - position_fix=3 is specific to VIA devices. The position - of the capture stream is checked from both LPIB and POSBUF - values. position_fix=4 is a combination mode, using LPIB - for playback and POSBUF for capture. - NB: If you get many "azx_get_response timeout" messages at loading, it's likely a problem of interrupts (e.g. ACPI irq routing). Try to boot with options like "pci=noacpi". Also, you diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt index d97d992ced14..c8c54544abc5 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt @@ -8,10 +8,37 @@ ALC880 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out 6stack 6-jack in back, 2-jack in front 6stack-digout 6-jack with a SPDIF out + w810 3-jack + z71v 3-jack (HP shared SPDIF) + asus 3-jack (ASUS Mobo) + asus-w1v ASUS W1V + asus-dig ASUS with SPDIF out + asus-dig2 ASUS with SPDIF out (using GPIO2) + uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) + F1734 2-jack + lg LG laptop (m1 express dual) + lg-lw LG LW20/LW25 laptop + tcl TCL S700 + clevo Clevo laptops (m520G, m665n) + medion Medion Rim 2150 + test for testing/debugging purpose, almost all controls can be + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) ALC260 ====== - N/A + fujitsu Fujitsu S7020 + 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 + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) ALC262 ====== @@ -43,7 +70,55 @@ ALC680 ALC882/883/885/888/889 ====================== - N/A + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + arima Arima W820Di1 + targa Targa T8, MSI-1049 T8 + asus-a7j ASUS A7J + asus-a7m ASUS A7M + macpro MacPro support + mb5 Macbook 5,1 + macmini3 Macmini 3,1 + mba21 Macbook Air 2,1 + mbp3 Macbook Pro rev3 + imac24 iMac 24'' with jack detection + imac91 iMac 9,1 + w2jc ASUS W2JC + 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883) + alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883) + 3stack-6ch 3-jack 6-channel + 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O + 6stack-dig-demo 6-jack digital for Intel demo board + acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G + acer-aspire-6530g Acer Aspire 6530G + acer-aspire-7730g Acer Aspire 7730G + acer-aspire-8930g Acer Aspire 8930G + medion Medion Laptops + targa-dig Targa/MSI + targa-2ch-dig Targa/MSI with 2-channel + targa-8ch-dig Targa/MSI with 8-channel (MSI GX620) + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) + lenovo-101e Lenovo 101E + lenovo-nb0763 Lenovo NB0763 + lenovo-ms7195-dig Lenovo MS7195 + lenovo-sky Lenovo Sky + haier-w66 Haier W66 + 3stack-hp HP machines with 3stack (Lucknow, Samba boards) + 6stack-dell Dell machines with 6stack (Inspiron 530) + mitac Mitac 8252D + clevo-m540r Clevo M540R (6ch + digital) + clevo-m720 Clevo M720 laptop series + fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 + 3stack-6ch-intel Intel DG33* boards + intel-alc889a Intel IbexPeak with ALC889A + intel-x58 Intel DX58 with ALC889 + asus-p5q ASUS P5Q-EM boards + mb31 MacBook 3,1 + sony-vaio-tt Sony VAIO TT + auto auto-config reading BIOS (default) ALC861/660 ========== diff --git a/trunk/Documentation/sound/alsa/HD-Audio.txt b/trunk/Documentation/sound/alsa/HD-Audio.txt index 7813c06a5c71..91fee3b45fb8 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio.txt @@ -59,12 +59,7 @@ a case, you can change the default method via `position_fix` option. `position_fix=1` means to use LPIB method explicitly. `position_fix=2` means to use the position-buffer. `position_fix=3` means to use a combination of both methods, needed -for some VIA controllers. The capture stream position is corrected -by comparing both LPIB and position-buffer values. -`position_fix=4` is another combination available for all controllers, -and uses LPIB for the playback and the position-buffer for the capture -streams. -0 is the default value for all other +for some VIA and ATI controllers. 0 is the default value for all other controllers, the automatic check and fallback to LPIB as described in the above. If you get a problem of repeated sounds, this option might help. diff --git a/trunk/include/sound/control.h b/trunk/include/sound/control.h index eff96dc7a278..b2796e83c7ac 100644 --- a/trunk/include/sound/control.h +++ b/trunk/include/sound/control.h @@ -227,11 +227,6 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master, return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); } -int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl, - void (*hook)(void *private_data, int), - void *private_data); -void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl); - /* * Helper functions for jack-detection controls */ diff --git a/trunk/include/sound/core.h b/trunk/include/sound/core.h index cea1b5426dfa..5ab255f196cc 100644 --- a/trunk/include/sound/core.h +++ b/trunk/include/sound/core.h @@ -417,7 +417,6 @@ static inline int __snd_bug_on(int cond) #define gameport_get_port_data(gp) (gp)->port_data #endif -#ifdef CONFIG_PCI /* PCI quirk list helper */ struct snd_pci_quirk { unsigned short subvendor; /* PCI subvendor ID */ @@ -457,6 +456,5 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); const struct snd_pci_quirk * snd_pci_quirk_lookup_id(u16 vendor, u16 device, const struct snd_pci_quirk *list); -#endif #endif /* __SOUND_CORE_H */ diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index 4ae9e22c4827..0cf91b2f08ca 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -264,7 +264,7 @@ struct snd_pcm_hw_constraint_ratdens { struct snd_pcm_hw_constraint_list { unsigned int count; - const unsigned int *list; + unsigned int *list; unsigned int mask; }; @@ -781,8 +781,7 @@ void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interva unsigned int k, struct snd_interval *c); void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, const struct snd_interval *b, struct snd_interval *c); -int snd_interval_list(struct snd_interval *i, unsigned int count, - const unsigned int *list, unsigned int mask); +int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask); int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, struct snd_ratnum *rats, unsigned int *nump, unsigned int *denp); diff --git a/trunk/include/sound/version.h b/trunk/include/sound/version.h index cc75024c1089..8fc5321e1ecc 100644 --- a/trunk/include/sound/version.h +++ b/trunk/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.25" +#define CONFIG_SND_VERSION "1.0.24" #define CONFIG_SND_DATE "" diff --git a/trunk/include/sound/ymfpci.h b/trunk/include/sound/ymfpci.h index 41199664666b..444cd6ba0ba7 100644 --- a/trunk/include/sound/ymfpci.h +++ b/trunk/include/sound/ymfpci.h @@ -366,8 +366,6 @@ struct snd_ymfpci { #ifdef CONFIG_PM u32 *saved_regs; u32 saved_ydsxgr_mode; - u16 saved_dsxg_legacy; - u16 saved_dsxg_elegacy; #endif }; diff --git a/trunk/sound/aoa/codecs/onyx.c b/trunk/sound/aoa/codecs/onyx.c index 270790d384e2..762af68c8996 100644 --- a/trunk/sound/aoa/codecs/onyx.c +++ b/trunk/sound/aoa/codecs/onyx.c @@ -1132,4 +1132,15 @@ static struct i2c_driver onyx_driver = { .id_table = onyx_i2c_id, }; -module_i2c_driver(onyx_driver); +static int __init onyx_init(void) +{ + return i2c_add_driver(&onyx_driver); +} + +static void __exit onyx_exit(void) +{ + i2c_del_driver(&onyx_driver); +} + +module_init(onyx_init); +module_exit(onyx_exit); diff --git a/trunk/sound/aoa/codecs/tas.c b/trunk/sound/aoa/codecs/tas.c index 8e63d1f35ce1..fd2188c3df2b 100644 --- a/trunk/sound/aoa/codecs/tas.c +++ b/trunk/sound/aoa/codecs/tas.c @@ -1026,4 +1026,15 @@ static struct i2c_driver tas_driver = { .id_table = tas_i2c_id, }; -module_i2c_driver(tas_driver); +static int __init tas_init(void) +{ + return i2c_add_driver(&tas_driver); +} + +static void __exit tas_exit(void) +{ + i2c_del_driver(&tas_driver); +} + +module_init(tas_init); +module_exit(tas_exit); diff --git a/trunk/sound/core/compress_offload.c b/trunk/sound/core/compress_offload.c index a68aed7fce02..dac3633507c9 100644 --- a/trunk/sound/core/compress_offload.c +++ b/trunk/sound/core/compress_offload.c @@ -441,22 +441,19 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) params = kmalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; - if (copy_from_user(params, (void __user *)arg, sizeof(*params))) { - retval = -EFAULT; - goto out; - } + if (copy_from_user(params, (void __user *)arg, sizeof(*params))) + return -EFAULT; retval = snd_compr_allocate_buffer(stream, params); if (retval) { - retval = -ENOMEM; - goto out; + kfree(params); + return -ENOMEM; } retval = stream->ops->set_params(stream, params); if (retval) goto out; stream->runtime->state = SNDRV_PCM_STATE_SETUP; - } else { + } else return -EPERM; - } out: kfree(params); return retval; diff --git a/trunk/sound/core/control.c b/trunk/sound/core/control.c index 2487a6bb1c54..819a5c579a39 100644 --- a/trunk/sound/core/control.c +++ b/trunk/sound/core/control.c @@ -1313,7 +1313,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, err = -EPERM; goto __kctl_end; } - err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); + err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); if (err > 0) { up_read(&card->controls_rwsem); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); diff --git a/trunk/sound/core/init.c b/trunk/sound/core/init.c index 068cf08d3ffb..3ac49b1b7cb8 100644 --- a/trunk/sound/core/init.c +++ b/trunk/sound/core/init.c @@ -480,104 +480,74 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -/* retrieve the last word of shortname or longname */ -static const char *retrieve_id_from_card_name(const char *name) +static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) { - const char *spos = name; - - while (*name) { - if (isspace(*name) && isalnum(name[1])) - spos = name + 1; - name++; - } - return spos; -} - -/* return true if the given id string doesn't conflict any other card ids */ -static bool card_id_ok(struct snd_card *card, const char *id) -{ - int i; - if (!snd_info_check_reserved_words(id)) - return false; - for (i = 0; i < snd_ecards_limit; i++) { - if (snd_cards[i] && snd_cards[i] != card && - !strcmp(snd_cards[i]->id, id)) - return false; - } - return true; -} - -/* copy to card->id only with valid letters from nid */ -static void copy_valid_id_string(struct snd_card *card, const char *src, - const char *nid) -{ - char *id = card->id; - - while (*nid && !isalnum(*nid)) - nid++; - if (isdigit(*nid)) - *id++ = isalpha(*src) ? *src : 'D'; - while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) { - if (isalnum(*nid)) - *id++ = *nid; - nid++; - } - *id = 0; -} - -/* Set card->id from the given string - * If the string conflicts with other ids, add a suffix to make it unique. - */ -static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, - const char *nid) -{ - int len, loops; - bool with_suffix; - bool is_default = false; + int i, len, idx_flag = 0, loops = SNDRV_CARDS; + const char *spos, *src; char *id; - copy_valid_id_string(card, src, nid); + if (nid == NULL) { + id = card->shortname; + spos = src = id; + while (*id != '\0') { + if (*id == ' ') + spos = id + 1; + id++; + } + } else { + spos = src = nid; + } id = card->id; + while (*spos != '\0' && !isalnum(*spos)) + spos++; + if (isdigit(*spos)) + *id++ = isalpha(src[0]) ? src[0] : 'D'; + while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { + if (isalnum(*spos)) + *id++ = *spos; + spos++; + } + *id = '\0'; - again: - /* use "Default" for obviously invalid strings - * ("card" conflicts with proc directories) - */ - if (!*id || !strncmp(id, "card", 4)) { + id = card->id; + + if (*id == '\0') strcpy(id, "Default"); - is_default = true; - } - with_suffix = false; - for (loops = 0; loops < SNDRV_CARDS; loops++) { - if (card_id_ok(card, id)) - return; /* OK */ + while (1) { + if (loops-- == 0) { + snd_printk(KERN_ERR "unable to set card id (%s)\n", id); + strcpy(card->id, card->proc_root->name); + return; + } + if (!snd_info_check_reserved_words(id)) + goto __change; + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) + goto __change; + } + break; + __change: len = strlen(id); - if (!with_suffix) { - /* add the "_X" suffix */ - char *spos = id + len; - if (len > sizeof(card->id) - 3) - spos = id + sizeof(card->id) - 3; - strcpy(spos, "_1"); - with_suffix = true; - } else { - /* modify the existing suffix */ - if (id[len - 1] != '9') - id[len - 1]++; + if (idx_flag) { + if (id[len-1] != '9') + id[len-1]++; else - id[len - 1] = 'A'; + id[len-1] = 'A'; + } else if ((size_t)len <= sizeof(card->id) - 3) { + strcat(id, "_1"); + idx_flag++; + } else { + spos = id + len - 2; + if ((size_t)len <= sizeof(card->id) - 2) + spos++; + *(char *)spos++ = '_'; + *(char *)spos++ = '1'; + *(char *)spos++ = '\0'; + idx_flag++; } } - /* fallback to the default id */ - if (!is_default) { - *id = 0; - goto again; - } - /* last resort... */ - snd_printk(KERN_ERR "unable to set card id (%s)\n", id); - if (card->proc_root->name) - strcpy(card->id, card->proc_root->name); } /** @@ -594,7 +564,7 @@ void snd_card_set_id(struct snd_card *card, const char *nid) if (card->id[0] != '\0') return; mutex_lock(&snd_card_mutex); - snd_card_set_id_no_lock(card, nid, nid); + snd_card_set_id_no_lock(card, nid); mutex_unlock(&snd_card_mutex); } EXPORT_SYMBOL(snd_card_set_id); @@ -626,12 +596,22 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, memcpy(buf1, buf, copy); buf1[copy] = '\0'; mutex_lock(&snd_card_mutex); - if (!card_id_ok(NULL, buf1)) { + if (!snd_info_check_reserved_words(buf1)) { + __exist: mutex_unlock(&snd_card_mutex); return -EEXIST; } + for (idx = 0; idx < snd_ecards_limit; idx++) { + if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { + if (card == snd_cards[idx]) + goto __ok; + else + goto __exist; + } + } strcpy(card->id, buf1); snd_info_card_id_change(card); +__ok: mutex_unlock(&snd_card_mutex); return count; @@ -685,18 +665,7 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - if (*card->id) { - /* make a unique id name from the given string */ - char tmpid[sizeof(card->id)]; - memcpy(tmpid, card->id, sizeof(card->id)); - snd_card_set_id_no_lock(card, tmpid, tmpid); - } else { - /* create an id from either shortname or longname */ - const char *src; - src = *card->shortname ? card->shortname : card->longname; - snd_card_set_id_no_lock(card, src, - retrieve_id_from_card_name(src)); - } + snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); diff --git a/trunk/sound/core/misc.c b/trunk/sound/core/misc.c index 768167925409..465f0ce772cb 100644 --- a/trunk/sound/core/misc.c +++ b/trunk/sound/core/misc.c @@ -72,7 +72,7 @@ void __snd_printk(unsigned int level, const char *path, int line, char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV"; #endif -#ifdef CONFIG_SND_DEBUG +#ifdef CONFIG_SND_DEBUG if (debug < level) return; #endif diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index 4d18941178e6..3420bd3da5d7 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -1029,8 +1029,7 @@ static int snd_interval_ratden(struct snd_interval *i, * * Returns non-zero if the value is changed, zero if not changed. */ -int snd_interval_list(struct snd_interval *i, unsigned int count, - const unsigned int *list, unsigned int mask) +int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) { unsigned int k; struct snd_interval list_range; diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 3fe99e644eb8..25ed9fe41b89 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -1586,18 +1586,12 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) struct file *file; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; - struct snd_pcm_group *group; file = snd_pcm_file_fd(fd); if (!file) return -EBADFD; pcm_file = file->private_data; substream1 = pcm_file->substream; - group = kmalloc(sizeof(*group), GFP_KERNEL); - if (!group) { - res = -ENOMEM; - goto _nolock; - } down_write(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || @@ -1610,7 +1604,11 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _end; } if (!snd_pcm_stream_linked(substream)) { - substream->group = group; + substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); + if (substream->group == NULL) { + res = -ENOMEM; + goto _end; + } spin_lock_init(&substream->group->lock); INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); @@ -1622,10 +1620,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); - _nolock: fput(file); - if (res < 0) - kfree(group); return res; } diff --git a/trunk/sound/core/vmaster.c b/trunk/sound/core/vmaster.c index 14a286a7bf2b..130cfe677d60 100644 --- a/trunk/sound/core/vmaster.c +++ b/trunk/sound/core/vmaster.c @@ -37,8 +37,6 @@ struct link_master { struct link_ctl_info info; int val; /* the master value */ unsigned int tlv[4]; - void (*hook)(void *private_data, int); - void *hook_private_data; }; /* @@ -128,9 +126,7 @@ static int master_init(struct link_master *master) master->info.count = 1; /* always mono */ /* set full volume as default (= no attenuation) */ master->val = master->info.max_val; - if (master->hook) - master->hook(master->hook_private_data, master->val); - return 1; + return 0; } return -ENOENT; } @@ -333,8 +329,6 @@ static int master_put(struct snd_kcontrol *kcontrol, slave_put_val(slave, uval); } kfree(uval); - if (master->hook && !err) - master->hook(master->hook_private_data, master->val); return 1; } @@ -414,41 +408,3 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, return kctl; } EXPORT_SYMBOL(snd_ctl_make_virtual_master); - -/** - * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control - * @kcontrol: vmaster kctl element - * @hook: the hook function - * - * Adds the given hook to the vmaster control element so that it's called - * at each time when the value is changed. - */ -int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, - void (*hook)(void *private_data, int), - void *private_data) -{ - struct link_master *master = snd_kcontrol_chip(kcontrol); - master->hook = hook; - master->hook_private_data = private_data; - return 0; -} -EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook); - -/** - * snd_ctl_sync_vmaster_hook - Sync the vmaster hook - * @kcontrol: vmaster kctl element - * - * Call the hook function to synchronize with the current value of the given - * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't - * exist. - */ -void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol) -{ - struct link_master *master; - if (!kcontrol) - return; - master = snd_kcontrol_chip(kcontrol); - if (master->hook) - master->hook(master->hook_private_data, master->val); -} -EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook); diff --git a/trunk/sound/isa/sb/emu8000_patch.c b/trunk/sound/isa/sb/emu8000_patch.c index c99c6078be33..e09f144177f5 100644 --- a/trunk/sound/isa/sb/emu8000_patch.c +++ b/trunk/sound/isa/sb/emu8000_patch.c @@ -22,6 +22,7 @@ #include "emu8000_local.h" #include #include +#include static int emu8000_reset_addr; module_param(emu8000_reset_addr, int, 0444); diff --git a/trunk/sound/pci/au88x0/au88x0.h b/trunk/sound/pci/au88x0/au88x0.h index 466a5c8e8354..bb938153a964 100644 --- a/trunk/sound/pci/au88x0/au88x0.h +++ b/trunk/sound/pci/au88x0/au88x0.h @@ -26,7 +26,7 @@ #include #include #include -#include + #endif #ifndef CHIP_AU8820 @@ -107,14 +107,6 @@ #define NR_WTPB 0x20 /* WT channels per each bank. */ #define NR_PCM 0x10 -struct pcm_vol { - struct snd_kcontrol *kctl; - int active; - int dma; - int mixin[4]; - int vol[4]; -}; - /* Structs */ typedef struct { //int this_08; /* Still unknown */ @@ -176,7 +168,6 @@ struct snd_vortex { /* Xtalk canceler */ int xt_mode; /* 1: speakers, 0:headphones. */ #endif - struct pcm_vol pcm_vol[NR_PCM]; int isquad; /* cache of extended ID codec flag. */ @@ -248,7 +239,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt); /* Connection stuff. */ static void vortex_connect_default(vortex_t * vortex, int en); static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, - int dir, int type, int subdev); + int dir, int type); static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype); #ifndef CHIP_AU8810 diff --git a/trunk/sound/pci/au88x0/au88x0_core.c b/trunk/sound/pci/au88x0/au88x0_core.c index 525f881f0409..6933a27a5d76 100644 --- a/trunk/sound/pci/au88x0/au88x0_core.c +++ b/trunk/sound/pci/au88x0/au88x0_core.c @@ -2050,6 +2050,8 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } /* Default Connections */ +static int +vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type); static void vortex_connect_default(vortex_t * vortex, int en) { @@ -2109,13 +2111,15 @@ static void vortex_connect_default(vortex_t * vortex, int en) Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. */ static int -vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, - int type, int subdev) +vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) { stream_t *stream; int i, en; - struct pcm_vol *p; + if ((nr_ch == 3) + || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) + return -EBUSY; + if (dma >= 0) { en = 0; vortex_adb_checkinout(vortex, @@ -2246,14 +2250,6 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, MIX_DEFIGAIN); #endif } - if (stream->type == VORTEX_PCM_ADB && en) { - p = &vortex->pcm_vol[subdev]; - p->dma = dma; - for (i = 0; i < nr_ch; i++) - p->mixin[i] = mix[i]; - for (i = 0; i < ch_top; i++) - p->vol[i] = 0; - } } #ifndef CHIP_AU8820 else { @@ -2477,7 +2473,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) hwread(vortex->mmio, VORTEX_IRQ_STAT); handled = 1; } - if ((source & IRQ_MIDI) && vortex->rmidi) { + if (source & IRQ_MIDI) { snd_mpu401_uart_interrupt(vortex->irq, vortex->rmidi->private_data); handled = 1; diff --git a/trunk/sound/pci/au88x0/au88x0_pcm.c b/trunk/sound/pci/au88x0/au88x0_pcm.c index e59f120742a4..0ef2f9712208 100644 --- a/trunk/sound/pci/au88x0/au88x0_pcm.c +++ b/trunk/sound/pci/au88x0/au88x0_pcm.c @@ -122,18 +122,6 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { .mask = 0, }; #endif - -static void vortex_notify_pcm_vol_change(struct snd_card *card, - struct snd_kcontrol *kctl, int activate) -{ - if (activate) - kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - else - kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | - SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); -} - /* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { @@ -242,14 +230,12 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type, - substream->number); + stream->type); /* Alloc routes. */ dma = vortex_adb_allocroute(chip, -1, params_channels(hw_params), - substream->stream, type, - substream->number); + substream->stream, type); if (dma < 0) { spin_unlock_irq(&chip->lock); return dma; @@ -260,11 +246,6 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, vortex_adbdma_setbuffers(chip, dma, params_period_bytes(hw_params), params_periods(hw_params)); - if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { - chip->pcm_vol[substream->number].active = 1; - vortex_notify_pcm_vol_change(chip->card, - chip->pcm_vol[substream->number].kctl, 1); - } } #ifndef CHIP_AU8810 else { @@ -294,18 +275,10 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) spin_lock_irq(&chip->lock); // Delete audio routes. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { - if (stream != NULL) { - if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { - chip->pcm_vol[substream->number].active = 0; - vortex_notify_pcm_vol_change(chip->card, - chip->pcm_vol[substream->number].kctl, - 0); - } + if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type, - substream->number); - } + stream->type); } #ifndef CHIP_AU8810 else { @@ -533,83 +506,6 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { }, }; -/* subdevice PCM Volume control */ - -static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - vortex_t *vortex = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); - uinfo->value.integer.min = -128; - uinfo->value.integer.max = 32; - return 0; -} - -static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i; - vortex_t *vortex = snd_kcontrol_chip(kcontrol); - int subdev = kcontrol->id.subdevice; - struct pcm_vol *p = &vortex->pcm_vol[subdev]; - int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); - for (i = 0; i < max_chn; i++) - ucontrol->value.integer.value[i] = p->vol[i]; - return 0; -} - -static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i; - int changed = 0; - int mixin; - unsigned char vol; - vortex_t *vortex = snd_kcontrol_chip(kcontrol); - int subdev = kcontrol->id.subdevice; - struct pcm_vol *p = &vortex->pcm_vol[subdev]; - int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); - for (i = 0; i < max_chn; i++) { - if (p->vol[i] != ucontrol->value.integer.value[i]) { - p->vol[i] = ucontrol->value.integer.value[i]; - if (p->active) { - switch (vortex->dma_adb[p->dma].nr_ch) { - case 1: - mixin = p->mixin[0]; - break; - case 2: - default: - mixin = p->mixin[(i < 2) ? i : (i - 2)]; - break; - case 4: - mixin = p->mixin[i]; - break; - }; - vol = p->vol[i]; - vortex_mix_setinputvolumebyte(vortex, - vortex->mixplayb[i], mixin, vol); - } - changed = 1; - } - } - return changed; -} - -static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); - -static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_INACTIVE, - .info = snd_vortex_pcm_vol_info, - .get = snd_vortex_pcm_vol_get, - .put = snd_vortex_pcm_vol_put, - .tlv = { .p = vortex_pcm_vol_db_scale }, -}; - /* create a pcm device */ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { @@ -659,20 +555,5 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) return err; } } - if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { - for (i = 0; i < NR_PCM; i++) { - chip->pcm_vol[i].active = 0; - chip->pcm_vol[i].dma = -1; - kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); - if (!kctl) - return -ENOMEM; - chip->pcm_vol[i].kctl = kctl; - kctl->id.device = 0; - kctl->id.subdevice = i; - err = snd_ctl_add(chip->card, kctl); - if (err < 0) - return err; - } - } return 0; } diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index 496f14c1a731..95ffa6a9db6e 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -2684,9 +2684,10 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); if (err < 0) goto out_err; - opl3->private_data = chip; } + opl3->private_data = chip; + sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->ctrl_io, chip->irq); diff --git a/trunk/sound/pci/ctxfi/ctvmem.c b/trunk/sound/pci/ctxfi/ctvmem.c index 6109490b83e8..b78f3fc3c33c 100644 --- a/trunk/sound/pci/ctxfi/ctvmem.c +++ b/trunk/sound/pci/ctxfi/ctvmem.c @@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " + printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " "memory space available!\n"); return NULL; } diff --git a/trunk/sound/pci/hda/alc260_quirks.c b/trunk/sound/pci/hda/alc260_quirks.c new file mode 100644 index 000000000000..3b5170b9700f --- /dev/null +++ b/trunk/sound/pci/hda/alc260_quirks.c @@ -0,0 +1,968 @@ +/* + * ALC260 quirk models + * included by patch_realtek.c + */ + +/* ALC260 models */ +enum { + ALC260_AUTO, + ALC260_BASIC, + ALC260_FUJITSU_S702X, + ALC260_ACER, + ALC260_WILL, + ALC260_REPLACER_672V, + ALC260_FAVORIT100, +#ifdef CONFIG_SND_DEBUG + ALC260_TEST, +#endif + ALC260_MODEL_LAST /* last tag */ +}; + +static const hda_nid_t alc260_dac_nids[1] = { + /* front */ + 0x02, +}; + +static const hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static const hda_nid_t alc260_adc_nids_alt[1] = { + /* ADC1 */ + 0x05, +}; + +/* NIDs used when simultaneous access to both ADCs makes sense. Note that + * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. + */ +static const hda_nid_t alc260_dual_adc_nids[2] = { + /* ADC0, ADC1 */ + 0x04, 0x05 +}; + +#define ALC260_DIGOUT_NID 0x03 +#define ALC260_DIGIN_NID 0x06 + +static const struct hda_input_mux alc260_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack, + * headphone jack and the internal CD lines since these are the only pins at + * which audio can appear. For flexibility, also allow the option of + * recording the mixer output on the second ADC (ADC0 doesn't have a + * connection to the mixer output). + */ +static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = { + { + .num_items = 3, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + { "Headphone", 0x2 }, + { "Mixer", 0x5 }, + }, + }, + +}; + +/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to + * the Fujitsu S702x, but jacks are marked differently. + */ +static const struct hda_input_mux alc260_acer_capture_sources[2] = { + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x5 }, + }, + }, + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Headphone", 0x6 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* Maxdata Favorit 100XS */ +static const struct hda_input_mux alc260_favorit100_capture_sources[2] = { + { + .num_items = 2, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + }, + }, + { + .num_items = 3, + .items = { + { "Line/Mic", 0x0 }, + { "CD", 0x4 }, + { "Mixer", 0x5 }, + }, + }, +}; + +/* + * This is just place-holder, so there's something for alc_build_pcms to look + * at when it calculates the maximum number of channels. ALC260 has no mixer + * element which allows changing the channel mode, so the verb list is + * never used. + */ +static const struct hda_channel_mode alc260_modes[1] = { + { 2, NULL }, +}; + + +/* Mixer combinations + * + * basic: base_output + input + pc_beep + capture + * fujitsu: fujitsu + capture + * acer: acer + capture + */ + +static const struct snd_kcontrol_new alc260_base_output_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc260_input_mixer[] = { + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), + { } /* end */ +}; + +/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, + * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. + */ +static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT), + { } /* end */ +}; + +/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current + * versions of the ALC260 don't act on requests to enable mic bias from NID + * 0x0f (used to drive the headphone jack in these laptops). The ALC260 + * datasheet doesn't mention this restriction. At this stage it's not clear + * whether this behaviour is intentional or is a hardware bug in chip + * revisions available in early 2006. Therefore for now allow the + * "Headphone Jack Mode" control to span all choices, but if it turns out + * that the lack of mic bias for this NID is intentional we could change the + * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006 + * don't appear to make the mic bias available from the "line" jack, even + * though the NID used for this jack (0x14) can supply it. The theory is + * that perhaps Acer have included blocking capacitors between the ALC260 + * and the output jack. If this turns out to be the case for all such + * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT + * to ALC_PIN_DIR_INOUT_NOMICBIAS. + * + * The C20x Tablet series have a mono internal speaker which is controlled + * via the chip's Mono sum widget and pin complex, so include the necessary + * controls for such models. On models without a "mono speaker" the control + * won't do anything. + */ +static const struct snd_kcontrol_new alc260_acer_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, + HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* Maxdata Favorit 100XS: one output and one input (0x12) jack + */ +static const struct snd_kcontrol_new alc260_favorit100_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + { } /* end */ +}; + +/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12, + * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17. + */ +static const struct snd_kcontrol_new alc260_will_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + { } /* end */ +}; + +/* Replacer 672V ALC260 pin usage: Mic jack = 0x12, + * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f. + */ +static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT), + { } /* end */ +}; + +/* + * initialization verbs + */ +static const struct hda_verb alc260_init_verbs[] = { + /* Line In pin widget for input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + /* LINE-2 is used for line-out in rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* select line-out */ + {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LINE-OUT pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* enable HP */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* enable Mono */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* mute capture amp left and right */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set vol=0 Line-Out mixer amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 HP mixer amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 Mono mixer amp left and right */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* unmute LINE-2 out pin */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & + * Line In 2 = 0x03 + */ + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* mute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } +}; + +/* Initialisation sequence for ALC260 as configured in Fujitsu S702x + * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD + * audio = 0x16, internal speaker = 0x10. + */ +static const struct hda_verb alc260_fujitsu_init_verbs[] = { + /* Disable all GPIOs */ + {0x01, AC_VERB_SET_GPIO_MASK, 0}, + /* Internal speaker is connected to headphone pin */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Headphone/Line-out jack connects to Line1 pin; make it an output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Line1 pin widget takes its input from the OUT1 sum bus + * when acting as an output. + */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Line1 pin widget output buffer since it starts as an output. + * If the pin mode is changed by the user the pin mode control will + * take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute input buffer of pin widget used for Line-in (no equiv + * mixer ctrl) + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - line + * in (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to line in (on mic1 pin) + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for ALC260 as configured in Acer TravelMate and + * similar laptops (adapted from Fujitsu init verbs). + */ +static const struct hda_verb alc260_acer_init_verbs[] = { + /* On TravelMate laptops, GPIO 0 enables the internal speaker and + * the headphone jack. Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Internal speaker/Headphone jack is connected to Line-out pin */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Internal microphone/Mic jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Line In jack is connected to Line1 pin */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */ + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute mono pin widget amp output (no equiv mixer ctrl) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +/* Initialisation sequence for Maxdata Favorit 100XS + * (adapted from Acer init verbs). + */ +static const struct hda_verb alc260_favorit100_init_verbs[] = { + /* GPIO 0 enables the output jack. + * Turn this on and rely on the standard mute + * methods whenever the user wants to turn these outputs off. + */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + /* Line/Mic input jack is connected to Mic1 pin */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + /* Ensure all other unused pins are disabled and muted. */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute Line-out pin widget amp left and right + * (no equiv mixer ctrl) + */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Mic1 and Line1 pin widget input buffers since they start as + * inputs. If the pin mode is changed by the user the pin mode control + * will take care of enabling the pin's input/output buffers as needed. + * Therefore there's no need to enable the input buffer at this + * stage. + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting - mic + * (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do similar with the second ADC: mute capture input amp and + * set ADC connection to mic to match ALSA's default state. + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; + +static const struct hda_verb alc260_will_verbs[] = { + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3040}, + {} +}; + +static const struct hda_verb alc260_replacer_672v_verbs[] = { + {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x1a, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x1a, AC_VERB_SET_PROC_COEF, 0x3050}, + + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + + {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc260_replacer_672v_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ + present = snd_hda_jack_detect(codec, 0x0f); + if (present) { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); + } else { + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); + } +} + +static void alc260_replacer_672v_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC_HP_EVENT) + alc260_replacer_672v_automute(codec); +} + +static const struct hda_verb alc260_hp_dc7600_verbs[] = { + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {} +}; + +/* Test configuration for debugging, modelled after the ALC880 test + * configuration. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc260_test_dac_nids[1] = { + 0x02, +}; +static const hda_nid_t alc260_test_adc_nids[2] = { + 0x04, 0x05, +}; +/* For testing the ALC260, each input MUX needs its own definition since + * the signal assignments are different. This assumes that the first ADC + * is NID 0x04. + */ +static const struct hda_input_mux alc260_test_capture_sources[2] = { + { + .num_items = 7, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "LINE-OUT pin", 0x5 }, + { "HP-OUT pin", 0x6 }, + }, + }, + { + .num_items = 8, + .items = { + { "MIC1 pin", 0x0 }, + { "MIC2 pin", 0x1 }, + { "LINE1 pin", 0x2 }, + { "LINE2 pin", 0x3 }, + { "CD pin", 0x4 }, + { "Mixer", 0x5 }, + { "LINE-OUT pin", 0x6 }, + { "HP-OUT pin", 0x7 }, + }, + }, +}; +static const struct snd_kcontrol_new alc260_test_mixer[] = { + /* Output driver widgets */ + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT), + + /* Modes for retasking pin widgets + * Note: the ALC260 doesn't seem to act on requests to enable mic + * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't + * mention this restriction. At this stage it's not clear whether + * this behaviour is intentional or is a hardware bug in chip + * revisions available at least up until early 2006. Therefore for + * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all + * choices, but if it turns out that the lack of mic bias for these + * NIDs is intentional we could change their modes from + * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS. + */ + ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT), + ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT), + + /* Loopback mixer controls */ + HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT), + + /* Controls for GPIO pins, assuming they are configured as outputs */ + ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), + ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), + ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), + ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), + + /* Switches to allow the digital IO pins to be enabled. The datasheet + * is ambigious as to which NID is which; testing on laptops which + * make this output available should provide clarification. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), + ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), + + /* A switch allowing EAPD to be enabled. Some laptops seem to use + * this output to turn on an external amplifier. + */ + ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), + ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), + + { } /* end */ +}; +static const struct hda_verb alc260_test_init_verbs[] = { + /* Enable all GPIOs as outputs with an initial value of 0 */ + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, + + /* Enable retasking pins as output, initially without power amp */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* Disable digital (SPDIF) pins initially, but users can enable + * them via a mixer switch. In the case of SPDIF-out, this initverb + * payload also sets the generation to 0, output to be in "consumer" + * PCM format, copyright asserted, no pre-emphasis and no validity + * control. + */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, + {0x0e, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Start with output sum widgets muted and their output gains at min */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + + /* Unmute retasking pin widget output buffers since the default + * state appears to be output. As the pin mode is changed by the + * user the pin mode control will take care of enabling the pin's + * input/output buffers as needed. + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Also unmute the mono-out pin widget */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to match default mixer setting (mic1 + * pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Do the same for the second ADC: mute capture input amp and + * set ADC connection to mic1 pin + */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ + + { } +}; +#endif + +/* + * ALC260 configurations + */ +static const char * const alc260_models[ALC260_MODEL_LAST] = { + [ALC260_BASIC] = "basic", + [ALC260_FUJITSU_S702X] = "fujitsu", + [ALC260_ACER] = "acer", + [ALC260_WILL] = "will", + [ALC260_REPLACER_672V] = "replacer", + [ALC260_FAVORIT100] = "favorit100", +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = "test", +#endif + [ALC260_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc260_cfg_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), + SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), + SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), + SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), + SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), + SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), + SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), + SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), + {} +}; + +static const struct alc_config_preset alc260_presets[] = { + [ALC260_BASIC] = { + .mixers = { alc260_base_output_mixer, + alc260_input_mixer }, + .init_verbs = { alc260_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_FUJITSU_S702X] = { + .mixers = { alc260_fujitsu_mixer }, + .init_verbs = { alc260_fujitsu_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources), + .input_mux = alc260_fujitsu_capture_sources, + }, + [ALC260_ACER] = { + .mixers = { alc260_acer_mixer }, + .init_verbs = { alc260_acer_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), + .input_mux = alc260_acer_capture_sources, + }, + [ALC260_FAVORIT100] = { + .mixers = { alc260_favorit100_mixer }, + .init_verbs = { alc260_favorit100_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .adc_nids = alc260_dual_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources), + .input_mux = alc260_favorit100_capture_sources, + }, + [ALC260_WILL] = { + .mixers = { alc260_will_mixer }, + .init_verbs = { alc260_init_verbs, alc260_will_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + }, + [ALC260_REPLACER_672V] = { + .mixers = { alc260_replacer_672v_mixer }, + .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, + .num_dacs = ARRAY_SIZE(alc260_dac_nids), + .dac_nids = alc260_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .adc_nids = alc260_adc_nids, + .dig_out_nid = ALC260_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .input_mux = &alc260_capture_source, + .unsol_event = alc260_replacer_672v_unsol_event, + .init_hook = alc260_replacer_672v_automute, + }, +#ifdef CONFIG_SND_DEBUG + [ALC260_TEST] = { + .mixers = { alc260_test_mixer }, + .init_verbs = { alc260_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), + .dac_nids = alc260_test_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids), + .adc_nids = alc260_test_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc260_modes), + .channel_mode = alc260_modes, + .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources), + .input_mux = alc260_test_capture_sources, + }, +#endif +}; + diff --git a/trunk/sound/pci/hda/alc880_quirks.c b/trunk/sound/pci/hda/alc880_quirks.c new file mode 100644 index 000000000000..5b68435d195b --- /dev/null +++ b/trunk/sound/pci/hda/alc880_quirks.c @@ -0,0 +1,1700 @@ +/* + * ALC880 quirk models + * included by patch_realtek.c + */ + +/* ALC880 board config type */ +enum { + ALC880_AUTO, + ALC880_3ST, + ALC880_3ST_DIG, + ALC880_5ST, + ALC880_5ST_DIG, + ALC880_W810, + ALC880_Z71V, + ALC880_6ST, + ALC880_6ST_DIG, + ALC880_F1734, + ALC880_ASUS, + ALC880_ASUS_DIG, + ALC880_ASUS_W1V, + ALC880_ASUS_DIG2, + ALC880_FUJITSU, + ALC880_UNIWILL_DIG, + ALC880_UNIWILL, + ALC880_UNIWILL_P53, + ALC880_CLEVO, + ALC880_TCL_S700, + ALC880_LG, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif + ALC880_MODEL_LAST /* last tag */ +}; + +/* + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, + * F-Mic = 0x1b, HP = 0x19 + */ + +static const hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; + +static const hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; + +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. + * Note: this is a 915GAV bug, fixed on 915GLV + */ +static const hda_nid_t alc880_adc_nids_alt[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; + +#define ALC880_DIGOUT_NID 0x06 +#define ALC880_DIGIN_NID 0x0a +#define ALC880_PIN_CD_NID 0x1c + +static const struct hda_input_mux alc880_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* channel source setting (2/6 channel selection for 3-stack) */ +/* 2ch mode */ +static const struct hda_verb alc880_threestack_ch2_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + /* set mic-in to input vref 80%, mute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* 6ch mode */ +static const struct hda_verb alc880_threestack_ch6_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + /* set mic-in to output, unmute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static const struct hda_channel_mode alc880_threestack_modes[2] = { + { 2, alc880_threestack_ch2_init }, + { 6, alc880_threestack_ch6_init }, +}; + +static const struct snd_kcontrol_new alc880_three_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* + * ALC880 5-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), + * Side = 0x02 (0xd) + * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 + * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 + */ + +/* additional mixers to alc880_three_stack_mixer */ +static const struct snd_kcontrol_new alc880_five_stack_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), + { } /* end */ +}; + +/* channel source setting (6/8 channel selection for 5-stack) */ +/* 6ch mode */ +static const struct hda_verb alc880_fivestack_ch6_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* 8ch mode */ +static const struct hda_verb alc880_fivestack_ch8_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static const struct hda_channel_mode alc880_fivestack_modes[2] = { + { 6, alc880_fivestack_ch6_init }, + { 8, alc880_fivestack_ch8_init }, +}; + + +/* + * ALC880 6-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), + * Side = 0x05 (0x0f) + * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, + * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b + */ + +static const hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* fixed 8-channels */ +static const struct hda_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, +}; + +static const struct snd_kcontrol_new alc880_six_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 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_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("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + + +/* + * ALC880 W810 model + * + * W810 has rear IO for: + * Front (DAC 02) + * Surround (DAC 03) + * Center/LFE (DAC 04) + * Digital out (06) + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. + * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * + * Plugging headphones in will disable the internal speakers. This is + * implemented in hardware, not via the driver using jack sense. In + * a similar fashion, plugging into the rear socket marked "front" will + * disable both the speakers and headphones. + * + * For input, there's a microphone jack, and an "audio in" jack. + * These may not do anything useful with this driver yet, because I + * haven't setup any initialization verbs for these yet... + */ + +static const hda_nid_t alc880_w810_dac_nids[3] = { + /* front, rear/surround, clfe */ + 0x02, 0x03, 0x04 +}; + +/* fixed 6 channels */ +static const struct hda_channel_mode alc880_w810_modes[1] = { + { 6, NULL } +}; + +/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ +static const struct snd_kcontrol_new alc880_w810_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + + +/* + * Z710V model + * + * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) + * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), + * Line = 0x1a + */ + +static const hda_nid_t alc880_z71v_dac_nids[1] = { + 0x02 +}; +#define ALC880_Z71V_HP_DAC 0x03 + +/* fixed 2 channels */ +static const struct hda_channel_mode alc880_2_jack_modes[1] = { + { 2, NULL } +}; + +static const struct snd_kcontrol_new alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +/* + * ALC880 F1734 model + * + * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) + * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 + */ + +static const hda_nid_t alc880_f1734_dac_nids[1] = { + 0x03 +}; +#define ALC880_F1734_HP_DAC 0x02 + +static const struct snd_kcontrol_new alc880_f1734_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct hda_input_mux alc880_f1734_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "CD", 0x4 }, + }, +}; + + +/* + * ALC880 ASUS model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a + */ + +#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ +#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ + +static const struct snd_kcontrol_new alc880_asus_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +/* + * ALC880 ASUS W1V model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a, Line2 = 0x1b + */ + +/* additional mixers to alc880_asus_mixer */ +static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + { } /* end */ +}; + +/* TCL S700 */ +static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone 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("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { } /* end */ +}; + +/* Uniwill */ +static const struct snd_kcontrol_new alc880_uniwill_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +/* + * initialize the codec volumes, etc + */ + +/* + * generic initialization of ADC, input mixers and output mixers + */ +static const struct hda_verb alc880_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for front + * panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_3stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 5-stack pin configuration: + * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, + * line-in/side = 0x1a, f-mic = 0x1b + */ +static const struct hda_verb alc880_pin_5stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ + + /* + * Set pin mode and muting + */ + /* set pin widgets 0x14-0x17 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* unmute pins for output (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * W810 pin configuration: + * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b + */ +static const struct hda_verb alc880_pin_w810_init_verbs[] = { + /* hphone/speaker input selector: front DAC */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } +}; + +/* + * Z71V pin configuration: + * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) + */ +static const struct hda_verb alc880_pin_z71v_init_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * 6-stack pin configuration: + * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, + * f-mic = 0x19, line = 0x1a, HP = 0x1b + */ +static const struct hda_verb alc880_pin_6stack_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* + * Uniwill pin configuration: + * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19, + * line = 0x1a + */ +static const struct hda_verb alc880_uniwill_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */ + /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT}, + + { } +}; + +/* +* Uniwill P53 +* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, + */ +static const struct hda_verb alc880_uniwill_p53_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_DCVOL_EVENT}, + + { } +}; + +static const struct hda_verb alc880_beep_init_verbs[] = { + { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) }, + { } +}; + +static void alc880_uniwill_setup(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_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +static void alc880_uniwill_init_hook(struct hda_codec *codec) +{ + alc_hp_automute(codec); + alc88x_simple_mic_automute(codec); +} + +static void alc880_uniwill_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! + */ + switch (res >> 28) { + case ALC_MIC_EVENT: + alc88x_simple_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static void alc880_uniwill_p53_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); +} + +static void alc880_uniwill_p53_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) == ALC_DCVOL_EVENT) + alc880_uniwill_p53_dcvol_automute(codec); + else + alc_sku_unsol_event(codec, res); +} + +/* + * F1734 pin configuration: + * HP = 0x14, speaker-out = 0x15, mic = 0x18 + */ +static const struct hda_verb alc880_pin_f1734_init_verbs[] = { + {0x07, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC_DCVOL_EVENT}, + + { } +}; + +/* + * ASUS pin configuration: + * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a + */ +static const struct hda_verb alc880_pin_asus_init_verbs[] = { + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + { } +}; + +/* Enable GPIO mask and set output */ +#define alc880_gpio1_init_verbs alc_gpio1_init_verbs +#define alc880_gpio2_init_verbs alc_gpio2_init_verbs +#define alc880_gpio3_init_verbs alc_gpio3_init_verbs + +/* Clevo m520g init */ +static const struct hda_verb alc880_pin_clevo_init_verbs[] = { + /* headphone output */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* line-out */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line-in */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* CD */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic2 (front panel) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* headphone */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + { } +}; + +static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, + + /* Headphone output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Front output*/ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* change to EAPD mode */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, + + { } +}; + +/* + * LG m1 express dual + * + * Pin assignment: + * Rear Line-In/Out (blue): 0x14 + * Build-in Mic-In: 0x15 + * Speaker-out: 0x17 + * HP-Out (green): 0x1b + * Mic-In/Out (red): 0x19 + * SPDIF-Out: 0x1e + */ + +/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */ +static const hda_nid_t alc880_lg_dac_nids[3] = { + 0x05, 0x02, 0x03 +}; + +/* seems analog CD is not working */ +static const struct hda_input_mux alc880_lg_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x5 }, + { "Internal Mic", 0x6 }, + }, +}; + +/* 2,4,6 channel modes */ +static const struct hda_verb alc880_lg_ch2_init[] = { + /* set line-in and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch4_init[] = { + /* set line-in to out and mic-in to input */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { } +}; + +static const struct hda_verb alc880_lg_ch6_init[] = { + /* set line-in and mic-in to output */ + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { } +}; + +static const struct hda_channel_mode alc880_lg_ch_modes[3] = { + { 2, alc880_lg_ch2_init }, + { 4, alc880_lg_ch4_init }, + { 6, alc880_lg_ch6_init }, +}; + +static const struct snd_kcontrol_new alc880_lg_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_lg_init_verbs[] = { + /* set capture source to mic-in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* mute all amp mixer inputs */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, + /* line-in to input */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* built-in mic */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* speaker-out */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* mic-in to input */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* HP-out */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x03}, + {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 | ALC_HP_EVENT}, + { } +}; + +/* toggle speaker-output according to the hp-jack state */ +static void alc880_lg_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x17; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + +/* + * Test configuration for debugging + * + * Almost all inputs/outputs are enabled. I/O pins can be configured via + * enum controls. + */ +#ifdef CONFIG_SND_DEBUG +static const hda_nid_t alc880_test_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05 +}; + +static const struct hda_input_mux alc880_test_capture_source = { + .num_items = 7, + .items = { + { "In-1", 0x0 }, + { "In-2", 0x1 }, + { "In-3", 0x2 }, + { "In-4", 0x3 }, + { "CD", 0x4 }, + { "Front", 0x5 }, + { "Surround", 0x6 }, + }, +}; + +static const struct hda_channel_mode alc880_test_modes[4] = { + { 2, NULL }, + { 4, NULL }, + { 6, NULL }, + { 8, NULL }, +}; + +static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "N/A", "Line Out", "HP Out", + "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= 8) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int pin_ctl, item = 0; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pin_ctl & AC_PINCTL_OUT_EN) { + if (pin_ctl & AC_PINCTL_HP_EN) + item = 2; + else + item = 1; + } else if (pin_ctl & AC_PINCTL_IN_EN) { + switch (pin_ctl & AC_PINCTL_VREFEN) { + case AC_PINCTL_VREF_HIZ: item = 3; break; + case AC_PINCTL_VREF_50: item = 4; break; + case AC_PINCTL_VREF_GRD: item = 5; break; + case AC_PINCTL_VREF_80: item = 6; break; + case AC_PINCTL_VREF_100: item = 7; break; + } + } + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + static const unsigned int ctls[] = { + 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, + }; + unsigned int old_ctl, new_ctl; + + old_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + new_ctl = ctls[ucontrol->value.enumerated.item[0]]; + if (old_ctl != new_ctl) { + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); + return 1; + } + return 0; +} + +static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[] = { + "Front", "Surround", "CLFE", "Side" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + ucontrol->value.enumerated.item[0] = sel & 3; + return 0; +} + +static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; + if (ucontrol->value.enumerated.item[0] != sel) { + sel = ucontrol->value.enumerated.item[0] & 3; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); + return 1; + } + return 0; +} + +#define PIN_CTL_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_ctl_info, \ + .get = alc_test_pin_ctl_get, \ + .put = alc_test_pin_ctl_put, \ + .private_value = nid \ + } + +#define PIN_SRC_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_test_pin_src_info, \ + .get = alc_test_pin_src_get, \ + .put = alc_test_pin_src_put, \ + .private_value = nid \ + } + +static const struct snd_kcontrol_new alc880_test_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + PIN_CTL_TEST("Front Pin Mode", 0x14), + PIN_CTL_TEST("Surround Pin Mode", 0x15), + PIN_CTL_TEST("CLFE Pin Mode", 0x16), + PIN_CTL_TEST("Side Pin Mode", 0x17), + PIN_CTL_TEST("In-1 Pin Mode", 0x18), + PIN_CTL_TEST("In-2 Pin Mode", 0x19), + PIN_CTL_TEST("In-3 Pin Mode", 0x1a), + PIN_CTL_TEST("In-4 Pin Mode", 0x1b), + PIN_SRC_TEST("In-1 Pin Source", 0x18), + PIN_SRC_TEST("In-2 Pin Source", 0x19), + PIN_SRC_TEST("In-3 Pin Source", 0x1a), + PIN_SRC_TEST("In-4 Pin Source", 0x1b), + HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc880_test_init_verbs[] = { + /* Unmute inputs of 0x0c - 0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* Vol output for 0x0c-0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* Set output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Unmute output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Set input pins 0x18-0x1c */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Mute input pins 0x18-0x1b */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* ADC set up */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Analog input/passthru */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; +#endif + +/* + */ + +static const char * const alc880_models[ALC880_MODEL_LAST] = { + [ALC880_3ST] = "3stack", + [ALC880_TCL_S700] = "tcl", + [ALC880_3ST_DIG] = "3stack-digout", + [ALC880_CLEVO] = "clevo", + [ALC880_5ST] = "5stack", + [ALC880_5ST_DIG] = "5stack-digout", + [ALC880_W810] = "w810", + [ALC880_Z71V] = "z71v", + [ALC880_6ST] = "6stack", + [ALC880_6ST_DIG] = "6stack-digout", + [ALC880_ASUS] = "asus", + [ALC880_ASUS_W1V] = "asus-w1v", + [ALC880_ASUS_DIG] = "asus-dig", + [ALC880_ASUS_DIG2] = "asus-dig2", + [ALC880_UNIWILL_DIG] = "uniwill", + [ALC880_UNIWILL_P53] = "uniwill-p53", + [ALC880_FUJITSU] = "fujitsu", + [ALC880_F1734] = "F1734", + [ALC880_LG] = "lg", +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = "test", +#endif + [ALC880_AUTO] = "auto", +}; + +static const struct snd_pci_quirk alc880_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), + SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), + SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), + SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), + SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V), + /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */ + SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), + SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), + SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */ + SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), + SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), + SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), + SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), + SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), + SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), + SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734), + SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), + SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), + SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), + SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), + SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), + SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), + SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ + SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), + SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), + SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), + /* default Intel */ + SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST), + SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), + SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), + {} +}; + +/* + * ALC880 codec presets + */ +static const struct alc_config_preset alc880_presets[] = { + [ALC880_3ST] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_3ST_DIG] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_3stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_TCL_S700] = { + .mixers = { alc880_tcl_s700_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_tcl_S700_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ + .num_adc_nids = 1, /* single ADC */ + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer}, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST_DIG] = { + .mixers = { alc880_three_stack_mixer, + alc880_five_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_5stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_6ST] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_6ST_DIG] = { + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_6stack_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_W810] = { + .mixers = { alc880_w810_base_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_w810_init_verbs, + alc880_gpio2_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_Z71V] = { + .mixers = { alc880_z71v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_z71v_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), + .dac_nids = alc880_z71v_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_F1734] = { + .mixers = { alc880_f1734_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_f1734_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), + .dac_nids = alc880_f1734_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_f1734_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_ASUS] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG2] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio2_init_verbs }, /* use GPIO2 */ + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_W1V] = { + .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL_DIG] = { + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL] = { + .mixers = { alc880_uniwill_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_unsol_event, + .setup = alc880_uniwill_setup, + .init_hook = alc880_uniwill_init_hook, + }, + [ALC880_UNIWILL_P53] = { + .mixers = { alc880_uniwill_p53_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_FUJITSU] = { + .mixers = { alc880_fujitsu_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_uniwill_p53_init_verbs, + alc880_beep_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, + .input_mux = &alc880_capture_source, + .unsol_event = alc880_uniwill_p53_unsol_event, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_hp_automute, + }, + [ALC880_CLEVO] = { + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_pin_clevo_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc880_capture_source, + }, + [ALC880_LG] = { + .mixers = { alc880_lg_mixer }, + .init_verbs = { alc880_volume_init_verbs, + alc880_lg_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids), + .dac_nids = alc880_lg_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), + .channel_mode = alc880_lg_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc880_lg_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc880_lg_setup, + .init_hook = alc_hp_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif + }, +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = { + .mixers = { alc880_test_mixer }, + .init_verbs = { alc880_test_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), + .dac_nids = alc880_test_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_test_modes), + .channel_mode = alc880_test_modes, + .input_mux = &alc880_test_capture_source, + }, +#endif +}; + diff --git a/trunk/sound/pci/hda/alc882_quirks.c b/trunk/sound/pci/hda/alc882_quirks.c new file mode 100644 index 000000000000..bdf0ed4ab3e2 --- /dev/null +++ b/trunk/sound/pci/hda/alc882_quirks.c @@ -0,0 +1,861 @@ +/* + * ALC882/ALC883/ALC888/ALC889 quirk models + * included by patch_realtek.c + */ + +/* ALC882 models */ +enum { + ALC882_AUTO, + ALC885_MBA21, + ALC885_MBP3, + ALC885_MB5, + ALC885_MACMINI3, + ALC885_IMAC91, + ALC889A_MB31, + ALC882_MODEL_LAST, +}; + +#define ALC882_DIGOUT_NID 0x06 +#define ALC882_DIGIN_NID 0x0a +#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID +#define ALC883_DIGIN_NID ALC882_DIGIN_NID +#define ALC1200_DIGOUT_NID 0x10 + + +static const struct hda_channel_mode alc882_ch_modes[1] = { + { 8, NULL } +}; + +/* DACs */ +static const hda_nid_t alc882_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; +#define alc883_dac_nids alc882_dac_nids + +/* ADCs */ +#define alc882_adc_nids alc880_adc_nids +#define alc882_adc_nids_alt alc880_adc_nids_alt +#define alc883_adc_nids alc882_adc_nids_alt + +static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +#define alc883_capsrc_nids alc882_capsrc_nids_alt + +/* input MUX */ +/* FIXME: should be a matrix-type input source selection */ + +static const struct hda_input_mux alc882_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +#define alc883_capture_source alc882_capture_source + +static const struct hda_input_mux mb5_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x7 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux macmini3_capture_source = { + .num_items = 2, + .items = { + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc883_3stack_6ch_intel = { + .num_items = 4, + .items = { + { "Mic", 0x1 }, + { "Front Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static const struct hda_input_mux alc889A_mb31_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + /* Front Mic (0x01) unused */ + { "Line", 0x2 }, + /* Line 2 (0x03) unused */ + /* CD (0x04) unused? */ + }, +}; + +static const struct hda_input_mux alc889A_imac91_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x01 }, + { "Line", 0x2 }, /* Not sure! */ + }, +}; + +/* Macbook Air 2,1 */ + +static const struct hda_channel_mode alc885_mba21_ch_modes[1] = { + { 2, NULL }, +}; + +/* + * macbook pro ALC885 can switch LineIn to LineOut without losing Mic + */ + +/* + * 2ch mode + */ +static const struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 4ch mode + */ +static const struct hda_verb alc885_mbp_ch4_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 4, alc885_mbp_ch4_init }, +}; + +/* + * 2ch + * Speakers/Woofer/HP = Front + * LineIn = Input + */ +static const struct hda_verb alc885_mb5_ch2_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } /* end */ +}; + +/* + * 6ch mode + * Speakers/HP = Front + * Woofer = LFE + * LineIn = Surround + */ +static const struct hda_verb alc885_mb5_ch6_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + { } /* end */ +}; + +static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = { + { 2, alc885_mb5_ch2_init }, + { 6, alc885_mb5_ch6_init }, +}; + +#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes + +/* Macbook Air 2,1 same control for HP and internal Speaker */ + +static const struct snd_kcontrol_new alc885_mba21_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT), + { } +}; + + +static const struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + 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, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_mb5_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_macmini3_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc885_imac91_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT), + { } /* end */ +}; + + +static const struct snd_kcontrol_new alc882_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc882_base_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* CLFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Side mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Front 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}, + /* Rear Pin: output 1 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* CLFE Pin: output 2 (0x0e) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* Side Pin: output 3 (0x0f) */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* 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: input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +#define alc883_init_verbs alc882_base_init_verbs + +/* Macbook 5,1 */ +static const struct hda_verb alc885_mb5_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front 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)}, + /* Surround 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)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {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, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {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, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + /* 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(0x1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, + { } +}; + +/* Macmini 3,1 */ +static const struct hda_verb alc885_macmini3_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front 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)}, + /* Surround 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)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {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, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {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, 0x03}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + /* 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)}, + { } +}; + + +static const struct hda_verb alc885_mba21_init_verbs[] = { + /*Internal and HP Speaker Mixer*/ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /*Internal Speaker Pin (0x0c)*/ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0e) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, + /* Line in (is hp when jack connected)*/ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + { } + }; + + +/* Macbook Pro rev3 */ +static const struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {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)}, + /* Rear 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)}, + /* HP mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front 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}, + /* HP Pin: output 0 (0x0e) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* 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: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {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)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + +/* iMac 9,1 */ +static const struct hda_verb alc885_imac91_init_verbs[] = { + /* Internal Speaker Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: Rear */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC_HP_EVENT | AC_USRSP_EN)}, + /* Line in Rear */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* 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}, + /* Rear 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)}, + /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ + {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)}, + /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {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)}, + /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +/* Toggle speaker-output according to the hp-jack state */ +static void alc885_imac24_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +#define alc885_mb5_setup alc885_imac24_setup +#define alc885_macmini3_setup alc885_imac24_setup + +/* Macbook Air 2,1 */ +static void alc885_mba21_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + + + +static void alc885_mbp3_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +static void alc885_imac91_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP); +} + +/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch2_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ +static const struct hda_verb alc889A_mb31_ch4_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ +static const struct hda_verb alc889A_mb31_ch5_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ +static const struct hda_verb alc889A_mb31_ch6_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { + { 2, alc889A_mb31_ch2_init }, + { 4, alc889A_mb31_ch4_init }, + { 5, alc889A_mb31_ch5_init }, + { 6, alc889A_mb31_ch6_init }, +}; + +static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc889A_mb31_mixer[] = { + /* Output mixers */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), + /* Output switches */ + HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), + /* Boost mixers */ + HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT), + /* Input mixers */ + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static const struct snd_kcontrol_new alc883_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ +}; + +static const struct hda_verb alc889A_mb31_verbs[] = { + /* Init rear pin (used as headphone output) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN}, + /* Init line pin (used as output in 4ch and 6ch mode) */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ + /* Init line 2 pin (used as headphone out by default) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ + { } /* end */ +}; + +/* Mute speakers according to the headphone jack state */ +static void alc889A_mb31_automute(struct hda_codec *codec) +{ + unsigned int present; + + /* Mute only in 2ch or 4ch mode */ + if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) + == 0x00) { + present = snd_hda_jack_detect(codec, 0x15); + snd_hda_codec_amp_stereo(codec, 0x14, 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 alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC_HP_EVENT) + alc889A_mb31_automute(codec); +} + +/* + * configuration and preset + */ +static const char * const alc882_models[ALC882_MODEL_LAST] = { + [ALC885_MB5] = "mb5", + [ALC885_MACMINI3] = "macmini3", + [ALC885_MBA21] = "mba21", + [ALC885_MBP3] = "mbp3", + [ALC885_IMAC91] = "imac91", + [ALC889A_MB31] = "mb31", + [ALC882_AUTO] = "auto", +}; + +/* codec SSID table for Intel Mac */ +static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5), + /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, + * so apparently no perfect solution yet + */ + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3), + {} /* terminator */ +}; + +static const struct alc_config_preset alc882_presets[] = { + [ALC885_MBA21] = { + .mixers = { alc885_mba21_mixer }, + .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc882_capture_source, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mba21_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = 2, + .dac_nids = alc882_dac_nids, + .hp_nid = 0x04, + .channel_mode = alc885_mbp_4ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mbp3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MB5] = { + .mixers = { alc885_mb5_mixer, alc882_chmode_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_mb5_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), + .input_mux = &mb5_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_mb5_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_MACMINI3] = { + .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_macmini3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_macmini3_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes), + .input_mux = &macmini3_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_macmini3_setup, + .init_hook = alc_hp_automute, + }, + [ALC885_IMAC91] = { + .mixers = {alc885_imac91_mixer}, + .init_verbs = { alc885_imac91_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mba21_ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), + .input_mux = &alc889A_imac91_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_sku_unsol_event, + .setup = alc885_imac91_setup, + .init_hook = alc_hp_automute, + }, + [ALC889A_MB31] = { + .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, + .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, + alc880_gpio1_init_verbs }, + .adc_nids = alc883_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .capsrc_nids = alc883_capsrc_nids, + .dac_nids = alc883_dac_nids, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .channel_mode = alc889A_mb31_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), + .input_mux = &alc889A_mb31_capture_source, + .dig_out_nid = ALC883_DIGOUT_NID, + .unsol_event = alc889A_mb31_unsol_event, + .init_hook = alc889A_mb31_automute, + }, +}; + + diff --git a/trunk/sound/pci/hda/alc_quirks.c b/trunk/sound/pci/hda/alc_quirks.c new file mode 100644 index 000000000000..a18952ed4311 --- /dev/null +++ b/trunk/sound/pci/hda/alc_quirks.c @@ -0,0 +1,480 @@ +/* + * Common codes for Realtek codec quirks + * included by patch_realtek.c + */ + +/* + * configuration template - to be copied to the spec instance + */ +struct alc_config_preset { + const struct snd_kcontrol_new *mixers[5]; /* should be identical size + * with spec + */ + const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ + const struct hda_verb *init_verbs[5]; + unsigned int num_dacs; + const hda_nid_t *dac_nids; + hda_nid_t dig_out_nid; /* optional */ + hda_nid_t hp_nid; /* optional */ + const hda_nid_t *slave_dig_outs; + unsigned int num_adc_nids; + const hda_nid_t *adc_nids; + const hda_nid_t *capsrc_nids; + hda_nid_t dig_in_nid; + unsigned int num_channel_mode; + const struct hda_channel_mode *channel_mode; + int need_dac_fix; + int const_channel_count; + unsigned int num_mux_defs; + const struct hda_input_mux *input_mux; + void (*unsol_event)(struct hda_codec *, unsigned int); + void (*setup)(struct hda_codec *); + void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + const struct hda_amp_list *loopbacks; + void (*power_hook)(struct hda_codec *codec); +#endif +}; + +/* + * channel mode setting + */ +static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, + spec->num_channel_mode); +} + +static int alc_ch_mode_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; + return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + spec->ext_channel_count); +} + +static int alc_ch_mode_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 err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, + spec->num_channel_mode, + &spec->ext_channel_count); + if (err >= 0 && !spec->const_channel_count) { + spec->multiout.max_channels = spec->ext_channel_count; + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + } + return err; +} + +/* + * Control the mode of pin widget settings via the mixer. "pc" is used + * instead of "%" to avoid consequences of accidentally treating the % as + * being part of a format specifier. Maximum allowed length of a value is + * 63 characters plus NULL terminator. + * + * Note: some retasking pin complexes seem to ignore requests for input + * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these + * are requested. Therefore order this list so that this behaviour will not + * cause problems when mixer clients move through the enum sequentially. + * NIDs 0x0f and 0x10 have been observed to have this behaviour as of + * March 2006. + */ +static const char * const alc_pin_mode_names[] = { + "Mic 50pc bias", "Mic 80pc bias", + "Line in", "Line out", "Headphone out", +}; +static const unsigned char alc_pin_mode_values[] = { + PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP, +}; +/* The control can present all 5 options, or it can limit the options based + * in the pin being assumed to be exclusively an input or an output pin. In + * addition, "input" pins may or may not process the mic bias option + * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to + * accept requests for bias as of chip versions up to March 2006) and/or + * wiring in the computer. + */ +#define ALC_PIN_DIR_IN 0x00 +#define ALC_PIN_DIR_OUT 0x01 +#define ALC_PIN_DIR_INOUT 0x02 +#define ALC_PIN_DIR_IN_NOMICBIAS 0x03 +#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 + +/* Info about the pin modes supported by the different pin direction modes. + * For each direction the minimum and maximum values are given. + */ +static const signed char alc_pin_mode_dir_info[5][2] = { + { 0, 2 }, /* ALC_PIN_DIR_IN */ + { 3, 4 }, /* ALC_PIN_DIR_OUT */ + { 0, 4 }, /* ALC_PIN_DIR_INOUT */ + { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */ + { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */ +}; +#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0]) +#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1]) +#define alc_pin_mode_n_items(_dir) \ + (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1) + +static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int item_num = uinfo->value.enumerated.item; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = alc_pin_mode_n_items(dir); + + if (item_numalc_pin_mode_max(dir)) + item_num = alc_pin_mode_min(dir); + strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]); + return 0; +} + +static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int i; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + /* Find enumerated value for current pinctl setting */ + i = alc_pin_mode_min(dir); + while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) + i++; + *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); + return 0; +} + +static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char dir = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + + if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir)) + val = alc_pin_mode_min(dir); + + change = pinctl != alc_pin_mode_values[val]; + if (change) { + /* Set pin mode to that requested */ + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); + + /* Also enable the retasking pin's input/output as required + * for the requested pin mode. Enum values of 2 or less are + * input modes. + * + * Dynamically switching the input/output buffers probably + * reduces noise slightly (particularly on input) so we'll + * do it. However, having both input and output buffers + * enabled simultaneously doesn't seem to be problematic if + * this turns out to be necessary in the future. + */ + if (val <= 2) { + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); + } else { + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); + } + } + return change; +} + +#define ALC_PIN_MODE(xname, nid, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_pin_mode_info, \ + .get = alc_pin_mode_get, \ + .put = alc_pin_mode_put, \ + .private_value = nid | (dir<<16) } + +/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged + * together using a mask with more than one bit set. This control is + * currently used only by the ALC260 test model. At this stage they are not + * needed for any "production" models. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_gpio_data_info snd_ctl_boolean_mono_info + +static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_DATA, + 0x00); + + /* Set/unset the masked GPIO bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (gpio_data & mask); + if (val == 0) + gpio_data &= ~mask; + else + gpio_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); + + return change; +} +#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_gpio_data_info, \ + .get = alc_gpio_data_get, \ + .put = alc_gpio_data_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling of the digital IO pins on the + * ALC260. This is incredibly simplistic; the intention of this control is + * to provide something in the test model allowing digital outputs to be + * identified if present. If models are found which can utilise these + * outputs a more complete mixer control can be devised for those models if + * necessary. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info + +static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, 0x00); + + *valp = (val & mask) != 0; + return 0; +} +static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + signed int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DIGI_CONVERT_1, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (val == 0 ? 0 : mask) != (ctrl_data & mask); + if (val==0) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); + + return change; +} +#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_spdif_ctrl_info, \ + .get = alc_spdif_ctrl_get, \ + .put = alc_spdif_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +/* A switch control to allow the enabling EAPD digital outputs on the ALC26x. + * Again, this is only used in the ALC26x test models to help identify when + * the EAPD line must be asserted for features to work. + */ +#ifdef CONFIG_SND_DEBUG +#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info + +static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, 0x00); + + *valp = (val & mask) != 0; + return 0; +} + +static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int change; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value & 0xffff; + unsigned char mask = (kcontrol->private_value >> 16) & 0xff; + long val = *ucontrol->value.integer.value; + unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, + 0x00); + + /* Set/unset the masked control bit(s) as needed */ + change = (!val ? 0 : mask) != (ctrl_data & mask); + if (!val) + ctrl_data &= ~mask; + else + ctrl_data |= mask; + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + ctrl_data); + + return change; +} + +#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ + .info = alc_eapd_ctrl_info, \ + .get = alc_eapd_ctrl_get, \ + .put = alc_eapd_ctrl_put, \ + .private_value = nid | (mask<<16) } +#endif /* CONFIG_SND_DEBUG */ + +static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!cfg->line_outs) { + while (cfg->line_outs < AUTO_CFG_MAX_OUTS && + cfg->line_out_pins[cfg->line_outs]) + cfg->line_outs++; + } + if (!cfg->speaker_outs) { + while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && + cfg->speaker_pins[cfg->speaker_outs]) + cfg->speaker_outs++; + } + if (!cfg->hp_outs) { + while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && + cfg->hp_pins[cfg->hp_outs]) + cfg->hp_outs++; + } +} + +/* + * set up from the preset table + */ +static void setup_preset(struct hda_codec *codec, + const struct alc_config_preset *preset) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) + add_mixer(spec, preset->mixers[i]); + spec->cap_mixer = preset->cap_mixer; + for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; + i++) + add_verb(spec, preset->init_verbs[i]); + + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + spec->need_dac_fix = preset->need_dac_fix; + spec->const_channel_count = preset->const_channel_count; + + if (preset->const_channel_count) + spec->multiout.max_channels = preset->const_channel_count; + else + spec->multiout.max_channels = spec->channel_mode[0].channels; + spec->ext_channel_count = spec->channel_mode[0].channels; + + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.slave_dig_outs = preset->slave_dig_outs; + spec->multiout.hp_nid = preset->hp_nid; + + spec->num_mux_defs = preset->num_mux_defs; + if (!spec->num_mux_defs) + spec->num_mux_defs = 1; + spec->input_mux = preset->input_mux; + + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; + spec->capsrc_nids = preset->capsrc_nids; + spec->dig_in_nid = preset->dig_in_nid; + + spec->unsol_event = preset->unsol_event; + spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = preset->power_hook; + spec->loopback.amplist = preset->loopbacks; +#endif + + if (preset->setup) + preset->setup(codec); + + alc_fixup_autocfg_pin_nums(codec); +} + +static void alc_simple_setup_automute(struct alc_spec *spec, int mode) +{ + int lo_pin = spec->autocfg.line_out_pins[0]; + + if (lo_pin == spec->autocfg.speaker_pins[0] || + lo_pin == spec->autocfg.hp_pins[0]) + lo_pin = 0; + spec->automute_mode = mode; + spec->detect_hp = !!spec->autocfg.hp_pins[0]; + spec->detect_lo = !!lo_pin; + spec->automute_lo = spec->automute_lo_possible = !!lo_pin; + spec->automute_speaker = spec->automute_speaker_possible = !!spec->autocfg.speaker_pins[0]; +} + +/* auto-toggle front mic */ +static void alc88x_simple_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_jack_detect(codec, 0x18); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); +} + diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 7a8fcc4c15f8..4df72c0e8c37 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -19,7 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -1448,7 +1447,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, for (i = 0; i < c->cvt_setups.used; i++) { p = snd_array_elem(&c->cvt_setups, i); if (!p->active && p->stream_tag == stream_tag && - get_wcaps_type(get_wcaps(c, p->nid)) == type) + get_wcaps_type(get_wcaps(codec, p->nid)) == type) p->dirty = 1; } } @@ -1760,11 +1759,7 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= index << AC_AMP_SET_INDEX_SHIFT; - if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && - (info->amp_caps & AC_AMPCAP_MIN_MUTE)) - ; /* set the zero value as a fake mute */ - else - parm |= val; + parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); info->vol[ch] = val; } @@ -2031,7 +2026,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 += ofs; val1 = ((int)val1) * ((int)val2); - if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) + if (min_mute) val2 |= TLV_DB_SCALE_MUTE; if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; @@ -2305,7 +2300,7 @@ typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); /* apply the function to all matching slave ctls in the mixer list */ static int map_slaves(struct hda_codec *codec, const char * const *slaves, - const char *suffix, map_slave_func_t func, void *data) + map_slave_func_t func, void *data) { struct hda_nid_item *items; const char * const *s; @@ -2318,14 +2313,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) continue; for (s = slaves; *s; s++) { - char tmpname[sizeof(sctl->id.name)]; - const char *name = *s; - if (suffix) { - snprintf(tmpname, sizeof(tmpname), "%s %s", - name, suffix); - name = tmpname; - } - if (!strcmp(sctl->id.name, name)) { + if (!strcmp(sctl->id.name, *s)) { err = func(data, sctl); if (err) return err; @@ -2341,65 +2329,12 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl) return 1; } -/* guess the value corresponding to 0dB */ -static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) -{ - int _tlv[4]; - const int *tlv = NULL; - int val = -1; - - if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - /* FIXME: set_fs() hack for obtaining user-space TLV data */ - mm_segment_t fs = get_fs(); - set_fs(get_ds()); - if (!kctl->tlv.c(kctl, 0, sizeof(_tlv), _tlv)) - tlv = _tlv; - set_fs(fs); - } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) - tlv = kctl->tlv.p; - if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) - val = -tlv[2] / tlv[3]; - return val; -} - -/* call kctl->put with the given value(s) */ -static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) -{ - struct snd_ctl_elem_value *ucontrol; - ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); - if (!ucontrol) - return -ENOMEM; - ucontrol->value.integer.value[0] = val; - ucontrol->value.integer.value[1] = val; - kctl->put(kctl, ucontrol); - kfree(ucontrol); - return 0; -} - -/* initialize the slave volume with 0dB */ -static int init_slave_0dB(void *data, struct snd_kcontrol *slave) -{ - int offset = get_kctl_0dB_offset(slave); - if (offset > 0) - put_kctl_with_value(slave, offset); - return 0; -} - -/* unmute the slave */ -static int init_slave_unmute(void *data, struct snd_kcontrol *slave) -{ - return put_kctl_with_value(slave, 1); -} - /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec * @name: vmaster control name * @tlv: TLV data (optional) * @slaves: slave control names (optional) - * @suffix: suffix string to each slave name (optional) - * @init_slave_vol: initialize slaves to unmute/0dB - * @ctl_ret: store the vmaster kcontrol in return * * Create a virtual master control with the given name. The TLV data * must be either NULL or a valid data. @@ -2410,18 +2345,13 @@ static int init_slave_unmute(void *data, struct snd_kcontrol *slave) * * This function returns zero if successful or a negative error code. */ -int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves, - const char *suffix, bool init_slave_vol, - struct snd_kcontrol **ctl_ret) +int snd_hda_add_vmaster(struct hda_codec *codec, char *name, + unsigned int *tlv, const char * const *slaves) { struct snd_kcontrol *kctl; int err; - if (ctl_ret) - *ctl_ret = NULL; - - err = map_slaves(codec, slaves, suffix, check_slave_present, NULL); + err = map_slaves(codec, slaves, check_slave_present, NULL); if (err != 1) { snd_printdd("No slave found for %s\n", name); return 0; @@ -2433,119 +2363,13 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - err = map_slaves(codec, slaves, suffix, - (map_slave_func_t)snd_ctl_add_slave, kctl); + err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave, + kctl); if (err < 0) return err; - - /* init with master mute & zero volume */ - put_kctl_with_value(kctl, 0); - if (init_slave_vol) - map_slaves(codec, slaves, suffix, - tlv ? init_slave_0dB : init_slave_unmute, kctl); - - if (ctl_ret) - *ctl_ret = kctl; - return 0; -} -EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); - -/* - * mute-LED control using vmaster - */ -static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "Off", "On", "Follow Master" - }; - unsigned int index; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - index = uinfo->value.enumerated.item; - if (index >= 3) - index = 2; - strcpy(uinfo->value.enumerated.name, texts[index]); - return 0; -} - -static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hook->mute_mode; return 0; } - -static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); - unsigned int old_mode = hook->mute_mode; - - hook->mute_mode = ucontrol->value.enumerated.item[0]; - if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER) - hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; - if (old_mode == hook->mute_mode) - return 0; - snd_hda_sync_vmaster_hook(hook); - return 1; -} - -static struct snd_kcontrol_new vmaster_mute_mode = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mute-LED Mode", - .info = vmaster_mute_mode_info, - .get = vmaster_mute_mode_get, - .put = vmaster_mute_mode_put, -}; - -/* - * Add a mute-LED hook with the given vmaster switch kctl - * "Mute-LED Mode" control is automatically created and associated with - * the given hook. - */ -int snd_hda_add_vmaster_hook(struct hda_codec *codec, - struct hda_vmaster_mute_hook *hook, - bool expose_enum_ctl) -{ - struct snd_kcontrol *kctl; - - if (!hook->hook || !hook->sw_kctl) - return 0; - snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); - hook->codec = codec; - hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; - if (!expose_enum_ctl) - return 0; - kctl = snd_ctl_new1(&vmaster_mute_mode, hook); - if (!kctl) - return -ENOMEM; - return snd_hda_ctl_add(codec, 0, kctl); -} -EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook); - -/* - * Call the hook with the current value for synchronization - * Should be called in init callback - */ -void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) -{ - if (!hook->hook || !hook->codec) - return; - switch (hook->mute_mode) { - case HDA_VMUTE_FOLLOW_MASTER: - snd_ctl_sync_vmaster_hook(hook->sw_kctl); - break; - default: - hook->hook(hook->codec, hook->mute_mode); - break; - } -} -EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); - +EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); /** * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch @@ -5290,7 +5114,7 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, const char *pfx = "", *sfx = ""; /* handle as a speaker if it's a fixed line-out */ - if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT) + if (!strcmp(name, "Line-Out") && attr == INPUT_PIN_ATTR_INT) name = "Speaker"; /* check the location */ switch (attr) { @@ -5349,7 +5173,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, switch (get_defcfg_device(def_conf)) { case AC_JACK_LINE_OUT: - return fill_audio_out_name(codec, nid, cfg, "Line Out", + return fill_audio_out_name(codec, nid, cfg, "Line-Out", label, maxlen, indexp); case AC_JACK_SPEAKER: return fill_audio_out_name(codec, nid, cfg, "Speaker", @@ -5444,10 +5268,6 @@ int snd_hda_suspend(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { if (hda_codec_is_power_on(codec)) hda_call_codec_suspend(codec); - else /* forcibly change the power to D3 even if not used */ - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D3); if (codec->patch_ops.post_suspend) codec->patch_ops.post_suspend(codec); } diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index 9a9f372e1be4..e9f71dc0d464 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -298,9 +298,6 @@ enum { #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 -/* driver-specific amp-caps: using bits 24-30 */ -#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ - /* Connection list */ #define AC_CLIST_LENGTH (0x7f<<0) #define AC_CLIST_LONG (1<<7) @@ -855,7 +852,6 @@ struct hda_codec { unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */ - unsigned int no_jack_detect:1; /* Machine has no jack-detection */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ unsigned int power_transition :1; /* power-state in transition */ diff --git a/trunk/sound/pci/hda/hda_eld.c b/trunk/sound/pci/hda/hda_eld.c index b58b4b1687fa..c1da422e085a 100644 --- a/trunk/sound/pci/hda/hda_eld.c +++ b/trunk/sound/pci/hda/hda_eld.c @@ -385,8 +385,8 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) { static unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000, 384000 + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 }; int i, j; diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index c19e71a94e1b..fb35474c1203 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -84,7 +84,7 @@ module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "DMA pointer read method." - "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); + "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO)."); module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); @@ -94,7 +94,7 @@ MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); -module_param(enable_msi, bint, 0444); +module_param(enable_msi, int, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); #ifdef CONFIG_SND_HDA_PATCH_LOADER module_param_array(patch, charp, NULL, 0444); @@ -121,8 +121,8 @@ module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif -static int align_buffer_size = -1; -module_param(align_buffer_size, bint, 0644); +static bool align_buffer_size = 1; +module_param(align_buffer_size, bool, 0644); MODULE_PARM_DESC(align_buffer_size, "Force buffer and period sizes to be multiple of 128 bytes."); @@ -148,7 +148,6 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, PCH}," "{Intel, CPT}," "{Intel, PPT}," - "{Intel, LPT}," "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," @@ -330,7 +329,6 @@ enum { POS_FIX_LPIB, POS_FIX_POSBUF, POS_FIX_VIACOMBO, - POS_FIX_COMBO, }; /* Defines for ATI HD Audio support in SB450 south bridge */ @@ -471,7 +469,6 @@ struct azx { unsigned int irq_pending_warned :1; unsigned int probing :1; /* codec probing phase */ unsigned int snoop:1; - unsigned int align_buffer_size:1; /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; @@ -517,7 +514,6 @@ enum { #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ -#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -530,8 +526,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE) + (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI) static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -1695,7 +1690,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates = hinfo->rates; snd_pcm_limit_hw_rates(runtime); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (chip->align_buffer_size) + if (align_buffer_size) /* constrain buffer sizes to be multiple of 128 bytes. This is more efficient in terms of memory access but isn't required by the HDA spec and @@ -2351,6 +2346,17 @@ static void azx_power_notify(struct hda_bus *bus) * power management */ +static int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec; + + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} + static int azx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); @@ -2397,7 +2403,8 @@ static int azx_resume(struct pci_dev *pci) return -EIO; azx_init_pci(chip); - azx_init_chip(chip, 1); + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip, 1); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2509,7 +2516,6 @@ static int __devinit check_position_fix(struct azx *chip, int fix) case POS_FIX_LPIB: case POS_FIX_POSBUF: case POS_FIX_VIACOMBO: - case POS_FIX_COMBO: return fix; } @@ -2689,12 +2695,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->position_fix[0] = chip->position_fix[1] = check_position_fix(chip, position_fix[dev]); - /* combo mode uses LPIB for playback */ - if (chip->position_fix[0] == POS_FIX_COMBO) { - chip->position_fix[0] = POS_FIX_LPIB; - chip->position_fix[1] = POS_FIX_AUTO; - } - check_probe_mask(chip, dev); chip->single_cmd = single_cmd; @@ -2773,16 +2773,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } /* disable buffer size rounding to 128-byte multiples if supported */ - if (align_buffer_size >= 0) - chip->align_buffer_size = !!align_buffer_size; - else { - if (chip->driver_caps & AZX_DCAPS_BUFSIZE) - chip->align_buffer_size = 0; - else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE) - chip->align_buffer_size = 1; - else - chip->align_buffer_size = 1; - } + if (chip->driver_caps & AZX_DCAPS_BUFSIZE) + align_buffer_size = 0; /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) @@ -2998,10 +2990,6 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE}, - /* Lynx Point */ - { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | diff --git a/trunk/sound/pci/hda/hda_jack.c b/trunk/sound/pci/hda/hda_jack.c index d68948499fbc..d8a35da0803f 100644 --- a/trunk/sound/pci/hda/hda_jack.c +++ b/trunk/sound/pci/hda/hda_jack.c @@ -19,22 +19,6 @@ #include "hda_local.h" #include "hda_jack.h" -bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) -{ - if (codec->no_jack_detect) - return false; - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) - return false; - if (!codec->ignore_misc_bit && - (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - return false; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) - return false; - return true; -} -EXPORT_SYMBOL_HDA(is_jack_detectable); - /* execute pin sense measurement */ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) { @@ -298,8 +282,7 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, - char *lastname, int *lastidx) + const struct auto_pin_cfg *cfg) { unsigned int def_conf, conn; char name[44]; @@ -315,10 +298,6 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return 0; snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); - if (!strcmp(name, lastname) && idx == *lastidx) - idx++; - strncpy(lastname, name, 44); - *lastidx = idx; err = snd_hda_jack_add_kctl(codec, nid, name, idx); if (err < 0) return err; @@ -332,42 +311,41 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { const hda_nid_t *p; - int i, err, lastidx = 0; - char lastname[44] = ""; + int i, err; for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } for (i = 0; i < cfg->num_inputs; i++) { - err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg); if (err < 0) return err; } for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, *p, cfg); if (err < 0) return err; } - err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, cfg->dig_in_pin, cfg); if (err < 0) return err; - err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, lastname, &lastidx); + err = add_jack_kctl(codec, cfg->mono_out_pin, cfg); if (err < 0) return err; return 0; diff --git a/trunk/sound/pci/hda/hda_jack.h b/trunk/sound/pci/hda/hda_jack.h index c66655cf413a..f8f97c71c9c1 100644 --- a/trunk/sound/pci/hda/hda_jack.h +++ b/trunk/sound/pci/hda/hda_jack.h @@ -62,7 +62,18 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); -bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); +static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) +{ + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) + return false; + if (!codec->ignore_misc_bit && + (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + return false; + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return false; + return true; +} int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name, int idx); diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 0ec9248165bc..aca8d3193b95 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -139,36 +139,10 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv); struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); -int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves, - const char *suffix, bool init_slave_vol, - struct snd_kcontrol **ctl_ret); -#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \ - __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) +int snd_hda_add_vmaster(struct hda_codec *codec, char *name, + unsigned int *tlv, const char * const *slaves); int snd_hda_codec_reset(struct hda_codec *codec); -enum { - HDA_VMUTE_OFF, - HDA_VMUTE_ON, - HDA_VMUTE_FOLLOW_MASTER, -}; - -struct hda_vmaster_mute_hook { - /* below two fields must be filled by the caller of - * snd_hda_add_vmaster_hook() beforehand - */ - struct snd_kcontrol *sw_kctl; - void (*hook)(void *, int); - /* below are initialized automatically */ - unsigned int mute_mode; /* HDA_VMUTE_XXX */ - struct hda_codec *codec; -}; - -int snd_hda_add_vmaster_hook(struct hda_codec *codec, - struct hda_vmaster_mute_hook *hook, - bool expose_enum_ctl); -void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook); - /* amp value bits */ #define HDA_AMP_MUTE 0x80 #define HDA_AMP_UNMUTE 0x00 diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 7143393927da..9cb14b42dfff 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -82,7 +82,6 @@ struct ad198x_spec { unsigned int inv_jack_detect: 1;/* inverted jack-detection */ unsigned int inv_eapd: 1; /* inverted EAPD implementation */ unsigned int analog_beep: 1; /* analog beep input present */ - unsigned int avoid_init_slave_vol:1; #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; @@ -138,17 +137,51 @@ static int ad198x_init(struct hda_codec *codec) return 0; } -static const char * const ad_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Mono", "Speaker", "IEC958", +static const char * const ad_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Mono Playback Volume", + "Speaker Playback Volume", + "IEC958 Playback Volume", NULL }; -static const char * const ad1988_6stack_fp_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", "IEC958", +static const char * const ad_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Mono Playback Switch", + "Speaker Playback Switch", + "IEC958 Playback Switch", NULL }; +static const char * const ad1988_6stack_fp_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "IEC958 Playback Volume", + NULL +}; + +static const char * const ad1988_6stack_fp_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "IEC958 Playback Switch", + NULL +}; static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -224,12 +257,10 @@ static int ad198x_build_controls(struct hda_codec *codec) unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); - err = __snd_hda_add_vmaster(codec, "Master Playback Volume", + err = snd_hda_add_vmaster(codec, "Master Playback Volume", vmaster_tlv, (spec->slave_vols ? - spec->slave_vols : ad_slave_pfxs), - "Playback Volume", - !spec->avoid_init_slave_vol, NULL); + spec->slave_vols : ad_slave_vols)); if (err < 0) return err; } @@ -237,8 +268,7 @@ static int ad198x_build_controls(struct hda_codec *codec) err = snd_hda_add_vmaster(codec, "Master Playback Switch", NULL, (spec->slave_sws ? - spec->slave_sws : ad_slave_pfxs), - "Playback Switch"); + spec->slave_sws : ad_slave_sws)); if (err < 0) return err; } @@ -3355,8 +3385,8 @@ static int patch_ad1988(struct hda_codec *codec) if (spec->autocfg.hp_pins[0]) { spec->mixers[spec->num_mixers++] = ad1988_hp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_pfxs; - spec->slave_sws = ad1988_6stack_fp_slave_pfxs; + spec->slave_vols = ad1988_6stack_fp_slave_vols; + spec->slave_sws = ad1988_6stack_fp_slave_sws; spec->alt_dac_nid = ad1988_alt_dac_nid; spec->stream_analog_alt_playback = &ad198x_pcm_analog_alt_playback; @@ -3564,8 +3594,16 @@ static const struct hda_amp_list ad1884_loopbacks[] = { #endif static const char * const ad1884_slave_vols[] = { - "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", - "Internal Mic", "Docking Mic", /* "Beep", */ "IEC958", + "PCM Playback Volume", + "Mic Playback Volume", + "Mono Playback Volume", + "Front Mic Playback Volume", + "Mic Playback Volume", + "CD Playback Volume", + "Internal Mic Playback Volume", + "Docking Mic Playback Volume", + /* "Beep Playback Volume", */ + "IEC958 Playback Volume", NULL }; @@ -3606,8 +3644,6 @@ static int patch_ad1884(struct hda_codec *codec) spec->vmaster_nid = 0x04; /* we need to cover all playback volumes */ spec->slave_vols = ad1884_slave_vols; - /* slaves may contain input volumes, so we can't raise to 0dB blindly */ - spec->avoid_init_slave_vol = 1; codec->patch_ops = ad198x_patch_ops; diff --git a/trunk/sound/pci/hda/patch_ca0132.c b/trunk/sound/pci/hda/patch_ca0132.c index 21d91d580da8..35abe3c62908 100644 --- a/trunk/sound/pci/hda/patch_ca0132.c +++ b/trunk/sound/pci/hda/patch_ca0132.c @@ -728,19 +728,18 @@ static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_MUTE, &data); if (err < 0) - goto exit; + return err; /* *valp 0 is mute, 1 is unmute */ data = (data & 0x7f) | (*valp ? 0 : 0x80); - err = chipio_write(codec, REG_CODEC_MUTE, data); + chipio_write(codec, REG_CODEC_MUTE, data); if (err < 0) - goto exit; + return err; spec->curr_hp_switch = *valp; - exit: snd_hda_power_down(codec); - return err < 0 ? err : 1; + return 1; } static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol, @@ -771,19 +770,18 @@ static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_MUTE, &data); if (err < 0) - goto exit; + return err; /* *valp 0 is mute, 1 is unmute */ data = (data & 0xef) | (*valp ? 0 : 0x10); - err = chipio_write(codec, REG_CODEC_MUTE, data); + chipio_write(codec, REG_CODEC_MUTE, data); if (err < 0) - goto exit; + return err; spec->curr_speaker_switch = *valp; - exit: snd_hda_power_down(codec); - return err < 0 ? err : 1; + return 1; } static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol, @@ -821,26 +819,25 @@ static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data); if (err < 0) - goto exit; + return err; val = 31 - left_vol; data = (data & 0xe0) | val; - err = chipio_write(codec, REG_CODEC_HP_VOL_L, data); + chipio_write(codec, REG_CODEC_HP_VOL_L, data); if (err < 0) - goto exit; + return err; val = 31 - right_vol; data = (data & 0xe0) | val; - err = chipio_write(codec, REG_CODEC_HP_VOL_R, data); + chipio_write(codec, REG_CODEC_HP_VOL_R, data); if (err < 0) - goto exit; + return err; spec->curr_hp_volume[0] = left_vol; spec->curr_hp_volume[1] = right_vol; - exit: snd_hda_power_down(codec); - return err < 0 ? err : 1; + return 1; } static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid) @@ -939,8 +936,6 @@ static int ca0132_build_controls(struct hda_codec *codec) if (err < 0) return err; err = add_in_volume(codec, spec->dig_in, "IEC958"); - if (err < 0) - return err; } return 0; } diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index c83ccdba1e5a..0e99357e822c 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -609,7 +609,7 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, "Front Speaker", "Surround Speaker", "Bass Speaker" }; static const char * const line_outs[] = { - "Front Line Out", "Surround Line Out", "Bass Line Out" + "Front Line-Out", "Surround Line-Out", "Bass Line-Out" }; fix_volume_caps(codec, dac); @@ -635,7 +635,7 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, if (num_ctls > 1) name = line_outs[idx]; else - name = "Line Out"; + name = "Line-Out"; break; } @@ -988,10 +988,8 @@ static void cs_automic(struct hda_codec *codec) change_cur_input(codec, !spec->automic_idx, 0); } else { if (present) { - if (spec->cur_input != spec->automic_idx) { - spec->last_input = spec->cur_input; - spec->cur_input = spec->automic_idx; - } + spec->last_input = spec->cur_input; + spec->cur_input = spec->automic_idx; } else { spec->cur_input = spec->last_input; } diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index e6eafb18c8f5..8a32a69c83c3 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -70,8 +70,6 @@ struct conexant_spec { const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; - bool vmaster_mute_led; const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -467,8 +465,21 @@ static const struct snd_kcontrol_new cxt_beep_mixer[] = { }; #endif -static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Front", "Surround", "CLFE", +static const char * const slave_vols[] = { + "Headphone Playback Volume", + "Speaker Playback Volume", + "Front Playback Volume", + "Surround Playback Volume", + "CLFE Playback Volume", + NULL +}; + +static const char * const slave_sws[] = { + "Headphone Playback Switch", + "Speaker Playback Switch", + "Front Playback Switch", + "Surround Playback Switch", + "CLFE Playback Switch", NULL }; @@ -508,17 +519,14 @@ static int conexant_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); + vmaster_tlv, slave_vols); if (err < 0) return err; } if (spec->vmaster_nid && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch", true, - &spec->vmaster_mute.sw_kctl); + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_sws); if (err < 0) return err; } @@ -3019,13 +3027,14 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO), + SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO), {} }; @@ -3473,7 +3482,7 @@ static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, "Disabled", "Enabled" }; static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" + "Disabled", "Speaker Only", "Line-Out+Speaker" }; const char * const *texts; @@ -3934,63 +3943,6 @@ static void enable_unsol_pins(struct hda_codec *codec, int num_pins, snd_hda_jack_detect_enable(codec, pins[i], action); } -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* is the given NID found in any of autocfg items? */ -static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid) -{ - int i; - - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) || - found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs)) - return true; - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].pin == nid) - return true; - if (cfg->dig_in_pin == nid) - return true; - return false; -} - -/* clear unsol-event tags on unused pins; Conexant codecs seem to leave - * invalid unsol tags by some reason - */ -static void clear_unsol_on_unused_pins(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - if (!found_in_autocfg(cfg, pin->nid)) - snd_hda_codec_write(codec, pin->nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, 0); - } -} - -/* turn on/off EAPD according to Master switch */ -static void cx_auto_vmaster_hook(void *private_data, int enabled) -{ - struct hda_codec *codec = private_data; - struct conexant_spec *spec = codec->spec; - - if (enabled && spec->pin_eapd_ctrls) { - cx_auto_update_speakers(codec); - return; - } - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); -} - static void cx_auto_init_output(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -4031,7 +3983,6 @@ static void cx_auto_init_output(struct hda_codec *codec) /* turn on all EAPDs if no individual EAPD control is available */ if (!spec->pin_eapd_ctrls) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); - clear_unsol_on_unused_pins(codec); } static void cx_auto_init_input(struct hda_codec *codec) @@ -4095,13 +4046,11 @@ static void cx_auto_init_digital(struct hda_codec *codec) static int cx_auto_init(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/ cx_auto_init_output(codec); cx_auto_init_input(codec); cx_auto_init_digital(codec); snd_hda_jack_report_sync(codec); - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); return 0; } @@ -4130,8 +4079,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; - if (!(query_amp_caps(codec, nid, hda_dir) & - (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) + if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) break; } return 0; @@ -4347,13 +4295,6 @@ static int cx_auto_build_controls(struct hda_codec *codec) err = snd_hda_jack_add_kctls(codec, &spec->autocfg); if (err < 0) return err; - if (spec->vmaster_mute.sw_kctl) { - spec->vmaster_mute.hook = cx_auto_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, - spec->vmaster_mute_led); - if (err < 0) - return err; - } return 0; } @@ -4378,6 +4319,7 @@ static int cx_auto_search_adcs(struct hda_codec *codec) return 0; } + static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = cx_auto_build_controls, .build_pcms = conexant_build_pcms, @@ -4425,7 +4367,6 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ { 0x17, 0x21a11000 }, /* dock-mic */ { 0x19, 0x2121103f }, /* dock-HP */ - { 0x1c, 0x21440100 }, /* dock SPDIF out */ {} }; @@ -4438,22 +4379,6 @@ static const struct snd_pci_quirk cxt_fixups[] = { {} }; -/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches - * can be created (bko#42825) - */ -static void add_cx5051_fake_mutes(struct hda_codec *codec) -{ - static hda_nid_t out_nids[] = { - 0x10, 0x11, 0 - }; - hda_nid_t *p; - - for (p = out_nids; *p; p++) - snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT, - AC_AMPCAP_MIN_MUTE | - query_amp_caps(codec, *p, HDA_OUTPUT)); -} - static int patch_conexant_auto(struct hda_codec *codec) { struct conexant_spec *spec; @@ -4472,25 +4397,10 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f15045: spec->single_adc_amp = 1; break; - case 0x14f15051: - add_cx5051_fake_mutes(codec); - break; } apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); - /* Show mute-led control only on HP laptops - * This is a sort of white-list: on HP laptops, EAPD corresponds - * only to the mute-LED without actualy amp function. Meanwhile, - * others may use EAPD really as an amp switch, so it might be - * not good to expose it blindly. - */ - switch (codec->subsystem_id >> 16) { - case 0x103c: - spec->vmaster_mute_led = 1; - break; - } - err = cx_auto_search_adcs(codec); if (err < 0) return err; @@ -4504,18 +4414,6 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->patch_ops = cx_auto_patch_ops; if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); - - /* Some laptops with Conexant chips show stalls in S3 resume, - * which falls into the single-cmd mode. - * Better to make reset, then. - */ - if (!codec->bus->sync_write) { - snd_printd("hda_codec: " - "Enable sync_write for stable communication\n"); - codec->bus->sync_write = 1; - codec->bus->allow_bus_reset = 1; - } - return 0; } diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index 540cd13f7f15..1168ebd3fb5c 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -1912,7 +1912,6 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -1959,7 +1958,6 @@ MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:80862805"); MODULE_ALIAS("snd-hda-codec-id:80862806"); -MODULE_ALIAS("snd-hda-codec-id:80862880"); MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 8ea2fd654327..5e82acf77c5a 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -80,8 +80,6 @@ enum { ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */ }; -#define MAX_VOL_NIDS 0x40 - struct alc_spec { /* codec parameterization */ const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -120,8 +118,8 @@ struct alc_spec { const hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ hda_nid_t mixer_nid; /* analog-mixer NID */ - DECLARE_BITMAP(vol_ctls, MAX_VOL_NIDS << 1); - DECLARE_BITMAP(sw_ctls, MAX_VOL_NIDS << 1); + DECLARE_BITMAP(vol_ctls, 0x20 << 1); + DECLARE_BITMAP(sw_ctls, 0x20 << 1); /* capture setup for dynamic dual-adc switch */ hda_nid_t cur_adc; @@ -179,7 +177,6 @@ struct alc_spec { unsigned int detect_lo:1; /* Line-out detection enabled */ unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ unsigned int automute_lo_possible:1; /* there are line outs and HP */ - unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ /* other flags */ unsigned int no_analog :1; /* digital I/O only */ @@ -188,6 +185,7 @@ struct alc_spec { unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ + unsigned int use_jack_tbl:1; /* 1 for model=auto */ /* auto-mute control */ int automute_mode; @@ -198,11 +196,8 @@ struct alc_spec { /* for virtual master */ hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; #endif /* for PLL fix */ @@ -223,6 +218,8 @@ struct alc_spec { struct snd_array bind_ctls; }; +#define ALC_MODEL_AUTO 0 /* common for all chips */ + static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int bits) { @@ -301,9 +298,6 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, int i, type, num_conns; hda_nid_t nid; - if (!spec->input_mux) - return 0; - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) @@ -502,24 +496,13 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, for (i = 0; i < num_pins; i++) { hda_nid_t nid = pins[i]; - unsigned int val; if (!nid) break; switch (spec->automute_mode) { case ALC_AUTOMUTE_PIN: - /* don't reset VREF value in case it's controlling - * the amp (see alc861_fixup_asus_amp_vref_0f()) - */ - if (spec->keep_vref_in_automute) { - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - val &= ~PIN_HP; - } else - val = 0; - val |= pin_bits; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - val); + pin_bits); break; case ALC_AUTOMUTE_AMP: snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, @@ -638,10 +621,17 @@ static void alc_mic_automute(struct hda_codec *codec) alc_mux_select(codec, 0, spec->int_mic_idx, false); } -/* handle the specified unsol action (ALC_XXX_EVENT) */ -static void alc_exec_unsol_event(struct hda_codec *codec, int action) +/* unsolicited event for HP jack sensing */ +static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) { - switch (action) { + struct alc_spec *spec = codec->spec; + if (codec->vendor_id == 0x10ec0880) + res >>= 28; + else + res >>= 26; + if (spec->use_jack_tbl) + res = snd_hda_jack_get_action(codec, res); + switch (res) { case ALC_HP_EVENT: alc_hp_automute(codec); break; @@ -655,53 +645,6 @@ static void alc_exec_unsol_event(struct hda_codec *codec, int action) snd_hda_jack_report_sync(codec); } -/* update the master volume per volume-knob's unsol event */ -static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - struct snd_kcontrol *kctl; - struct snd_ctl_elem_value *uctl; - - kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume"); - if (!kctl) - return; - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (!uctl) - return; - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); - val &= HDA_AMP_VOLMASK; - uctl->value.integer.value[0] = val; - uctl->value.integer.value[1] = val; - kctl->put(kctl, uctl); - kfree(uctl); -} - -/* unsolicited event for HP jack sensing */ -static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) -{ - int action; - - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - action = snd_hda_jack_get_action(codec, res); - if (action == ALC_DCVOL_EVENT) { - /* Execute the dc-vol event here as it requires the NID - * but we don't pass NID to alc_exec_unsol_event(). - * Once when we convert all static quirks to the auto-parser, - * this can be integerated into there. - */ - struct hda_jack_tbl *jack; - jack = snd_hda_jack_tbl_get_from_tag(codec, res); - if (jack) - alc_update_knob_master(codec, jack->nid); - return; - } - alc_exec_unsol_event(codec, action); -} - /* call init functions of standard auto-mute helpers */ static void alc_inithook(struct hda_codec *codec) { @@ -842,7 +785,7 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, "Disabled", "Enabled" }; static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" + "Disabled", "Speaker Only", "Line-Out+Speaker" }; const char * const *texts; @@ -1073,6 +1016,45 @@ static bool alc_check_dyn_adc_switch(struct hda_codec *codec) return true; } +/* rebuild imux for matching with the given auto-mic pins (if not yet) */ +static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux; + static char * const texts[3] = { + "Mic", "Internal Mic", "Dock Mic" + }; + int i; + + if (!spec->auto_mic) + return false; + imux = &spec->private_imux[0]; + if (spec->input_mux == imux) + return true; + spec->imux_pins[0] = spec->ext_mic_pin; + spec->imux_pins[1] = spec->int_mic_pin; + spec->imux_pins[2] = spec->dock_mic_pin; + for (i = 0; i < 3; i++) { + strcpy(imux->items[i].label, texts[i]); + if (spec->imux_pins[i]) { + hda_nid_t pin = spec->imux_pins[i]; + int c; + for (c = 0; c < spec->num_adc_nids; c++) { + hda_nid_t cap = get_capsrc(spec, c); + int idx = get_connection_index(codec, cap, pin); + if (idx >= 0) { + imux->items[i].index = idx; + break; + } + } + imux->num_items = i + 1; + } + } + spec->num_mux_defs = 1; + spec->input_mux = imux; + return true; +} + /* check whether all auto-mic pins are valid; setup indices if OK */ static bool alc_auto_mic_check_imux(struct hda_codec *codec) { @@ -1442,7 +1424,6 @@ enum { ALC_FIXUP_ACT_PRE_PROBE, ALC_FIXUP_ACT_PROBE, ALC_FIXUP_ACT_INIT, - ALC_FIXUP_ACT_BUILD, }; static void alc_apply_fixup(struct hda_codec *codec, int action) @@ -1522,13 +1503,6 @@ static void alc_pick_fixup(struct hda_codec *codec, int id = -1; const char *name = NULL; - /* when model=nofixup is given, don't pick up any fixups */ - if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { - spec->fixup_list = NULL; - spec->fixup_id = -1; - return; - } - if (codec->modelname && models) { while (models->name) { if (!strcmp(codec->modelname, models->name)) { @@ -1856,10 +1830,32 @@ DEFINE_CAPMIX_NOSRC(3); /* * slave controls for virtual master */ -static const char * const alc_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "Mono", "Line Out", - "CLFE", "Bass Speaker", "PCM", +static const char * const alc_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Speaker Playback Volume", + "Mono Playback Volume", + "Line-Out Playback Volume", + "PCM Playback Volume", + NULL, +}; + +static const char * const alc_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Speaker Playback Switch", + "Mono Playback Switch", + "IEC958 Playback Switch", + "Line-Out Playback Switch", + "PCM Playback Switch", NULL, }; @@ -1887,7 +1883,7 @@ static const struct snd_kcontrol_new alc_beep_mixer[] = { }; #endif -static int __alc_build_controls(struct hda_codec *codec) +static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct snd_kcontrol *kctl = NULL; @@ -1950,17 +1946,14 @@ static int __alc_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, alc_slave_pfxs, - "Playback Volume"); + vmaster_tlv, alc_slave_vols); if (err < 0) return err; } if (!spec->no_analog && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_pfxs, - "Playback Switch", - true, &spec->vmaster_mute.sw_kctl); + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, alc_slave_sws); if (err < 0) return err; } @@ -2036,19 +2029,10 @@ static int __alc_build_controls(struct hda_codec *codec) alc_free_kctls(codec); /* no longer needed */ - return 0; -} - -static int alc_build_controls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err = __alc_build_controls(codec); - if (err < 0) - return err; err = snd_hda_jack_add_kctls(codec, &spec->autocfg); if (err < 0) return err; - alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); + return 0; } @@ -2058,23 +2042,21 @@ static int alc_build_controls(struct hda_codec *codec) */ static void alc_init_special_input_src(struct hda_codec *codec); -static void alc_auto_init_std(struct hda_codec *codec); static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int i; - if (spec->init_hook) - spec->init_hook(codec); - alc_fix_pll(codec); alc_auto_init_amp(codec, spec->init_amp); for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); alc_init_special_input_src(codec); - alc_auto_init_std(codec); + + if (spec->init_hook) + spec->init_hook(codec); alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); @@ -2316,7 +2298,7 @@ static int alc_build_pcms(struct hda_codec *codec) "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - if (spec->multiout.num_dacs > 0) { + if (spec->multiout.dac_nids > 0) { p = spec->stream_analog_playback; if (!p) p = &alc_pcm_analog_playback; @@ -2663,25 +2645,6 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return channel_name[ch]; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx) -{ - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) - return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} -#else -#define add_loopback_list(spec, mix, idx) /* NOP */ -#endif - /* create input playback/capture controls for the given pin */ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname, int ctlidx, @@ -2697,7 +2660,6 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; - add_loopback_list(spec, mix_nid, idx); return 0; } @@ -2962,27 +2924,10 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, return 0; } -static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - int i; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - ARRAY_SIZE(spec->private_dac_nids)) || - found_in_nid_list(nid, spec->multiout.hp_out_nid, - ARRAY_SIZE(spec->multiout.hp_out_nid)) || - found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - return true; - for (i = 0; i < spec->multi_ios; i++) { - if (spec->multi_io[i].dac == nid) - return true; - } - return false; -} - /* look for an empty DAC slot */ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) { + struct alc_spec *spec = codec->spec; hda_nid_t srcs[5]; int i, num; @@ -2992,8 +2937,16 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); if (!nid) continue; - if (!alc_is_dac_already_used(codec, nid)) - return nid; + if (found_in_nid_list(nid, spec->multiout.dac_nids, + ARRAY_SIZE(spec->private_dac_nids))) + continue; + if (found_in_nid_list(nid, spec->multiout.hp_out_nid, + ARRAY_SIZE(spec->multiout.hp_out_nid))) + continue; + if (found_in_nid_list(nid, spec->multiout.extra_out_nid, + ARRAY_SIZE(spec->multiout.extra_out_nid))) + continue; + return nid; } return 0; } @@ -3005,8 +2958,6 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec, hda_nid_t srcs[5]; int i, num; - if (!pin || !dac) - return false; pin = alc_go_down_to_selector(codec, pin); num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); for (i = 0; i < num; i++) { @@ -3019,260 +2970,83 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec, static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) { - struct alc_spec *spec = codec->spec; hda_nid_t sel = alc_go_down_to_selector(codec, pin); - hda_nid_t nid, nid_found, srcs[5]; - int i, num = snd_hda_get_connections(codec, sel, srcs, - ARRAY_SIZE(srcs)); - if (num == 1) + if (snd_hda_get_conn_list(codec, sel, NULL) == 1) return alc_auto_look_for_dac(codec, pin); - nid_found = 0; - for (i = 0; i < num; i++) { - if (srcs[i] == spec->mixer_nid) - continue; - nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (nid && !alc_is_dac_already_used(codec, nid)) { - if (nid_found) - return 0; - nid_found = nid; - } - } - return nid_found; -} - -/* mark up volume and mute control NIDs: used during badness parsing and - * at creating actual controls - */ -static inline unsigned int get_ctl_pos(unsigned int data) -{ - hda_nid_t nid = get_amp_nid_(data); - unsigned int dir; - if (snd_BUG_ON(nid >= MAX_VOL_NIDS)) - return 0; - dir = get_amp_direction_(data); - return (nid << 1) | dir; -} - -#define is_ctl_used(bits, data) \ - test_bit(get_ctl_pos(data), bits) -#define mark_ctl_usage(bits, data) \ - set_bit(get_ctl_pos(data), bits) - -static void clear_vol_marks(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls)); - memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls)); + return 0; } -/* badness definition */ -enum { - /* No primary DAC is found for the main output */ - BAD_NO_PRIMARY_DAC = 0x10000, - /* No DAC is found for the extra output */ - BAD_NO_DAC = 0x4000, - /* No possible multi-ios */ - BAD_MULTI_IO = 0x103, - /* No individual DAC for extra output */ - BAD_NO_EXTRA_DAC = 0x102, - /* No individual DAC for extra surrounds */ - BAD_NO_EXTRA_SURR_DAC = 0x101, - /* Primary DAC shared with main surrounds */ - BAD_SHARED_SURROUND = 0x100, - /* Primary DAC shared with main CLFE */ - BAD_SHARED_CLFE = 0x10, - /* Primary DAC shared with extra surrounds */ - BAD_SHARED_EXTRA_SURROUND = 0x10, - /* Volume widget is shared */ - BAD_SHARED_VOL = 0x10, -}; - -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); - -static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - unsigned int val; - int badness = 0; - - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) { - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, nid)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->vol_ctls, val); - } else - badness += BAD_SHARED_VOL; - nid = alc_look_for_out_mute_nid(codec, pin, dac); - if (nid) { - unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); - if (is_ctl_used(spec->sw_ctls, val)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->sw_ctls, val); - } else - badness += BAD_SHARED_VOL; - return badness; -} - -struct badness_table { - int no_primary_dac; /* no primary DAC */ - int no_dac; /* no secondary DACs */ - int shared_primary; /* primary DAC is shared with main output */ - int shared_surr; /* secondary DAC shared with main or primary */ - int shared_clfe; /* third DAC shared with main or primary */ - int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ -}; - -static struct badness_table main_out_badness = { - .no_primary_dac = BAD_NO_PRIMARY_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_PRIMARY_DAC, - .shared_surr = BAD_SHARED_SURROUND, - .shared_clfe = BAD_SHARED_CLFE, - .shared_surr_main = BAD_SHARED_SURROUND, -}; - -static struct badness_table extra_out_badness = { - .no_primary_dac = BAD_NO_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_EXTRA_DAC, - .shared_surr = BAD_SHARED_EXTRA_SURROUND, - .shared_clfe = BAD_SHARED_EXTRA_SURROUND, - .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, -}; - -/* try to assign DACs to pins and return the resultant badness */ -static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, hda_nid_t *dacs, - const struct badness_table *bad) +/* return 0 if no possible DAC is found, 1 if one or more found */ +static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs, + const hda_nid_t *pins, hda_nid_t *dacs) { - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, j; - int badness = 0; - hda_nid_t dac; + int i; - if (!num_outs) - return 0; + if (num_outs && !dacs[0]) { + dacs[0] = alc_auto_look_for_dac(codec, pins[0]); + if (!dacs[0]) + return 0; + } - for (i = 0; i < num_outs; i++) { - hda_nid_t pin = pins[i]; + for (i = 1; i < num_outs; i++) + dacs[i] = get_dac_if_single(codec, pins[i]); + for (i = 1; i < num_outs; i++) { if (!dacs[i]) - dacs[i] = alc_auto_look_for_dac(codec, pin); - if (!dacs[i] && !i) { - for (j = 1; j < num_outs; j++) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) { - dacs[0] = dacs[j]; - dacs[j] = 0; - break; - } - } - } - dac = dacs[i]; - if (!dac) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[0])) - dac = dacs[0]; - else if (cfg->line_outs > i && - alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[i])) - dac = spec->private_dac_nids[i]; - if (dac) { - if (!i) - badness += bad->shared_primary; - else if (i == 1) - badness += bad->shared_surr; - else - badness += bad->shared_clfe; - } else if (alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[0])) { - dac = spec->private_dac_nids[0]; - badness += bad->shared_surr_main; - } else if (!i) - badness += bad->no_primary_dac; - else - badness += bad->no_dac; - } - if (dac) - badness += eval_shared_vol_badness(codec, pin, dac); + dacs[i] = alc_auto_look_for_dac(codec, pins[i]); } - - return badness; + return 1; } static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset); - -static bool alc_map_singles(struct hda_codec *codec, int outs, - const hda_nid_t *pins, hda_nid_t *dacs) -{ - int i; - bool found = false; - for (i = 0; i < outs; i++) { - if (dacs[i]) - continue; - dacs[i] = get_dac_if_single(codec, pins[i]); - if (dacs[i]) - found = true; - } - return found; -} + unsigned int location, int offset); +static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, + hda_nid_t pin, hda_nid_t dac); /* fill in the dac_nids table from the parsed pin configuration */ -static int fill_and_eval_dacs(struct hda_codec *codec, - bool fill_hardwired, - bool fill_mio_first) +static int alc_auto_fill_dac_nids(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err, badness; + unsigned int location, defcfg; + int num_pins; + bool redone = false; + int i; + again: /* set num_dacs once to full for alc_auto_look_for_dac() */ spec->multiout.num_dacs = cfg->line_outs; - spec->multiout.dac_nids = spec->private_dac_nids; + spec->multiout.hp_out_nid[0] = 0; + spec->multiout.extra_out_nid[0] = 0; memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); - memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); - memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); + spec->multiout.dac_nids = spec->private_dac_nids; spec->multi_ios = 0; - clear_vol_marks(codec); - badness = 0; /* fill hard-wired DACs first */ - if (fill_hardwired) { - bool mapped; - do { - mapped = alc_map_singles(codec, cfg->line_outs, - cfg->line_out_pins, - spec->private_dac_nids); - mapped |= alc_map_singles(codec, cfg->hp_outs, - cfg->hp_pins, - spec->multiout.hp_out_nid); - mapped |= alc_map_singles(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid); - if (fill_mio_first && cfg->line_outs == 1 && - cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0); - if (!err) - mapped = true; - } - } while (mapped); + if (!redone) { + for (i = 0; i < cfg->line_outs; i++) + spec->private_dac_nids[i] = + get_dac_if_single(codec, cfg->line_out_pins[i]); + if (cfg->hp_outs) + spec->multiout.hp_out_nid[0] = + get_dac_if_single(codec, cfg->hp_pins[0]); + if (cfg->speaker_outs) + spec->multiout.extra_out_nid[0] = + get_dac_if_single(codec, cfg->speaker_pins[0]); } - badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins, - spec->private_dac_nids, - &main_out_badness); + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t pin = cfg->line_out_pins[i]; + if (spec->private_dac_nids[i]) + continue; + spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin); + if (!spec->private_dac_nids[i] && !redone) { + /* if we can't find primary DACs, re-probe without + * checking the hard-wired DACs + */ + redone = true; + goto again; + } + } /* re-count num_dacs and squash invalid entries */ spec->multiout.num_dacs = 0; @@ -3287,144 +3061,30 @@ static int fill_and_eval_dacs(struct hda_codec *codec, } } - if (fill_mio_first && - cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { /* try to fill multi-io first */ - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - /* we don't count badness at this stage yet */ + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); + + num_pins = alc_auto_fill_multi_ios(codec, location, 0); + if (num_pins > 0) { + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; + } } - if (cfg->line_out_type != AUTO_PIN_HP_OUT) { - err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins, - spec->multiout.hp_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins, + spec->multiout.hp_out_nid); if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_dacs(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - badness += err; - } - if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - /* try multi-ios with HP + inputs */ - int offset = 0; - if (cfg->line_outs >= 3) - offset = 1; - err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, - offset); - if (err < 0) - return err; - badness += err; - } - - if (spec->multi_ios == 2) { - for (i = 0; i < 2; i++) - spec->private_dac_nids[spec->multiout.num_dacs++] = - spec->multi_io[i].dac; - spec->ext_channel_count = 2; - } else if (spec->multi_ios) { - spec->multi_ios = 0; - badness += BAD_MULTI_IO; - } - - return badness; -} - -#define DEBUG_BADNESS - -#ifdef DEBUG_BADNESS -#define debug_badness snd_printdd -#else -#define debug_badness(...) -#endif - -static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg) -{ - debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[2], - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3]); - if (spec->multi_ios > 0) - debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", - spec->multi_ios, - spec->multi_io[0].pin, spec->multi_io[1].pin, - spec->multi_io[0].dac, spec->multi_io[1].dac); - debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->hp_pins[0], cfg->hp_pins[1], - cfg->hp_pins[2], cfg->hp_pins[2], - spec->multiout.hp_out_nid[0], - spec->multiout.hp_out_nid[1], - spec->multiout.hp_out_nid[2], - spec->multiout.hp_out_nid[3]); - debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->speaker_pins[0], cfg->speaker_pins[1], - cfg->speaker_pins[2], cfg->speaker_pins[3], - spec->multiout.extra_out_nid[0], - spec->multiout.extra_out_nid[1], - spec->multiout.extra_out_nid[2], - spec->multiout.extra_out_nid[3]); -} - -static int alc_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg *best_cfg; - int best_badness = INT_MAX; - int badness; - bool fill_hardwired = true, fill_mio_first = true; - bool best_wired = true, best_mio = true; - bool hp_spk_swapped = false; - - best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); - if (!best_cfg) - return -ENOMEM; - *best_cfg = *cfg; - - for (;;) { - badness = fill_and_eval_dacs(codec, fill_hardwired, - fill_mio_first); - if (badness < 0) - return badness; - debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", - cfg->line_out_type, fill_hardwired, fill_mio_first, - badness); - debug_show_configs(spec, cfg); - if (badness < best_badness) { - best_badness = badness; - *best_cfg = *cfg; - best_wired = fill_hardwired; - best_mio = fill_mio_first; - } - if (!badness) - break; - fill_mio_first = !fill_mio_first; - if (!fill_mio_first) - continue; - fill_hardwired = !fill_hardwired; - if (!fill_hardwired) - continue; - if (hp_spk_swapped) - break; - hp_spk_swapped = true; - if (cfg->speaker_outs > 0 && + int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid); + /* if no speaker volume is assigned, try again as the primary + * output + */ + if (!err && cfg->speaker_outs > 0 && cfg->line_out_type == AUTO_PIN_HP_OUT) { cfg->hp_outs = cfg->line_outs; memcpy(cfg->hp_pins, cfg->line_out_pins, @@ -3435,45 +3095,45 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) cfg->speaker_outs = 0; memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - fill_hardwired = true; - continue; - } - if (cfg->hp_outs > 0 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - fill_hardwired = true; - continue; - } - break; + redone = false; + goto again; + } } - if (badness) { - *cfg = *best_cfg; - fill_and_eval_dacs(codec, best_wired, best_mio); + if (!spec->multi_ios && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && + cfg->hp_outs) { + /* try multi-ios with HP + inputs */ + defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]); + location = get_defcfg_location(defcfg); + + num_pins = alc_auto_fill_multi_ios(codec, location, 1); + if (num_pins > 0) { + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; + } } - debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", - cfg->line_out_type, best_wired, best_mio); - debug_show_configs(spec, cfg); if (cfg->line_out_pins[0]) spec->vmaster_nid = alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0], spec->multiout.dac_nids[0]); - - /* clear the bitmap flags for creating controls */ - clear_vol_marks(codec); - kfree(best_cfg); return 0; } +static inline unsigned int get_ctl_pos(unsigned int data) +{ + hda_nid_t nid = get_amp_nid_(data); + unsigned int dir = get_amp_direction_(data); + return (nid << 1) | dir; +} + +#define is_ctl_used(bits, data) \ + test_bit(get_ctl_pos(data), bits) +#define mark_ctl_usage(bits, data) \ + set_bit(get_ctl_pos(data), bits) + static int alc_auto_add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, hda_nid_t nid, unsigned int chs) @@ -3573,7 +3233,7 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, int i, err, noutputs; noutputs = cfg->line_outs; - if (spec->multi_ios > 0 && cfg->line_outs < 3) + if (spec->multi_ios > 0) noutputs += spec->multi_ios; for (i = 0; i < noutputs; i++) { @@ -3585,17 +3245,14 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, dac = spec->multiout.dac_nids[i]; if (!dac) continue; - if (i >= cfg->line_outs) { + if (i >= cfg->line_outs) pin = spec->multi_io[i - 1].pin; - index = 0; - name = channel_name[i]; - } else { + else pin = cfg->line_out_pins[i]; - name = alc_get_line_out_pfx(spec, i, true, &index); - } sw = alc_look_for_out_mute_nid(codec, pin, dac); vol = alc_look_for_out_vol_nid(codec, pin, dac); + name = alc_get_line_out_pfx(spec, i, true, &index); if (!name || !strcmp(name, "CLFE")) { /* Center/LFE */ err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); @@ -3692,31 +3349,41 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins, return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0); } - for (i = 0; i < num_pins; i++) { - hda_nid_t dac; - if (dacs[num_pins - 1]) - dac = dacs[i]; /* with individual volumes */ - else - dac = 0; - if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { - err = alc_auto_create_extra_out(codec, pins[i], dac, - "Bass Speaker", 0); - } else if (num_pins >= 3) { - snprintf(name, sizeof(name), "%s %s", - pfx, channel_name[i]); - err = alc_auto_create_extra_out(codec, pins[i], dac, - name, 0); - } else { - err = alc_auto_create_extra_out(codec, pins[i], dac, - pfx, i); + if (dacs[num_pins - 1]) { + /* OK, we have a multi-output system with individual volumes */ + for (i = 0; i < num_pins; i++) { + if (num_pins >= 3) { + snprintf(name, sizeof(name), "%s %s", + pfx, channel_name[i]); + err = alc_auto_create_extra_out(codec, pins[i], dacs[i], + name, 0); + } else { + err = alc_auto_create_extra_out(codec, pins[i], dacs[i], + pfx, i); + } + if (err < 0) + return err; } - if (err < 0) - return err; - } - if (dacs[num_pins - 1]) return 0; + } + + /* Let's create a bind-controls */ + ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw); + if (!ctl) + return -ENOMEM; + n = 0; + for (i = 0; i < num_pins; i++) { + if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP) + ctl->values[n++] = + HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT); + } + if (n) { + snprintf(name, sizeof(name), "%s Playback Switch", pfx); + err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl); + if (err < 0) + return err; + } - /* Let's create a bind-controls for volumes */ ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); if (!ctl) return -ENOMEM; @@ -3852,111 +3519,58 @@ static void alc_auto_init_extra_out(struct hda_codec *codec) } } -/* check whether the given pin can be a multi-io pin */ -static bool can_be_multiio_pin(struct hda_codec *codec, - unsigned int location, hda_nid_t nid) -{ - unsigned int defcfg, caps; - - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - return false; - if (location && get_defcfg_location(defcfg) != location) - return false; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) - return false; - return true; -} - /* * multi-io helper - * - * When hardwired is set, try to fill ony hardwired pins, and returns - * zero if any pins are filled, non-zero if nothing found. - * When hardwired is off, try to fill possible input pins, and returns - * the badness value. */ static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset) + unsigned int location, + int offset) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int type, i, j, dacs, num_pins, old_pins; - unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); - unsigned int location = get_defcfg_location(defcfg); - int badness = 0; - - old_pins = spec->multi_ios; - if (old_pins >= 2) - goto end_fill; - - num_pins = 0; - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type != type) - continue; - if (can_be_multiio_pin(codec, location, - cfg->inputs[i].pin)) - num_pins++; - } - } - if (num_pins < 2) - goto end_fill; + hda_nid_t prime_dac = spec->private_dac_nids[0]; + int type, i, dacs, num_pins = 0; dacs = spec->multiout.num_dacs; for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; hda_nid_t dac = 0; - + unsigned int defcfg, caps; if (cfg->inputs[i].type != type) continue; - if (!can_be_multiio_pin(codec, location, nid)) + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) continue; - for (j = 0; j < spec->multi_ios; j++) { - if (nid == spec->multi_io[j].pin) - break; - } - if (j < spec->multi_ios) + if (location && get_defcfg_location(defcfg) != location) continue; - - if (offset && offset + spec->multi_ios < dacs) { - dac = spec->private_dac_nids[offset + spec->multi_ios]; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + continue; + if (offset && offset + num_pins < dacs) { + dac = spec->private_dac_nids[offset + num_pins]; if (!alc_auto_is_dac_reachable(codec, nid, dac)) dac = 0; } - if (hardwired) - dac = get_dac_if_single(codec, nid); - else if (!dac) + if (!dac) dac = alc_auto_look_for_dac(codec, nid); - if (!dac) { - badness++; + if (!dac) continue; - } - spec->multi_io[spec->multi_ios].pin = nid; - spec->multi_io[spec->multi_ios].dac = dac; - spec->multi_ios++; - if (spec->multi_ios >= 2) - break; + spec->multi_io[num_pins].pin = nid; + spec->multi_io[num_pins].dac = dac; + num_pins++; + spec->private_dac_nids[spec->multiout.num_dacs++] = dac; } } - end_fill: - if (badness) - badness = BAD_MULTI_IO; - if (old_pins == spec->multi_ios) { - if (hardwired) - return 1; /* nothing found */ - else - return badness; /* no badness if nothing found */ - } - if (!hardwired && spec->multi_ios < 2) { - spec->multi_ios = old_pins; - return badness; + spec->multiout.num_dacs = dacs; + if (num_pins < 2) { + /* clear up again */ + memset(spec->private_dac_nids + dacs, 0, + sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs)); + spec->private_dac_nids[0] = prime_dac; + return 0; } - - return 0; + return num_pins; } static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, @@ -4154,7 +3768,7 @@ static void alc_auto_init_input_src(struct hda_codec *codec) else nums = spec->num_adc_nids; for (c = 0; c < nums; c++) - alc_mux_select(codec, c, spec->cur_mux[c], true); + alc_mux_select(codec, 0, spec->cur_mux[c], true); } /* add mic boosts if needed */ @@ -4290,6 +3904,7 @@ static void set_capture_mixer(struct hda_codec *codec) static void alc_auto_init_std(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->use_jack_tbl = 1; alc_auto_init_multi_out(codec); alc_auto_init_extra_out(codec); alc_auto_init_analog_input(codec); @@ -4311,7 +3926,6 @@ static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), - SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; @@ -4411,9 +4025,6 @@ static int alc_parse_auto_config(struct hda_codec *codec, if (spec->kctls.list) add_mixer(spec, spec->kctls.list); - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); - return 1; } @@ -4424,47 +4035,26 @@ static int alc880_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + /* * ALC880 fix-ups */ enum { - ALC880_FIXUP_GPIO1, ALC880_FIXUP_GPIO2, ALC880_FIXUP_MEDION_RIM, - ALC880_FIXUP_LG, - ALC880_FIXUP_W810, - ALC880_FIXUP_EAPD_COEF, - ALC880_FIXUP_TCL_S700, - ALC880_FIXUP_VOL_KNOB, - ALC880_FIXUP_FUJITSU, - ALC880_FIXUP_F1734, - ALC880_FIXUP_UNIWILL, - ALC880_FIXUP_UNIWILL_DIG, - ALC880_FIXUP_Z71V, - ALC880_FIXUP_3ST_BASE, - ALC880_FIXUP_3ST, - ALC880_FIXUP_3ST_DIG, - ALC880_FIXUP_5ST_BASE, - ALC880_FIXUP_5ST, - ALC880_FIXUP_5ST_DIG, - ALC880_FIXUP_6ST_BASE, - ALC880_FIXUP_6ST, - ALC880_FIXUP_6ST_DIG, }; -/* enable the volume-knob widget support on NID 0x21 */ -static void alc880_fixup_vol_knob(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - if (action == ALC_FIXUP_ACT_PROBE) - snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT); -} - static const struct alc_fixup alc880_fixups[] = { - [ALC880_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, - }, [ALC880_FIXUP_GPIO2] = { .type = ALC_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, @@ -4479,323 +4069,40 @@ static const struct alc_fixup alc880_fixups[] = { .chained = true, .chain_id = ALC880_FIXUP_GPIO2, }, - [ALC880_FIXUP_LG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - /* disable bogus unused pins */ - { 0x16, 0x411111f0 }, - { 0x18, 0x411111f0 }, - { 0x1a, 0x411111f0 }, - { } - } - }, - [ALC880_FIXUP_W810] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - /* disable bogus unused pins */ - { 0x17, 0x411111f0 }, - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO2, - }, - [ALC880_FIXUP_EAPD_COEF] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, - {} - }, - }, - [ALC880_FIXUP_TCL_S700] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* change to EAPD mode */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, - {} - }, - .chained = true, - .chain_id = ALC880_FIXUP_GPIO2, - }, - [ALC880_FIXUP_VOL_KNOB] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc880_fixup_vol_knob, - }, - [ALC880_FIXUP_FUJITSU] = { - /* override all pins as BIOS on old Amilo is broken */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x0121411f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x99030130 }, /* bass speaker */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x411111f0 }, /* N/A */ - { 0x19, 0x01a19950 }, /* mic-in */ - { 0x1a, 0x411111f0 }, /* N/A */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x01454140 }, /* SPDIF out */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_VOL_KNOB, - }, - [ALC880_FIXUP_F1734] = { - /* almost compatible with FUJITSU, but no bass and SPDIF */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x0121411f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x411111f0 }, /* N/A */ - { 0x19, 0x01a19950 }, /* mic-in */ - { 0x1a, 0x411111f0 }, /* N/A */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_VOL_KNOB, - }, - [ALC880_FIXUP_UNIWILL] = { - /* need to fix HP and speaker pins to be parsed correctly */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x0121411f }, /* HP */ - { 0x15, 0x99030120 }, /* speaker */ - { 0x16, 0x99030130 }, /* bass speaker */ - { } - }, - }, - [ALC880_FIXUP_UNIWILL_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - /* disable bogus unused pins */ - { 0x17, 0x411111f0 }, - { 0x19, 0x411111f0 }, - { 0x1b, 0x411111f0 }, - { 0x1f, 0x411111f0 }, - { } - } - }, - [ALC880_FIXUP_Z71V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - /* set up the whole pins as BIOS is utterly broken */ - { 0x14, 0x99030120 }, /* speaker */ - { 0x15, 0x0121411f }, /* HP */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x01a19950 }, /* mic-in */ - { 0x19, 0x411111f0 }, /* N/A */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x411111f0 }, /* N/A */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - } - }, - [ALC880_FIXUP_3ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x01014010 }, /* line-out */ - { 0x15, 0x411111f0 }, /* N/A */ - { 0x16, 0x411111f0 }, /* N/A */ - { 0x17, 0x411111f0 }, /* N/A */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x0121411f }, /* HP */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x02a19c40 }, /* front-mic */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_3ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_3ST_BASE, - }, - [ALC880_FIXUP_3ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_3ST_BASE, - }, - [ALC880_FIXUP_5ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x01014010 }, /* front */ - { 0x15, 0x411111f0 }, /* N/A */ - { 0x16, 0x01011411 }, /* CLFE */ - { 0x17, 0x01016412 }, /* surr */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x0121411f }, /* HP */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x02a19c40 }, /* front-mic */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_5ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_5ST_BASE, - }, - [ALC880_FIXUP_5ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_5ST_BASE, - }, - [ALC880_FIXUP_6ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x01014010 }, /* front */ - { 0x15, 0x01016412 }, /* surr */ - { 0x16, 0x01011411 }, /* CLFE */ - { 0x17, 0x01012414 }, /* side */ - { 0x18, 0x01a19c30 }, /* mic-in */ - { 0x19, 0x02a19c40 }, /* front-mic */ - { 0x1a, 0x01813031 }, /* line-in */ - { 0x1b, 0x0121411f }, /* HP */ - { 0x1c, 0x411111f0 }, /* N/A */ - { 0x1d, 0x411111f0 }, /* N/A */ - /* 0x1e is filled in below */ - { 0x1f, 0x411111f0 }, /* N/A */ - { } - } - }, - [ALC880_FIXUP_6ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x411111f0 }, /* N/A */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_6ST_BASE, - }, - [ALC880_FIXUP_6ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1e, 0x0144111e }, /* SPDIF */ - { } - }, - .chained = true, - .chain_id = ALC880_FIXUP_6ST_BASE, - }, }; static const struct snd_pci_quirk alc880_fixup_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), - SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), - SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), - SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), - SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), - SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734), - SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL), - SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), - SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), - SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), - SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), - SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), - SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), - - /* Below is the copied entries from alc880_quirks.c. - * It's not quite sure whether BIOS sets the correct pin-config table - * on these machines, thus they are kept to be compatible with - * the old static quirks. Once when it's confirmed to work without - * these overrides, it'd be better to remove. - */ - SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST), - SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST), - SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */ - SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG), - SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG), - /* default Intel */ - SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST), - SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG), - SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG), {} }; -static const struct alc_model_fixup alc880_fixup_models[] = { - {.id = ALC880_FIXUP_3ST, .name = "3stack"}, - {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, - {.id = ALC880_FIXUP_5ST, .name = "5stack"}, - {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, - {.id = ALC880_FIXUP_6ST, .name = "6stack"}, - {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, - {} -}; +/* + * board setups + */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#define alc_board_config \ + snd_hda_check_board_config +#define alc_board_codec_sid_config \ + snd_hda_check_board_codec_sid_config +#include "alc_quirks.c" +#else +#define alc_board_config(codec, nums, models, tbl) -1 +#define alc_board_codec_sid_config(codec, nums, models, tbl) -1 +#define setup_preset(codec, x) /* NOP */ +#endif /* * OK, here we have finally the patch for ALC880 */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc880_quirks.c" +#endif + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -4807,14 +4114,47 @@ static int patch_alc880(struct hda_codec *codec) spec->mixer_nid = 0x0b; spec->need_dac_fix = 1; - alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, - alc880_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC880_MODEL_LAST, + alc880_models, alc880_cfg_tbl); + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } - /* automatic parse from the BIOS config */ - err = alc880_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) + goto error; +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using 3-stack mode...\n"); + board_config = ALC880_3ST; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) { + spec->vmaster_nid = 0x0c; + setup_preset(codec, &alc880_presets[board_config]); + } + + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -4823,10 +4163,16 @@ static int patch_alc880(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } - codec->patch_ops = alc_patch_ops; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif + return 0; error: @@ -4845,115 +4191,49 @@ static int alc260_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + /* * Pin config fixes */ enum { - ALC260_FIXUP_HP_DC5750, - ALC260_FIXUP_HP_PIN_0F, - ALC260_FIXUP_COEF, - ALC260_FIXUP_GPIO1, - ALC260_FIXUP_GPIO1_TOGGLE, - ALC260_FIXUP_REPLACER, - ALC260_FIXUP_HP_B1900, + PINFIX_HP_DC5750, }; -static void alc260_gpio1_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->hp_jack_present); -} - -static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PROBE) { - /* although the machine has only one output pin, we need to - * toggle GPIO1 according to the jack state - */ - spec->automute_hook = alc260_gpio1_automute; - spec->detect_hp = 1; - spec->automute_speaker = 1; - spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ - snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); - spec->unsol_event = alc_sku_unsol_event; - add_verb(codec->spec, alc_gpio1_init_verbs); - } -} - static const struct alc_fixup alc260_fixups[] = { - [ALC260_FIXUP_HP_DC5750] = { + [PINFIX_HP_DC5750] = { .type = ALC_FIXUP_PINS, .v.pins = (const struct alc_pincfg[]) { { 0x11, 0x90130110 }, /* speaker */ { } } }, - [ALC260_FIXUP_HP_PIN_0F] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x0f, 0x01214000 }, /* HP */ - { } - } - }, - [ALC260_FIXUP_COEF] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 }, - { } - }, - .chained = true, - .chain_id = ALC260_FIXUP_HP_PIN_0F, - }, - [ALC260_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, - }, - [ALC260_FIXUP_GPIO1_TOGGLE] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc260_fixup_gpio1_toggle, - .chained = true, - .chain_id = ALC260_FIXUP_HP_PIN_0F, - }, - [ALC260_FIXUP_REPLACER] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, - { } - }, - .chained = true, - .chain_id = ALC260_FIXUP_GPIO1_TOGGLE, - }, - [ALC260_FIXUP_HP_B1900] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc260_fixup_gpio1_toggle, - .chained = true, - .chain_id = ALC260_FIXUP_COEF, - } }; static const struct snd_pci_quirk alc260_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), - SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), - SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), - SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750), - SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900), - SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1), - SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER), - SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF), + SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750), {} }; /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc260_quirks.c" +#endif + static int patch_alc260(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int err, board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4963,13 +4243,47 @@ static int patch_alc260(struct hda_codec *codec) spec->mixer_nid = 0x07; - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC260_MODEL_LAST, + alc260_models, alc260_cfg_tbl); + if (board_config < 0) { + snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } - /* automatic parse from the BIOS config */ - err = alc260_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } + + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc260_parse_auto_config(codec); + if (err < 0) + goto error; +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS + else if (!err) { + printk(KERN_INFO + "hda_codec: Cannot set up configuration " + "from BIOS. Using base mode...\n"); + board_config = ALC260_BASIC; + } +#endif + } + + if (board_config != ALC_MODEL_AUTO) { + setup_preset(codec, &alc260_presets[board_config]); + spec->vmaster_nid = 0x08; + } + + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -4978,10 +4292,16 @@ static int patch_alc260(struct hda_codec *codec) set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; - - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif return 0; @@ -5002,6 +4322,9 @@ static int patch_alc260(struct hda_codec *codec) * In addition, an independent DAC for the multi-playback (not used in this * driver yet). */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif /* * Pin config fixes @@ -5012,14 +4335,11 @@ enum { ALC882_FIXUP_PB_M5210, ALC882_FIXUP_ACER_ASPIRE_7736, ALC882_FIXUP_ASUS_W90V, - ALC889_FIXUP_CD, ALC889_FIXUP_VAIO_TT, ALC888_FIXUP_EEE1601, ALC882_FIXUP_EAPD, ALC883_FIXUP_EAPD, ALC883_FIXUP_ACER_EAPD, - ALC882_FIXUP_GPIO1, - ALC882_FIXUP_GPIO2, ALC882_FIXUP_GPIO3, ALC889_FIXUP_COEF, ALC882_FIXUP_ASUS_W2JC, @@ -5027,9 +4347,6 @@ enum { ALC882_FIXUP_ACER_ASPIRE_8930G, ALC882_FIXUP_ASPIRE_8930G_VERBS, ALC885_FIXUP_MACPRO_GPIO, - ALC889_FIXUP_DAC_ROUTE, - ALC889_FIXUP_MBP_VREF, - ALC889_FIXUP_IMAC91_VREF, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -5083,76 +4400,6 @@ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, alc882_gpio_mute(codec, 1, 0); } -/* Fix the connection of some pins for ALC889: - * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't - * work correctly (bko#42740) - */ -static void alc889_fixup_dac_route(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - if (action == ALC_FIXUP_ACT_PRE_PROBE) { - /* fake the connections during parsing the tree */ - hda_nid_t conn1[2] = { 0x0c, 0x0d }; - hda_nid_t conn2[2] = { 0x0e, 0x0f }; - snd_hda_override_conn_list(codec, 0x14, 2, conn1); - snd_hda_override_conn_list(codec, 0x15, 2, conn1); - snd_hda_override_conn_list(codec, 0x18, 2, conn2); - snd_hda_override_conn_list(codec, 0x1a, 2, conn2); - } else if (action == ALC_FIXUP_ACT_PROBE) { - /* restore the connections */ - hda_nid_t conn[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 }; - snd_hda_override_conn_list(codec, 0x14, 5, conn); - snd_hda_override_conn_list(codec, 0x15, 5, conn); - snd_hda_override_conn_list(codec, 0x18, 5, conn); - snd_hda_override_conn_list(codec, 0x1a, 5, conn); - } -} - -/* Set VREF on HP pin */ -static void alc889_fixup_mbp_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - static hda_nid_t nids[2] = { 0x14, 0x15 }; - int i; - - if (action != ALC_FIXUP_ACT_INIT) - return; - for (i = 0; i < ARRAY_SIZE(nids); i++) { - unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); - if (get_defcfg_device(val) != AC_JACK_HP_OUT) - continue; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - val |= AC_PINCTL_VREF_80; - snd_hda_codec_write(codec, nids[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, val); - spec->keep_vref_in_automute = 1; - break; - } -} - -/* Set VREF on speaker pins on imac91 */ -static void alc889_fixup_imac91_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - static hda_nid_t nids[2] = { 0x18, 0x1a }; - int i; - - if (action != ALC_FIXUP_ACT_INIT) - return; - for (i = 0; i < ARRAY_SIZE(nids); i++) { - unsigned int val; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - val |= AC_PINCTL_VREF_50; - snd_hda_codec_write(codec, nids[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, val); - } - spec->keep_vref_in_automute = 1; -} - static const struct alc_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = ALC_FIXUP_PINS, @@ -5189,13 +4436,6 @@ static const struct alc_fixup alc882_fixups[] = { { } } }, - [ALC889_FIXUP_CD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x1c, 0x993301f0 }, /* CD */ - { } - } - }, [ALC889_FIXUP_VAIO_TT] = { .type = ALC_FIXUP_PINS, .v.pins = (const struct alc_pincfg[]) { @@ -5238,14 +4478,6 @@ static const struct alc_fixup alc882_fixups[] = { { } } }, - [ALC882_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = alc_gpio1_init_verbs, - }, - [ALC882_FIXUP_GPIO2] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = alc_gpio2_init_verbs, - }, [ALC882_FIXUP_GPIO3] = { .type = ALC_FIXUP_VERBS, .v.verbs = alc_gpio3_init_verbs, @@ -5315,22 +4547,6 @@ static const struct alc_fixup alc882_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc885_fixup_macpro_gpio, }, - [ALC889_FIXUP_DAC_ROUTE] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc889_fixup_dac_route, - }, - [ALC889_FIXUP_MBP_VREF] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc889_fixup_mbp_vref, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, - [ALC889_FIXUP_IMAC91_VREF] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc889_fixup_imac91_vref, - .chained = true, - .chain_id = ALC882_FIXUP_GPIO1, - }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -5355,7 +4571,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), - SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736), SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), @@ -5364,30 +4579,14 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), /* All Apple entries are in codec SSIDs */ - SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), - SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), @@ -5409,10 +4608,14 @@ static int alc882_parse_auto_config(struct hda_codec *codec) /* */ +#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS +#include "alc882_quirks.c" +#endif + static int patch_alc882(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int err, board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5436,15 +4639,45 @@ static int patch_alc882(struct hda_codec *codec) if (err < 0) goto error; - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + board_config = alc_board_config(codec, ALC882_MODEL_LAST, + alc882_models, NULL); + if (board_config < 0) + board_config = alc_board_codec_sid_config(codec, + ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + + if (board_config < 0) { + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); + board_config = ALC_MODEL_AUTO; + } + + if (board_config == ALC_MODEL_AUTO) { + alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + } alc_auto_parse_customize_define(codec); - /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); - if (err < 0) - goto error; + if (board_config == ALC_MODEL_AUTO) { + /* automatic parse from the BIOS config */ + err = alc882_parse_auto_config(codec); + if (err < 0) + goto error; + } + + if (board_config != ALC_MODEL_AUTO) { + setup_preset(codec, &alc882_presets[board_config]); + spec->vmaster_nid = 0x0c; + } + + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); @@ -5453,9 +4686,16 @@ static int patch_alc882(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + if (board_config == ALC_MODEL_AUTO) + spec->init_hook = alc_auto_init_std; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif return 0; @@ -5482,6 +4722,7 @@ enum { ALC262_FIXUP_FSC_H270, ALC262_FIXUP_HP_Z200, ALC262_FIXUP_TYAN, + ALC262_FIXUP_TOSHIBA_RX1, ALC262_FIXUP_LENOVO_3000, ALC262_FIXUP_BENQ, ALC262_FIXUP_BENQ_T31, @@ -5511,6 +4752,16 @@ static const struct alc_fixup alc262_fixups[] = { { } } }, + [ALC262_FIXUP_TOSHIBA_RX1] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x90170110 }, /* speaker */ + { 0x15, 0x0421101f }, /* HP */ + { 0x1a, 0x40f000f0 }, /* N/A */ + { 0x1b, 0x40f000f0 }, /* N/A */ + { 0x1e, 0x40f000f0 }, /* N/A */ + } + }, [ALC262_FIXUP_LENOVO_3000] = { .type = ALC_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -5543,6 +4794,8 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), + SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", + ALC262_FIXUP_TOSHIBA_RX1), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), @@ -5551,6 +4804,10 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + /* */ static int patch_alc262(struct hda_codec *codec) @@ -5590,6 +4847,15 @@ static int patch_alc262(struct hda_codec *codec) if (err < 0) goto error; + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -5597,10 +4863,16 @@ static int patch_alc262(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif return 0; @@ -5694,7 +4966,17 @@ static int patch_alc268(struct hda_codec *codec) (0 << AC_AMPCAP_MUTE_SHIFT)); } + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; return 0; @@ -5707,6 +4989,10 @@ static int patch_alc268(struct hda_codec *codec) /* * ALC269 */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc269_loopbacks alc880_loopbacks +#endif + static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -5728,6 +5014,35 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = { /* NID is set in alc_build_pcms */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_mic2_for_mute_led(struct hda_codec *codec) +{ + switch (codec->subsystem_id) { + case 0x103c1586: + return 1; + } + return 0; +} + +static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) +{ + /* update mute-LED according to the speaker mute state */ + if (nid == 0x01 || nid == 0x14) { + int pinval; + if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + pinval = 0x24; + else + pinval = 0x20; + /* mic2 vref pin is used for mute LED control */ + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); + } + return alc_check_power_status(codec, nid); +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + /* different alc269-variants */ enum { ALC269_TYPE_ALC269VA, @@ -5878,31 +5193,6 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec, spec->automute_hook = alc269_quanta_automute; } -/* update mute-LED according to the speaker mute state via mic2 VREF pin */ -static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled) -{ - struct hda_codec *codec = private_data; - unsigned int pinval = enabled ? 0x20 : 0x24; - snd_hda_codec_update_cache(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinval); -} - -static void alc269_fixup_mic2_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - switch (action) { - case ALC_FIXUP_ACT_BUILD: - spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook; - snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); - /* fallthru */ - case ALC_FIXUP_ACT_INIT: - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - break; - } -} - enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -5920,7 +5210,6 @@ enum { ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, ALC269VB_FIXUP_DMIC, - ALC269_FIXUP_MIC2_MUTE_LED, }; static const struct alc_fixup alc269_fixups[] = { @@ -6041,14 +5330,9 @@ static const struct alc_fixup alc269_fixups[] = { { } }, }, - [ALC269_FIXUP_MIC2_MUTE_LED] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_mic2_mute, - }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), @@ -6071,7 +5355,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), -#if 0 +#if 1 /* Below is a quirk table taken from the old code. * Basically the device should work as is without the fixup table. * If BIOS doesn't give a proper info, enable the corresponding @@ -6080,6 +5364,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC), + SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC), @@ -6129,14 +5414,10 @@ static const struct alc_model_fixup alc269_fixup_models[] = { }; -static void alc269_fill_coef(struct hda_codec *codec) +static int alc269_fill_coef(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; int val; - if (spec->codec_variant != ALC269_TYPE_ALC269VB) - return; - if ((alc_get_coef0(codec) & 0x00ff) < 0x015) { alc_write_coef_idx(codec, 0xf, 0x960b); alc_write_coef_idx(codec, 0xe, 0x8817); @@ -6171,6 +5452,8 @@ static void alc269_fill_coef(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x4); /* HP */ alc_write_coef_idx(codec, 0x4, val | (1<<11)); + + return 0; } /* @@ -6214,7 +5497,6 @@ static int patch_alc269(struct hda_codec *codec) } if (err < 0) goto error; - spec->init_hook = alc269_fill_coef; alc269_fill_coef(codec); } @@ -6227,6 +5509,15 @@ static int patch_alc269(struct hda_codec *codec) if (err < 0) goto error; + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -6234,13 +5525,21 @@ static int patch_alc269(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; #ifdef CONFIG_PM codec->patch_ops.resume = alc269_resume; #endif + spec->init_hook = alc_auto_init_std; spec->shutup = alc269_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc269_loopbacks; + if (alc269_mic2_for_mute_led(codec)) + codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; +#endif return 0; @@ -6260,43 +5559,24 @@ static int alc861_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids); } -/* Pin config fixes */ -enum { - ALC861_FIXUP_FSC_AMILO_PI1505, - ALC861_FIXUP_AMP_VREF_0F, - ALC861_FIXUP_NO_JACK_DETECT, - ALC861_FIXUP_ASUS_A6RP, +#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, + { } /* end */ }; +#endif -/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ -static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - if (action != ALC_FIXUP_ACT_INIT) - return; - val = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) - val |= AC_PINCTL_IN_EN; - val |= AC_PINCTL_VREF_50; - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, val); - spec->keep_vref_in_automute = 1; -} - -/* suppress the jack-detection */ -static void alc_fixup_no_jack_detect(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - if (action == ALC_FIXUP_ACT_PRE_PROBE) - codec->no_jack_detect = 1; -} +/* Pin config fixes */ +enum { + PINFIX_FSC_AMILO_PI1505, +}; static const struct alc_fixup alc861_fixups[] = { - [ALC861_FIXUP_FSC_AMILO_PI1505] = { + [PINFIX_FSC_AMILO_PI1505] = { .type = ALC_FIXUP_PINS, .v.pins = (const struct alc_pincfg[]) { { 0x0b, 0x0221101f }, /* HP */ @@ -6304,29 +5584,10 @@ static const struct alc_fixup alc861_fixups[] = { { } } }, - [ALC861_FIXUP_AMP_VREF_0F] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc861_fixup_asus_amp_vref_0f, - }, - [ALC861_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc_fixup_no_jack_detect, - }, - [ALC861_FIXUP_ASUS_A6RP] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc861_fixup_asus_amp_vref_0f, - .chained = true, - .chain_id = ALC861_FIXUP_NO_JACK_DETECT, - } }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), - SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), - SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; @@ -6353,6 +5614,15 @@ static int patch_alc861(struct hda_codec *codec) if (err < 0) goto error; + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) @@ -6360,13 +5630,16 @@ static int patch_alc861(struct hda_codec *codec) set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->power_hook = alc_power_eapd; + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861_loopbacks; #endif - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - return 0; error: @@ -6381,6 +5654,10 @@ static int patch_alc861(struct hda_codec *codec) * * In addition, an independent DAC */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks +#endif + static int alc861vd_parse_auto_config(struct hda_codec *codec) { static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 }; @@ -6461,6 +5738,15 @@ static int patch_alc861vd(struct hda_codec *codec) add_verb(spec, alc660vd_eapd_verbs); } + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + if (!spec->no_analog) { err = snd_hda_attach_beep_device(codec, 0x23); if (err < 0) @@ -6468,11 +5754,16 @@ static int patch_alc861vd(struct hda_codec *codec) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; - - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861vd_loopbacks; +#endif return 0; @@ -6492,6 +5783,9 @@ static int patch_alc861vd(struct hda_codec *codec) * In addition, an independent DAC for the multi-playback (not used in this * driver yet). */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif /* * BIOS auto configuration @@ -6541,7 +5835,6 @@ enum { ALC662_FIXUP_ASUS_MODE6, ALC662_FIXUP_ASUS_MODE7, ALC662_FIXUP_ASUS_MODE8, - ALC662_FIXUP_NO_JACK_DETECT, }; static const struct alc_fixup alc662_fixups[] = { @@ -6687,10 +5980,6 @@ static const struct alc_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC662_FIXUP_SKU_IGNORE }, - [ALC662_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc_fixup_no_jack_detect, - }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6699,7 +5988,6 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), - SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), @@ -6821,6 +6109,15 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) goto error; + if (!spec->no_analog && !spec->adc_nids) { + alc_auto_fill_adc_caps(codec); + alc_rebuild_imux_for_auto_mic(codec); + alc_remove_invalid_adc_nids(codec); + } + + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + if (!spec->no_analog && has_cdefine_beep(codec)) { err = snd_hda_attach_beep_device(codec, 0x1); if (err < 0) @@ -6840,10 +6137,16 @@ static int patch_alc662(struct hda_codec *codec) } } + alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc662_loopbacks; +#endif return 0; @@ -6883,7 +6186,11 @@ static int patch_alc680(struct hda_codec *codec) return err; } + if (!spec->no_analog && !spec->cap_mixer) + set_capture_mixer(codec); + codec->patch_ops = alc_patch_ops; + spec->init_hook = alc_auto_init_std; return 0; } diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 33a9946b492c..3556408d6ece 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -99,7 +99,6 @@ enum { STAC_DELL_VOSTRO_3500, STAC_92HD83XXX_HP_cNB11_INTQUAD, STAC_HP_DV7_4000, - STAC_HP_ZEPHYR, STAC_92HD83XXX_MODELS }; @@ -310,8 +309,6 @@ struct sigmatel_spec { unsigned long auto_capvols[MAX_ADCS_NUM]; unsigned auto_dmic_cnt; hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; - - struct hda_vmaster_mute_hook vmaster_mute; }; static const hda_nid_t stac9200_adc_nids[1] = { @@ -665,6 +662,7 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE static int stac_vrefout_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) { @@ -688,6 +686,7 @@ static int stac_vrefout_set(struct hda_codec *codec, return 1; } +#endif static unsigned int stac92xx_vref_set(struct hda_codec *codec, hda_nid_t nid, unsigned int new_vref) @@ -895,13 +894,6 @@ static const struct hda_verb stac92hd83xxx_core_init[] = { {} }; -static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = { - { 0x22, 0x785, 0x43 }, - { 0x22, 0x782, 0xe0 }, - { 0x22, 0x795, 0x00 }, - {} -}; - static const struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, @@ -1007,8 +999,8 @@ static const struct hda_verb stac9205_core_init[] = { } static const struct snd_kcontrol_new stac9200_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), { } /* end */ @@ -1035,8 +1027,8 @@ static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { }; static const struct snd_kcontrol_new stac925x_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), { } /* end */ }; @@ -1068,25 +1060,34 @@ static struct snd_kcontrol_new stac_smux_mixer = { .put = stac92xx_smux_enum_put, }; -static const char * const slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", +static const char * const slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Speaker Playback Volume", NULL }; -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled); - -static void stac92xx_vmaster_hook(void *private_data, int val) -{ - stac92xx_update_led_status(private_data, val); -} +static const char * const slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Speaker Playback Switch", + "IEC958 Playback Switch", + NULL +}; static void stac92xx_free_kctls(struct hda_codec *codec); static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - unsigned int vmaster_tlv[4]; int err; int i; @@ -1143,28 +1144,22 @@ static int stac92xx_build_controls(struct hda_codec *codec) } /* if we have no master control, let's create it */ - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - /* correct volume offset */ - vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; - /* minimum value is actually mute */ - vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch", true, - &spec->vmaster_mute.sw_kctl); - if (err < 0) - return err; - - if (spec->gpio_led) { - spec->vmaster_mute.hook = stac92xx_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); + if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + unsigned int vmaster_tlv[4]; + snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], + HDA_OUTPUT, vmaster_tlv); + /* correct volume offset */ + vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; + /* minimum value is actually mute */ + vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + vmaster_tlv, slave_vols); + if (err < 0) + return err; + } + if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_sws); if (err < 0) return err; } @@ -1613,7 +1608,7 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, - "Alienware M17x R3", STAC_DELL_EQ), + "Alienware M17x", STAC_ALIENWARE_M17X), {} /* terminator */ }; @@ -1641,12 +1636,6 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x40f000f0, 0x40f000f0, }; -static const unsigned int hp_zephyr_pin_configs[10] = { - 0x01813050, 0x0421201f, 0x04a1205e, 0x96130310, - 0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130, - 0, 0, -}; - static const unsigned int hp_cNB11_intquad_pin_configs[10] = { 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, @@ -1660,7 +1649,6 @@ static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs, [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, - [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs, }; static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { @@ -1671,7 +1659,6 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500", [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", [STAC_HP_DV7_4000] = "hp-dv7-4000", - [STAC_HP_ZEPHYR] = "hp-zephyr", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1724,14 +1711,6 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, - "HP", STAC_HP_ZEPHYR), - {} /* terminator */ -}; - -static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = { - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, - "HP", STAC_HP_ZEPHYR), {} /* terminator */ }; @@ -4184,15 +4163,13 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, return 1; } -static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) { int i; for (i = 0; i < cfg->hp_outs; i++) if (cfg->hp_pins[i] == nid) return 1; /* nid is a HP-Out */ - for (i = 0; i < cfg->line_outs; i++) - if (cfg->line_out_pins[i] == nid) - return 1; /* nid is a line-Out */ + return 0; /* nid is not a HP-Out */ }; @@ -4398,7 +4375,7 @@ static int stac92xx_init(struct hda_codec *codec) continue; } - if (is_nid_out_jack_pin(cfg, nid)) + if (is_nid_hp_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, @@ -4431,7 +4408,8 @@ static int stac92xx_init(struct hda_codec *codec) snd_hda_jack_report_sync(codec); /* sync mute LED */ - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + if (spec->gpio_led) + hda_call_check_power_status(codec, 0x01); if (spec->dac_list) stac92xx_power_down(codec); return 0; @@ -4649,7 +4627,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec) unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; if (no_hp_sensing(spec, i)) continue; - if (1 /*presence*/) + if (presence) stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); #if 0 /* FIXME */ /* Resetting the pinctl like below may lead to (a sort of) regressions @@ -4890,14 +4868,7 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) /* BIOS bug: unfilled OEM string */ if (strstr(dev->name, "HP_Mute_LED_P_G")) { set_hp_led_gpio(codec); - switch (codec->subsystem_id) { - case 0x103c148a: - spec->gpio_led_polarity = 0; - break; - default: - spec->gpio_led_polarity = 1; - break; - } + spec->gpio_led_polarity = 1; return 1; } } @@ -5009,6 +4980,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE static int stac92xx_pre_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -5043,41 +5015,83 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, afg_power_state); snd_hda_codec_set_power_to_all(codec, fg, power_state, true); } -#else -#define stac92xx_suspend NULL -#define stac92xx_resume NULL -#define stac92xx_pre_resume NULL -#define stac92xx_set_power_state NULL -#endif /* CONFIG_PM */ -/* update mute-LED accoring to the master switch */ -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled) +/* + * For this feature CONFIG_SND_HDA_POWER_SAVE is needed + * as mute LED state is updated in check_power_status hook + */ +static int stac92xx_update_led_status(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int muted = !enabled; + int i, num_ext_dacs, muted = 1; + unsigned int muted_lvl, notmtd_lvl; + hda_nid_t nid; if (!spec->gpio_led) - return; - - /* LED state is inverted on these systems */ - if (spec->gpio_led_polarity) - muted = !muted; + return 0; + for (i = 0; i < spec->multiout.num_dacs; i++) { + nid = spec->multiout.dac_nids[i]; + if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE)) { + muted = 0; /* something heard */ + break; + } + } + if (muted && spec->multiout.hp_nid) + if (!(snd_hda_codec_amp_read(codec, + spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE)) { + muted = 0; /* HP is not muted */ + } + num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid); + for (i = 0; muted && i < num_ext_dacs; i++) { + nid = spec->multiout.extra_out_nid[i]; + if (nid == 0) + break; + if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE)) { + muted = 0; /* extra output is not muted */ + } + } /*polarity defines *not* muted state level*/ if (!spec->vref_mute_led_nid) { if (muted) spec->gpio_data &= ~spec->gpio_led; /* orange */ else spec->gpio_data |= spec->gpio_led; /* white */ + + if (!spec->gpio_led_polarity) { + /* LED state is inverted on these systems */ + spec->gpio_data ^= spec->gpio_led; + } stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); } else { - spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; + notmtd_lvl = spec->gpio_led_polarity ? + AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_GRD; + muted_lvl = spec->gpio_led_polarity ? + AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ; + spec->vref_led = muted ? muted_lvl : notmtd_lvl; stac_vrefout_set(codec, spec->vref_mute_led_nid, spec->vref_led); } + return 0; } +/* + * use power check for controlling mute led of HP notebooks + */ +static int stac92xx_check_power_status(struct hda_codec *codec, + hda_nid_t nid) +{ + stac92xx_update_led_status(codec); + + return 0; +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#endif /* CONFIG_PM */ + static const struct hda_codec_ops stac92xx_patch_ops = { .build_controls = stac92xx_build_controls, .build_pcms = stac92xx_build_pcms, @@ -5557,12 +5571,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) STAC_92HD83XXX_MODELS, stac92hd83xxx_models, stac92hd83xxx_cfg_tbl); - /* check codec subsystem id if not found */ - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - STAC_92HD83XXX_MODELS, stac92hd83xxx_models, - stac92hd83xxx_codec_id_cfg_tbl); again: if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", @@ -5573,17 +5581,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; - switch (spec->board_config) { - case STAC_HP_ZEPHYR: - spec->init = stac92hd83xxx_hp_zephyr_init; - break; - } - if (find_mute_led_cfg(codec, -1/*no default cfg*/)) snd_printd("mute LED gpio %d polarity %d\n", spec->gpio_led, spec->gpio_led_polarity); +#ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { if (!spec->vref_mute_led_nid) { spec->gpio_mask |= spec->gpio_led; @@ -5593,10 +5596,11 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->patch_ops.set_power_state = stac92xx_set_power_state; } -#ifdef CONFIG_PM codec->patch_ops.pre_resume = stac92xx_pre_resume; -#endif + codec->patch_ops.check_power_status = + stac92xx_check_power_status; } +#endif err = stac92xx_parse_auto_config(codec); if (!err) { @@ -5893,6 +5897,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->gpio_led, spec->gpio_led_polarity); +#ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { if (!spec->vref_mute_led_nid) { spec->gpio_mask |= spec->gpio_led; @@ -5902,10 +5907,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) codec->patch_ops.set_power_state = stac92xx_set_power_state; } -#ifdef CONFIG_PM codec->patch_ops.pre_resume = stac92xx_pre_resume; -#endif + codec->patch_ops.check_power_status = + stac92xx_check_power_status; } +#endif spec->multiout.dac_nids = spec->dac_nids; diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index 06214fdc9486..03e63fed9caf 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -199,9 +199,6 @@ struct via_spec { unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; - /* analog low-power control */ - bool alc_mode; - /* smart51 setup */ unsigned int smart51_nums; hda_nid_t smart51_pins[2]; @@ -550,10 +547,7 @@ static void via_auto_init_output(struct hda_codec *codec, pin = path->path[path->depth - 1]; init_output_pin(codec, pin, pin_type); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - else - caps = 0; + caps = query_amp_caps(codec, pin, HDA_OUTPUT); if (caps & AC_AMPCAP_MUTE) { unsigned int val; val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; @@ -648,10 +642,6 @@ static void via_auto_init_analog_input(struct hda_codec *codec) /* init ADCs */ for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t nid = spec->adc_nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) || - !(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)) - continue; snd_hda_codec_write(codec, spec->adc_nids[i], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)); @@ -673,9 +663,6 @@ static void via_auto_init_analog_input(struct hda_codec *codec) /* init input-src */ for (i = 0; i < spec->num_adc_nids; i++) { int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx; - /* secondary ADCs must have the unique MUX */ - if (i > 0 && !spec->mux_nids[i]) - break; if (spec->mux_nids[adc_idx]) { int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx; snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, @@ -700,15 +687,6 @@ static void via_auto_init_analog_input(struct hda_codec *codec) } } -static void update_power_state(struct hda_codec *codec, hda_nid_t nid, - unsigned int parm) -{ - if (snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0) == parm) - return; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); -} - static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned int *affected_parm) { @@ -731,7 +709,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, } else parm = AC_PWRST_D3; - update_power_state(codec, nid, parm); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, @@ -771,7 +749,6 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, return 0; spec->no_pin_power_ctl = val; set_widgets_power_state(codec); - analog_low_current_mode(codec); return 1; } @@ -1059,19 +1036,13 @@ static bool is_aa_path_mute(struct hda_codec *codec) } /* enter/exit analog low-current mode */ -static void __analog_low_current_mode(struct hda_codec *codec, bool force) +static void analog_low_current_mode(struct hda_codec *codec) { struct via_spec *spec = codec->spec; bool enable; unsigned int verb, parm; - if (spec->no_pin_power_ctl) - enable = false; - else - enable = is_aa_path_mute(codec) && !spec->opened_streams; - if (enable == spec->alc_mode && !force) - return; - spec->alc_mode = enable; + enable = is_aa_path_mute(codec) && (spec->opened_streams != 0); /* decide low current mode's verb & parameter */ switch (spec->codec_type) { @@ -1103,11 +1074,6 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) snd_hda_codec_write(codec, codec->afg, 0, verb, parm); } -static void analog_low_current_mode(struct hda_codec *codec) -{ - return __analog_low_current_mode(codec, false); -} - /* * generic initialization of ADC, input mixers and output mixers */ @@ -1452,9 +1418,25 @@ static const struct hda_pcm_stream via_pcm_digital_capture = { /* * slave controls for virtual master */ -static const char * const via_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", +static const char * const via_slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", + "Center Playback Volume", + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", + "Speaker Playback Volume", + NULL, +}; + +static const char * const via_slave_sws[] = { + "Front Playback Switch", + "Surround Playback Switch", + "Center Playback Switch", + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", + "Speaker Playback Switch", NULL, }; @@ -1464,7 +1446,6 @@ static int via_build_controls(struct hda_codec *codec) struct snd_kcontrol *kctl; int err, i; - spec->no_pin_power_ctl = 1; if (spec->set_widgets_power_state) if (!via_clone_control(spec, &via_pin_power_ctl_enum)) return -ENOMEM; @@ -1499,15 +1480,13 @@ static int via_build_controls(struct hda_codec *codec) snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], HDA_OUTPUT, vmaster_tlv); err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_pfxs, - "Playback Volume"); + vmaster_tlv, via_slave_vols); if (err < 0) return err; } if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_pfxs, - "Playback Switch"); + NULL, via_slave_sws); if (err < 0) return err; } @@ -1515,13 +1494,15 @@ static int via_build_controls(struct hda_codec *codec) /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); for (i = 0; kctl && i < kctl->count; i++) { - if (!spec->mux_nids[i]) - continue; err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); if (err < 0) return err; } + /* init power states */ + set_widgets_power_state(codec); + analog_low_current_mode(codec); + via_free_kctls(codec); /* no longer needed */ err = snd_hda_jack_add_kctls(codec, &spec->autocfg); @@ -2314,7 +2295,10 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, if (mux) { /* switch to D0 beofre change index */ - update_power_state(codec, mux, AC_PWRST_D0); + if (snd_hda_codec_read(codec, mux, 0, + AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) + snd_hda_codec_write(codec, mux, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); snd_hda_codec_write(codec, mux, 0, AC_VERB_SET_CONNECT_SEL, spec->inputs[cur].mux_idx); @@ -2483,8 +2467,6 @@ static int create_mic_boost_ctls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; int i, err; for (i = 0; i < cfg->num_inputs; i++) { @@ -2499,13 +2481,8 @@ static int create_mic_boost_ctls(struct hda_codec *codec) if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) continue; label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; snprintf(name, sizeof(name), "%s Boost Volume", label); - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); if (err < 0) return err; @@ -2799,10 +2776,6 @@ static int via_init(struct hda_codec *codec) for (i = 0; i < spec->num_iverbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); - /* init power states */ - set_widgets_power_state(codec); - __analog_low_current_mode(codec, true); - via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_speaker_out(codec); @@ -2949,9 +2922,9 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (17h), AIW 0/1 (13h/14h) */ - update_power_state(codec, 0x17, parm); - update_power_state(codec, 0x13, parm); - update_power_state(codec, 0x14, parm); + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* PW0 (19h), SW1 (18h), AOW1 (11h) */ @@ -2959,8 +2932,8 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x19, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1b, &parm); - update_power_state(codec, 0x18, parm); - update_power_state(codec, 0x11, parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); /* PW6 (22h), SW2 (26h), AOW2 (24h) */ if (is_8ch) { @@ -2968,16 +2941,20 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x22, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - update_power_state(codec, 0x26, parm); - update_power_state(codec, 0x24, parm); + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x24, 0, + AC_VERB_SET_POWER_STATE, parm); } else if (codec->vendor_id == 0x11064397) { /* PW7(23h), SW2(27h), AOW2(25h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - update_power_state(codec, 0x27, parm); - update_power_state(codec, 0x25, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); } /* PW 3/4/7 (1ch/1dh/23h) */ @@ -2989,13 +2966,17 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x23, &parm); /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm); - update_power_state(codec, 0x10, parm); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); if (is_8ch) { - update_power_state(codec, 0x25, parm); - update_power_state(codec, 0x27, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) - update_power_state(codec, 0x25, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); } static int patch_vt1708S(struct hda_codec *codec); @@ -3168,10 +3149,10 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */ /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - update_power_state(codec, 0x13, parm); - update_power_state(codec, 0x12, parm); - update_power_state(codec, 0x1f, parm); - update_power_state(codec, 0x20, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* PW 3/4 (16h/17h) */ @@ -3179,9 +3160,10 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) set_pin_power_state(codec, 0x17, &parm); set_pin_power_state(codec, 0x16, &parm); /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - update_power_state(codec, 0x1a, imux_is_smixer ? AC_PWRST_D0 : parm); - update_power_state(codec, 0x10, parm); - update_power_state(codec, 0x1d, parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); } static int patch_vt1702(struct hda_codec *codec) @@ -3246,48 +3228,52 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - update_power_state(codec, 0x1e, parm); - update_power_state(codec, 0x1f, parm); - update_power_state(codec, 0x10, parm); - update_power_state(codec, 0x11, parm); + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x27, &parm); - update_power_state(codec, 0x1a, parm); - update_power_state(codec, 0xb, parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm); /* PW2 (26h), AOW2 (ah) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x2b, &parm); - update_power_state(codec, 0xa, parm); + snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm); /* PW0 (24h), AOW0 (8h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (!spec->hp_independent_mode) /* check for redirected HP */ set_pin_power_state(codec, 0x28, &parm); - update_power_state(codec, 0x8, parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - update_power_state(codec, 0x21, imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); /* PW1 (25h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x2a, &parm); - update_power_state(codec, 0x9, parm); + snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm); if (spec->hp_independent_mode) { /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - update_power_state(codec, 0x1b, parm); - update_power_state(codec, 0x34, parm); - update_power_state(codec, 0xc, parm); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xc, 0, + AC_VERB_SET_POWER_STATE, parm); } } @@ -3447,8 +3433,8 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (17h), AIW0(13h) */ - update_power_state(codec, 0x17, parm); - update_power_state(codec, 0x13, parm); + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x1e, &parm); @@ -3456,11 +3442,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) if (spec->dmic_enabled) set_pin_power_state(codec, 0x22, &parm); else - update_power_state(codec, 0x22, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x22, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); /* SW2(26h), AIW1(14h) */ - update_power_state(codec, 0x26, parm); - update_power_state(codec, 0x14, parm); + snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* PW0 (19h), SW1 (18h), AOW1 (11h) */ @@ -3469,8 +3456,8 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) /* Smart 5.1 PW2(1bh) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1b, &parm); - update_power_state(codec, 0x18, parm); - update_power_state(codec, 0x11, parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); /* PW7 (23h), SW3 (27h), AOW3 (25h) */ parm = AC_PWRST_D3; @@ -3478,12 +3465,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) /* Smart 5.1 PW1(1ah) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - update_power_state(codec, 0x27, parm); + snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); /* Smart 5.1 PW5(1eh) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1e, &parm); - update_power_state(codec, 0x25, parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); /* Mono out */ /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ @@ -3499,9 +3486,9 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) mono_out = 1; } parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - update_power_state(codec, 0x28, parm); - update_power_state(codec, 0x29, parm); - update_power_state(codec, 0x2a, parm); + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); /* PW 3/4 (1ch/1dh) */ parm = AC_PWRST_D3; @@ -3509,12 +3496,15 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1d, &parm); /* HP Independent Mode, power on AOW3 */ if (spec->hp_independent_mode) - update_power_state(codec, 0x25, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); /* force to D0 for internal Speaker */ /* MW0 (16h), AOW0 (10h) */ - update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm); - update_power_state(codec, 0x10, mono_out ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); } static int patch_vt1716S(struct hda_codec *codec) @@ -3590,45 +3580,54 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) set_pin_power_state(codec, 0x2b, &parm); parm = AC_PWRST_D0; /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - update_power_state(codec, 0x1e, parm); - update_power_state(codec, 0x1f, parm); - update_power_state(codec, 0x10, parm); - update_power_state(codec, 0x11, parm); + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* AOW0 (8h)*/ - update_power_state(codec, 0x8, parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); if (spec->codec_type == VT1802) { /* PW4 (28h), MW4 (18h), MUX4(38h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - update_power_state(codec, 0x18, parm); - update_power_state(codec, 0x38, parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, + AC_VERB_SET_POWER_STATE, parm); } else { /* PW4 (26h), MW4 (1ch), MUX4(37h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); - update_power_state(codec, 0x1c, parm); - update_power_state(codec, 0x37, parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x37, 0, + AC_VERB_SET_POWER_STATE, parm); } if (spec->codec_type == VT1802) { /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - update_power_state(codec, 0x15, parm); - update_power_state(codec, 0x35, parm); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); } else { /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - update_power_state(codec, 0x19, parm); - update_power_state(codec, 0x35, parm); + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); } if (spec->hp_independent_mode) - update_power_state(codec, 0x9, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); /* Class-D */ /* PW0 (24h), MW0(18h/14h), MUX0(34h) */ @@ -3638,10 +3637,12 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) set_pin_power_state(codec, 0x24, &parm); parm = present ? AC_PWRST_D3 : AC_PWRST_D0; if (spec->codec_type == VT1802) - update_power_state(codec, 0x14, parm); + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, parm); else - update_power_state(codec, 0x18, parm); - update_power_state(codec, 0x34, parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm); /* Mono Out */ present = snd_hda_jack_detect(codec, 0x26); @@ -3649,20 +3650,28 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) parm = present ? AC_PWRST_D3 : AC_PWRST_D0; if (spec->codec_type == VT1802) { /* PW15 (33h), MW8(1ch), MUX8(3ch) */ - update_power_state(codec, 0x33, parm); - update_power_state(codec, 0x1c, parm); - update_power_state(codec, 0x3c, parm); + snd_hda_codec_write(codec, 0x33, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, parm); } else { /* PW15 (31h), MW8(17h), MUX8(3bh) */ - update_power_state(codec, 0x31, parm); - update_power_state(codec, 0x17, parm); - update_power_state(codec, 0x3b, parm); + snd_hda_codec_write(codec, 0x31, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, parm); } /* MW9 (21h) */ if (imux_is_smixer || !is_aa_path_mute(codec)) - update_power_state(codec, 0x21, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); else - update_power_state(codec, 0x21, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } /* patch for vt2002P */ @@ -3722,28 +3731,30 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) set_pin_power_state(codec, 0x2b, &parm); parm = AC_PWRST_D0; /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - update_power_state(codec, 0x1e, parm); - update_power_state(codec, 0x1f, parm); - update_power_state(codec, 0x10, parm); - update_power_state(codec, 0x11, parm); + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); /* outputs */ /* AOW0 (8h)*/ - update_power_state(codec, 0x8, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); /* PW4 (28h), MW4 (18h), MUX4(38h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - update_power_state(codec, 0x18, parm); - update_power_state(codec, 0x38, parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm); /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - update_power_state(codec, 0x15, parm); - update_power_state(codec, 0x35, parm); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm); if (spec->hp_independent_mode) - update_power_state(codec, 0x9, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); /* Internal Speaker */ /* PW0 (24h), MW0(14h), MUX0(34h) */ @@ -3752,11 +3763,15 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (present) { - update_power_state(codec, 0x14, AC_PWRST_D3); - update_power_state(codec, 0x34, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } else { - update_power_state(codec, 0x14, AC_PWRST_D0); - update_power_state(codec, 0x34, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); } @@ -3767,20 +3782,26 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x31, &parm); if (present) { - update_power_state(codec, 0x1c, AC_PWRST_D3); - update_power_state(codec, 0x3c, AC_PWRST_D3); - update_power_state(codec, 0x3e, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } else { - update_power_state(codec, 0x1c, AC_PWRST_D0); - update_power_state(codec, 0x3c, AC_PWRST_D0); - update_power_state(codec, 0x3e, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); } /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x33, &parm); - update_power_state(codec, 0x1d, parm); - update_power_state(codec, 0x3d, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm); } diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index 812d10e43ae0..92362973764d 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -1013,25 +1013,6 @@ static int set_rate_constraints(struct snd_ice1712 *ice, ice->hw_rates); } -/* if the card has the internal rate locked (is_pro_locked), limit runtime - hw rates to the current internal rate only. -*/ -static void constrain_rate_if_locked(struct snd_pcm_substream *substream) -{ - struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int rate; - if (is_pro_rate_locked(ice)) { - rate = ice->get_rate(ice); - if (rate >= runtime->hw.rate_min - && rate <= runtime->hw.rate_max) { - runtime->hw.rate_min = rate; - runtime->hw.rate_max = rate; - } - } -} - - /* multi-channel playback needs alignment 8x32bit regardless of the channels * actually used */ @@ -1065,7 +1046,6 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); - constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1086,7 +1066,6 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); - constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1236,7 +1215,6 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); - constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; @@ -1273,7 +1251,6 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); - constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index e0a4263baa20..9f3b01bb72c8 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -2100,12 +2100,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, - { - .subvendor = 0x161f, - .subdevice = 0x202f, - .name = "Gateway M520", - .type = AC97_TUNE_INV_EAPD - }, { .subvendor = 0x161f, .subdevice = 0x203a, diff --git a/trunk/sound/pci/oxygen/oxygen_mixer.c b/trunk/sound/pci/oxygen/oxygen_mixer.c index c0dbb52d45be..26c7e8bcb229 100644 --- a/trunk/sound/pci/oxygen/oxygen_mixer.c +++ b/trunk/sound/pci/oxygen/oxygen_mixer.c @@ -618,12 +618,9 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, mutex_lock(&chip->mutex); reg = oxygen_read_ac97(chip, codec, index); mutex_unlock(&chip->mutex); - if (!stereo) { - value->value.integer.value[0] = 31 - (reg & 0x1f); - } else { - value->value.integer.value[0] = 31 - ((reg >> 8) & 0x1f); - value->value.integer.value[1] = 31 - (reg & 0x1f); - } + value->value.integer.value[0] = 31 - (reg & 0x1f); + if (stereo) + value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); return 0; } @@ -639,14 +636,14 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, mutex_lock(&chip->mutex); oldreg = oxygen_read_ac97(chip, codec, index); - if (!stereo) { - newreg = oldreg & ~0x1f; - newreg |= 31 - (value->value.integer.value[0] & 0x1f); - } else { - newreg = oldreg & ~0x1f1f; - newreg |= (31 - (value->value.integer.value[0] & 0x1f)) << 8; - newreg |= 31 - (value->value.integer.value[1] & 0x1f); - } + newreg = oldreg; + newreg = (newreg & ~0x1f) | + (31 - (value->value.integer.value[0] & 0x1f)); + if (stereo) + newreg = (newreg & ~0x1f00) | + ((31 - (value->value.integer.value[1] & 0x1f)) << 8); + else + newreg = (newreg & ~0x1f00) | ((newreg & 0x1f) << 8); change = newreg != oldreg; if (change) oxygen_write_ac97(chip, codec, index, newreg); diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index bc030a2088da..cc9f6c83d661 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -6333,7 +6333,6 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, hw->ops.open = snd_hdspm_hwdep_dummy_op; hw->ops.ioctl = snd_hdspm_hwdep_ioctl; - hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl; hw->ops.release = snd_hdspm_hwdep_dummy_op; return 0; diff --git a/trunk/sound/pci/ymfpci/ymfpci.c b/trunk/sound/pci/ymfpci/ymfpci.c index 94ab728f5ca8..e57b89e8aa89 100644 --- a/trunk/sound/pci/ymfpci/ymfpci.c +++ b/trunk/sound/pci/ymfpci/ymfpci.c @@ -286,22 +286,17 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, snd_card_free(card); return err; } - err = snd_ymfpci_mixer(chip, rear_switch[dev]); - if (err < 0) { + if ((err = snd_ymfpci_pcm_4ch(chip, 2, NULL)) < 0) { snd_card_free(card); return err; } - if (chip->ac97->ext_id & AC97_EI_SDAC) { - err = snd_ymfpci_pcm_4ch(chip, 2, NULL); - if (err < 0) { - snd_card_free(card); - return err; - } - err = snd_ymfpci_pcm2(chip, 3, NULL); - if (err < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_ymfpci_pcm2(chip, 3, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) { + snd_card_free(card); + return err; } if ((err = snd_ymfpci_timer(chip, 0)) < 0) { snd_card_free(card); diff --git a/trunk/sound/pci/ymfpci/ymfpci_main.c b/trunk/sound/pci/ymfpci/ymfpci_main.c index a8159b81e9c4..03ee4e365311 100644 --- a/trunk/sound/pci/ymfpci/ymfpci_main.c +++ b/trunk/sound/pci/ymfpci/ymfpci_main.c @@ -1614,14 +1614,6 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static struct snd_kcontrol_new snd_ymfpci_dup4ch __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "4ch Duplication", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_ymfpci_info_dup4ch, - .get = snd_ymfpci_get_dup4ch, - .put = snd_ymfpci_put_dup4ch, -}; static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = { { @@ -1650,6 +1642,13 @@ YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL), YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0), YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0), YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "4ch Duplication", + .info = snd_ymfpci_info_dup4ch, + .get = snd_ymfpci_get_dup4ch, + .put = snd_ymfpci_put_dup4ch, +}, }; @@ -1839,12 +1838,6 @@ int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip))) < 0) return err; } - if (chip->ac97->ext_id & AC97_EI_SDAC) { - kctl = snd_ctl_new1(&snd_ymfpci_dup4ch, chip); - err = snd_ctl_add(chip->card, kctl); - if (err < 0) - return err; - } /* add S/PDIF control */ if (snd_BUG_ON(!chip->pcm_spdif)) @@ -2317,10 +2310,6 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, - &chip->saved_dsxg_legacy); - pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, - &chip->saved_dsxg_elegacy); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); @@ -2355,11 +2344,6 @@ int snd_ymfpci_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97); - pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, - chip->saved_dsxg_legacy); - pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, - chip->saved_dsxg_elegacy); - /* start hw again */ if (chip->start_count > 0) { spin_lock_irq(&chip->reg_lock); diff --git a/trunk/sound/soc/codecs/ak4642.c b/trunk/sound/soc/codecs/ak4642.c index 278c0a0575f5..5ef70b5d27e4 100644 --- a/trunk/sound/soc/codecs/ak4642.c +++ b/trunk/sound/soc/codecs/ak4642.c @@ -146,10 +146,13 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, 0, 0xFF, 1, out_tlv), + + SOC_SINGLE("Headphone Switch", PW_MGMT2, 6, 1, 0), }; -static const struct snd_kcontrol_new ak4642_headphone_control = - SOC_DAPM_SINGLE("Switch", PW_MGMT2, 6, 1, 0); +static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = { + SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0), +}; static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = { SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0), @@ -162,12 +165,13 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPOUTR"), SND_SOC_DAPM_OUTPUT("LINEOUT"), - SND_SOC_DAPM_PGA("HPL Out", PW_MGMT2, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("HPR Out", PW_MGMT2, 4, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("Headphone Enable", SND_SOC_NOPM, 0, 0, - &ak4642_headphone_control), + SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), - SND_SOC_DAPM_PGA("DACH", MD_CTL4, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HPOUTR Mixer", PW_MGMT2, 4, 0, + &ak4642_hpout_mixer_controls[0], + ARRAY_SIZE(ak4642_hpout_mixer_controls)), SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0, &ak4642_lout_mixer_controls[0], @@ -180,17 +184,12 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = { static const struct snd_soc_dapm_route ak4642_intercon[] = { /* Outputs */ - {"HPOUTL", NULL, "HPL Out"}, - {"HPOUTR", NULL, "HPR Out"}, + {"HPOUTL", NULL, "HPOUTL Mixer"}, + {"HPOUTR", NULL, "HPOUTR Mixer"}, {"LINEOUT", NULL, "LINEOUT Mixer"}, - {"HPL Out", NULL, "Headphone Enable"}, - {"HPR Out", NULL, "Headphone Enable"}, - - {"Headphone Enable", "Switch", "DACH"}, - - {"DACH", NULL, "DAC"}, - + {"HPOUTL Mixer", "DACH", "DAC"}, + {"HPOUTR Mixer", "DACH", "DAC"}, {"LINEOUT Mixer", "DACL", "DAC"}, }; diff --git a/trunk/sound/soc/codecs/cs42l73.c b/trunk/sound/soc/codecs/cs42l73.c index 78979b3e0e95..9d38db8f1919 100644 --- a/trunk/sound/soc/codecs/cs42l73.c +++ b/trunk/sound/soc/codecs/cs42l73.c @@ -1113,7 +1113,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].mmcc &= 0xC0; priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc; priv->config[id].spc &= 0xFC; - priv->config[id].spc |= MCK_SCLK_MCLK; + priv->config[id].spc &= MCK_SCLK_64FS; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; diff --git a/trunk/sound/soc/codecs/wm2000.c b/trunk/sound/soc/codecs/wm2000.c index a75c3766aede..c2880907fced 100644 --- a/trunk/sound/soc/codecs/wm2000.c +++ b/trunk/sound/soc/codecs/wm2000.c @@ -733,9 +733,8 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, struct wm2000_priv *wm2000; struct wm2000_platform_data *pdata; const char *filename; - const struct firmware *fw = NULL; - int ret; - int reg; + const struct firmware *fw; + int reg, ret; u16 id; wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv), @@ -752,7 +751,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(wm2000->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto out; + goto err; } /* Verify that this is a WM2000 */ @@ -764,7 +763,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, if (id != 0x2000) { dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); ret = -ENODEV; - goto out_regmap_exit; + goto err_regmap; } reg = wm2000_read(i2c, WM2000_REG_REVISON); @@ -783,7 +782,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ret = request_firmware(&fw, filename, &i2c->dev); if (ret != 0) { dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); - goto out_regmap_exit; + goto err_regmap; } /* Pre-cook the concatenation of the register address onto the image */ @@ -794,13 +793,15 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, if (wm2000->anc_download == NULL) { dev_err(&i2c->dev, "Out of memory\n"); ret = -ENOMEM; - goto out_regmap_exit; + goto err_fw; } wm2000->anc_download[0] = 0x80; wm2000->anc_download[1] = 0x00; memcpy(wm2000->anc_download + 2, fw->data, fw->size); + release_firmware(fw); + wm2000->anc_eng_ena = 1; wm2000->anc_active = 1; wm2000->spk_ena = 1; @@ -808,14 +809,18 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, wm2000_reset(wm2000); - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0); - if (!ret) - goto out; + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, + NULL, 0); + if (ret != 0) + goto err_fw; -out_regmap_exit: - regmap_exit(wm2000->regmap); -out: + return 0; + +err_fw: release_firmware(fw); +err_regmap: + regmap_exit(wm2000->regmap); +err: return ret; } diff --git a/trunk/sound/soc/codecs/wm5100.c b/trunk/sound/soc/codecs/wm5100.c index 89f2af77b1c3..66f0611e68b6 100644 --- a/trunk/sound/soc/codecs/wm5100.c +++ b/trunk/sound/soc/codecs/wm5100.c @@ -1405,7 +1405,6 @@ static int wm5100_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: regcache_cache_only(wm5100->regmap, true); - regcache_mark_dirty(wm5100->regmap); if (wm5100->pdata.ldo_ena) gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), @@ -2184,7 +2183,6 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) if (wm5100->jack_detecting) { dev_dbg(codec->dev, "Microphone detected\n"); wm5100->jack_mic = true; - wm5100->jack_detecting = false; snd_soc_jack_report(wm5100->jack, SND_JACK_HEADSET, SND_JACK_HEADSET | SND_JACK_BTN_0); @@ -2223,7 +2221,6 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) SND_JACK_BTN_0); } else if (wm5100->jack_detecting) { dev_dbg(codec->dev, "Headphone detected\n"); - wm5100->jack_detecting = false; snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE, SND_JACK_HEADPHONE); @@ -2613,13 +2610,6 @@ static const struct regmap_config wm5100_regmap = { .cache_type = REGCACHE_RBTREE, }; -static const unsigned int wm5100_mic_ctrl_reg[] = { - WM5100_IN1L_CONTROL, - WM5100_IN2L_CONTROL, - WM5100_IN3L_CONTROL, - WM5100_IN4L_CONTROL, -}; - static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2752,7 +2742,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, } for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) { - regmap_update_bits(wm5100->regmap, wm5100_mic_ctrl_reg[i], + regmap_update_bits(wm5100->regmap, WM5100_IN1L_CONTROL, WM5100_IN1_MODE_MASK | WM5100_IN1_DMIC_SUP_MASK, (wm5100->pdata.in_mode[i] << diff --git a/trunk/sound/soc/codecs/wm8958-dsp2.c b/trunk/sound/soc/codecs/wm8958-dsp2.c index 40ac888faf3d..8d4ea43d40a3 100644 --- a/trunk/sound/soc/codecs/wm8958-dsp2.c +++ b/trunk/sound/soc/codecs/wm8958-dsp2.c @@ -55,7 +55,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, return 0; if (fw->size < 32) { - dev_err(codec->dev, "%s: firmware too short (%zd bytes)\n", + dev_err(codec->dev, "%s: firmware too short (%d bytes)\n", name, fw->size); goto err; } diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index 0ac228b7dc04..296de4e30d26 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -96,7 +96,7 @@ static int wm8962_regulator_event_##n(struct notifier_block *nb, \ struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - regcache_mark_dirty(wm8962->regmap); \ + regcache_cache_only(wm8962->regmap, true); \ } \ return 0; \ } @@ -2564,7 +2564,7 @@ static int dsp2_event(struct snd_soc_dapm_widget *w, return 0; } -static const char *st_text[] = { "None", "Left", "Right" }; +static const char *st_text[] = { "None", "Right", "Left" }; static const struct soc_enum str_enum = SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text); @@ -3159,13 +3159,13 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: - aif0 |= 0x4; + aif0 |= 0x40; break; case SNDRV_PCM_FORMAT_S24_LE: - aif0 |= 0x8; + aif0 |= 0x80; break; case SNDRV_PCM_FORMAT_S32_LE: - aif0 |= 0xc; + aif0 |= 0xc0; break; default: return -EINVAL; diff --git a/trunk/sound/soc/codecs/wm8978.c b/trunk/sound/soc/codecs/wm8978.c index 85d514d63a4c..0b1f7ada17bc 100644 --- a/trunk/sound/soc/codecs/wm8978.c +++ b/trunk/sound/soc/codecs/wm8978.c @@ -1001,7 +1001,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { .reg_cache_default = wm8978_reg, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1043,27 +1042,22 @@ static struct i2c_driver wm8978_i2c_driver = { .remove = __devexit_p(wm8978_i2c_remove), .id_table = wm8978_i2c_id, }; -#endif static int __init wm8978_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ret = i2c_add_driver(&wm8978_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", ret); } -#endif return ret; } module_init(wm8978_modinit); static void __exit wm8978_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8978_i2c_driver); -#endif } module_exit(wm8978_exit); diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index ec69a6c152fe..93d27b660257 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -770,8 +770,6 @@ static void vmid_reference(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - pm_runtime_get_sync(codec->dev); - wm8994->vmid_refcount++; dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n", @@ -785,12 +783,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_VMID_RAMP_MASK, WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | - (0x3 << WM8994_VMID_RAMP_SHIFT)); - - /* Remove discharge for line out */ - snd_soc_update_bits(codec, WM8994_ANTIPOP_1, - WM8994_LINEOUT1_DISCH | - WM8994_LINEOUT2_DISCH, 0); + (0x11 << WM8994_VMID_RAMP_SHIFT)); /* Main bias enable, VMID=2x40k */ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, @@ -844,8 +837,6 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_VMID_BUF_ENA | WM8994_VMID_RAMP_MASK, 0); } - - pm_runtime_put(codec->dev); } static int vmid_event(struct snd_soc_dapm_widget *w, @@ -2762,6 +2753,11 @@ static int wm8994_resume(struct snd_soc_codec *codec) codec->cache_only = 0; } + /* Restore the registers */ + ret = snd_soc_cache_sync(codec); + if (ret != 0) + dev_err(codec->dev, "Failed to sync cache: %d\n", ret); + wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { diff --git a/trunk/sound/soc/codecs/wm8996.c b/trunk/sound/soc/codecs/wm8996.c index 61f7daa4d0e6..86f5b6bd7af2 100644 --- a/trunk/sound/soc/codecs/wm8996.c +++ b/trunk/sound/soc/codecs/wm8996.c @@ -108,7 +108,7 @@ static int wm8996_regulator_event_##n(struct notifier_block *nb, \ struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - regcache_mark_dirty(wm8996->regmap); \ + regcache_cache_only(wm8996->regmap, true); \ } \ return 0; \ } @@ -1120,8 +1120,7 @@ SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("Bandgap", SND_SOC_NOPM, 0, 0, bg_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0), diff --git a/trunk/sound/soc/codecs/wm_hubs.c b/trunk/sound/soc/codecs/wm_hubs.c index 8a68cea4a3ee..2a61094075f8 100644 --- a/trunk/sound/soc/codecs/wm_hubs.c +++ b/trunk/sound/soc/codecs/wm_hubs.c @@ -586,14 +586,14 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), }; static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; static const struct snd_kcontrol_new line2n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), }; static const struct snd_kcontrol_new line2p_mix[] = { @@ -613,8 +613,6 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), - SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, in1l_pga, ARRAY_SIZE(in1l_pga)), SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, @@ -836,11 +834,9 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { - { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, @@ -848,8 +844,8 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = { }; static const struct snd_soc_dapm_route lineout2_diff_routes[] = { - { "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" }, - { "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" }, + { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, + { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, @@ -857,11 +853,9 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { - { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, - { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, diff --git a/trunk/sound/soc/imx/imx-ssi.c b/trunk/sound/soc/imx/imx-ssi.c index b6adbed6e506..01d1f749cf02 100644 --- a/trunk/sound/soc/imx/imx-ssi.c +++ b/trunk/sound/soc/imx/imx-ssi.c @@ -112,7 +112,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) break; case SND_SOC_DAIFMT_DSP_A: /* data on rising edge of bclk, frame high 1clk before data */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; break; } diff --git a/trunk/sound/soc/mxs/mxs-saif.c b/trunk/sound/soc/mxs/mxs-saif.c index f204dbac11d4..dccfb37a9626 100644 --- a/trunk/sound/soc/mxs/mxs-saif.c +++ b/trunk/sound/soc/mxs/mxs-saif.c @@ -124,8 +124,6 @@ static int mxs_saif_set_clk(struct mxs_saif *saif, * * If MCLK is not used, we just set saif clk to 512*fs. */ - clk_prepare_enable(master_saif->clk); - if (master_saif->mclk_in_use) { if (mclk % 32 == 0) { scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; @@ -135,7 +133,6 @@ static int mxs_saif_set_clk(struct mxs_saif *saif, ret = clk_set_rate(master_saif->clk, 384 * rate); } else { /* SAIF MCLK should be either 32x or 48x */ - clk_disable_unprepare(master_saif->clk); return -EINVAL; } } else { @@ -143,8 +140,6 @@ static int mxs_saif_set_clk(struct mxs_saif *saif, scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; } - clk_disable_unprepare(master_saif->clk); - if (ret) return ret; diff --git a/trunk/sound/soc/samsung/neo1973_wm8753.c b/trunk/sound/soc/samsung/neo1973_wm8753.c index d23b19a59d83..7ac0ba2025c3 100644 --- a/trunk/sound/soc/samsung/neo1973_wm8753.c +++ b/trunk/sound/soc/samsung/neo1973_wm8753.c @@ -230,6 +230,8 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { /* GTA02 specific routes and controls */ +#ifdef CONFIG_MACH_NEO1973_GTA02 + static int gta02_speaker_enabled; static int lm4853_set_spk(struct snd_kcontrol *kcontrol, @@ -309,6 +311,10 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) return 0; } +#else +static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } +#endif + static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; @@ -316,6 +322,10 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) int ret; /* set up NC codec pins */ + if (machine_is_neo1973_gta01()) { + snd_soc_dapm_nc_pin(dapm, "LOUT2"); + snd_soc_dapm_nc_pin(dapm, "ROUT2"); + } snd_soc_dapm_nc_pin(dapm, "OUT3"); snd_soc_dapm_nc_pin(dapm, "OUT4"); snd_soc_dapm_nc_pin(dapm, "LINE1"); @@ -360,6 +370,50 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) return 0; } +/* GTA01 specific controls */ + +#ifdef CONFIG_MACH_NEO1973_GTA01 + +static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { + {"Amp IN", NULL, "ROUT1"}, + {"Amp IN", NULL, "LOUT1"}, + + {"Handset Spk", NULL, "Amp EP"}, + {"Stereo Out", NULL, "Amp LS"}, + {"Headphone", NULL, "Amp HP"}, +}; + +static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Handset Spk", NULL), + SND_SOC_DAPM_SPK("Stereo Out", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), +}; + +static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) +{ + int ret; + + ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, + ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, + ARRAY_SIZE(neo1973_lm4857_routes)); + if (ret) + return ret; + + snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); + snd_soc_dapm_ignore_suspend(dapm, "Headphone"); + + return 0; +} + +#else +static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; +#endif + static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", @@ -367,7 +421,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { .platform_name = "samsung-audio", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", - .codec_name = "wm8753.0-001a", + .codec_name = "wm8753-codec.0-001a", .init = neo1973_wm8753_init, .ops = &neo1973_hifi_ops, }, @@ -376,7 +430,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { .stream_name = "Voice", .cpu_dai_name = "dfbmcs320-pcm", .codec_dai_name = "wm8753-voice", - .codec_name = "wm8753.0-001a", + .codec_name = "wm8753-codec.0-001a", .ops = &neo1973_voice_ops, }, }; @@ -386,6 +440,11 @@ static struct snd_soc_aux_dev neo1973_aux_devs[] = { .name = "dfbmcs320", .codec_name = "dfbmcs320.0", }, + { + .name = "lm4857", + .codec_name = "lm4857.0-007c", + .init = neo1973_lm4857_init, + }, }; static struct snd_soc_codec_conf neo1973_codec_conf[] = { @@ -395,10 +454,14 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = { }, }; +#ifdef CONFIG_MACH_NEO1973_GTA02 static const struct gpio neo1973_gta02_gpios[] = { { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, }; +#else +static const struct gpio neo1973_gta02_gpios[] = {}; +#endif static struct snd_soc_card neo1973 = { .name = "neo1973", @@ -417,7 +480,7 @@ static int __init neo1973_init(void) { int ret; - if (!machine_is_neo1973_gta02()) + if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) return -ENODEV; if (machine_is_neo1973_gta02()) { diff --git a/trunk/sound/soc/sh/fsi.c b/trunk/sound/soc/sh/fsi.c index ea4a82d01160..db6c89a28bda 100644 --- a/trunk/sound/soc/sh/fsi.c +++ b/trunk/sound/soc/sh/fsi.c @@ -1152,8 +1152,12 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); + int samples_pos = io->buff_sample_pos - 1; - return fsi_sample2frame(fsi, io->buff_sample_pos); + if (samples_pos < 0) + samples_pos = 0; + + return fsi_sample2frame(fsi, samples_pos); } static struct snd_pcm_ops fsi_pcm_ops = { diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 92cee24ed2dc..b5ecf6d23214 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -567,17 +567,6 @@ int snd_soc_suspend(struct device *dev) if (!codec->suspended && codec->driver->suspend) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: - /* - * If the CODEC is capable of idle - * bias off then being in STANDBY - * means it's doing something, - * otherwise fall through. - */ - if (codec->dapm.idle_bias_off) { - dev_dbg(codec->dev, - "idle_bias_off CODEC on over suspend\n"); - break; - } case SND_SOC_BIAS_OFF: codec->driver->suspend(codec); codec->suspended = 1; diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 1315663c1c09..1f55ded4047f 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -3068,13 +3068,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) * standby. */ if (powerdown) { - if (dapm->bias_level == SND_SOC_BIAS_ON) - snd_soc_dapm_set_bias_level(dapm, - SND_SOC_BIAS_PREPARE); + snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); dapm_seq_run(dapm, &down_list, 0, false); - if (dapm->bias_level == SND_SOC_BIAS_PREPARE) - snd_soc_dapm_set_bias_level(dapm, - SND_SOC_BIAS_STANDBY); + snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); } } @@ -3087,9 +3083,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) list_for_each_entry(codec, &card->codec_dev_list, list) { soc_dapm_shutdown_codec(&codec->dapm); - if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) - snd_soc_dapm_set_bias_level(&codec->dapm, - SND_SOC_BIAS_OFF); + snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); } } diff --git a/trunk/sound/spi/at73c213.c b/trunk/sound/spi/at73c213.c index c6500d00053b..4dd051bdf4fd 100644 --- a/trunk/sound/spi/at73c213.c +++ b/trunk/sound/spi/at73c213.c @@ -1112,7 +1112,17 @@ static struct spi_driver at73c213_driver = { .remove = __devexit_p(snd_at73c213_remove), }; -module_spi_driver(at73c213_driver); +static int __init at73c213_init(void) +{ + return spi_register_driver(&at73c213_driver); +} +module_init(at73c213_init); + +static void __exit at73c213_exit(void) +{ + spi_unregister_driver(&at73c213_driver); +} +module_exit(at73c213_exit); MODULE_AUTHOR("Hans-Christian Egtvedt "); MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); diff --git a/trunk/sound/usb/6fire/chip.c b/trunk/sound/usb/6fire/chip.c index fc8cc823e438..8af92e3e9c18 100644 --- a/trunk/sound/usb/6fire/chip.c +++ b/trunk/sound/usb/6fire/chip.c @@ -5,6 +5,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify @@ -28,7 +29,7 @@ #include MODULE_AUTHOR("Torsten Schenk "); -MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver"); +MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0"); MODULE_LICENSE("GPL v2"); MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); diff --git a/trunk/sound/usb/6fire/chip.h b/trunk/sound/usb/6fire/chip.h index bde02d105a51..d11e5cb520f0 100644 --- a/trunk/sound/usb/6fire/chip.h +++ b/trunk/sound/usb/6fire/chip.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/comm.c b/trunk/sound/usb/6fire/comm.c index 6c3d531a250e..c994daa57af2 100644 --- a/trunk/sound/usb/6fire/comm.c +++ b/trunk/sound/usb/6fire/comm.c @@ -5,6 +5,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/comm.h b/trunk/sound/usb/6fire/comm.h index d2af0a5ddcf3..edc5dc84b888 100644 --- a/trunk/sound/usb/6fire/comm.h +++ b/trunk/sound/usb/6fire/comm.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/common.h b/trunk/sound/usb/6fire/common.h index b6eb03ed1c2c..7dbeb4a37831 100644 --- a/trunk/sound/usb/6fire/common.h +++ b/trunk/sound/usb/6fire/common.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/control.c b/trunk/sound/usb/6fire/control.c index 07ed914d5e71..ac828eff1a63 100644 --- a/trunk/sound/usb/6fire/control.c +++ b/trunk/sound/usb/6fire/control.c @@ -5,12 +5,9 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * - * Thanks to: - * - Holger Ruckdeschel: he found out how to control individual channel - * volumes and introduced mute switch - * * This program 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 @@ -19,7 +16,6 @@ #include #include -#include #include "control.h" #include "comm.h" @@ -28,6 +24,26 @@ static char *opt_coax_texts[2] = { "Optical", "Coax" }; static char *line_phono_texts[2] = { "Line", "Phono" }; +/* + * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$ + * this is done because the linear values cause rapid degredation + * of volume in the uppermost region. + */ +static const u8 log_volume_table[128] = { + 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34, + 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, + 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, + 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, + 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, + 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, + 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, + 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, + 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, + 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, + 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f }; + /* * data that needs to be sent to device. sets up card internal stuff. * values dumped from windows driver and filtered by trial'n'error. @@ -43,7 +59,7 @@ init_data[] = { { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, - { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, + { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, { 0 } /* TERMINATING ENTRY */ @@ -54,47 +70,20 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; -static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); -static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500); - enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; -static void usb6fire_control_output_vol_update(struct control_runtime *rt) +static void usb6fire_control_master_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; - int i; - - if (comm_rt) - for (i = 0; i < 6; i++) - if (!(rt->ovol_updated & (1 << i))) { - comm_rt->write8(comm_rt, 0x12, 0x0f + i, - 180 - rt->output_vol[i]); - rt->ovol_updated |= 1 << i; - } -} - -static void usb6fire_control_output_mute_update(struct control_runtime *rt) -{ - struct comm_runtime *comm_rt = rt->chip->comm; - - if (comm_rt) - comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); -} - -static void usb6fire_control_input_vol_update(struct control_runtime *rt) -{ - struct comm_runtime *comm_rt = rt->chip->comm; - int i; - - if (comm_rt) - for (i = 0; i < 2; i++) - if (!(rt->ivol_updated & (1 << i))) { - comm_rt->write8(comm_rt, 0x12, 0x1c + i, - rt->input_vol[i] & 0x3f); - rt->ivol_updated |= 1 << i; - } + if (comm_rt) { + /* set volume */ + comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f - + log_volume_table[rt->master_vol]); + /* unmute */ + comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); + } } static void usb6fire_control_line_phono_update(struct control_runtime *rt) @@ -176,147 +165,34 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt) return -EINVAL; } -static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, +static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 180; - return 0; -} - -static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - unsigned int ch = kcontrol->private_value; - int changed = 0; - - if (ch > 4) { - snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); - return -EINVAL; - } - - if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { - rt->output_vol[ch] = ucontrol->value.integer.value[0]; - rt->ovol_updated &= ~(1 << ch); - changed = 1; - } - if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { - rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; - rt->ovol_updated &= ~(2 << ch); - changed = 1; - } - - if (changed) - usb6fire_control_output_vol_update(rt); - - return changed; -} - -static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - unsigned int ch = kcontrol->private_value; - - if (ch > 4) { - snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); - return -EINVAL; - } - - ucontrol->value.integer.value[0] = rt->output_vol[ch]; - ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; - return 0; -} - -static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - unsigned int ch = kcontrol->private_value; - u8 old = rt->output_mute; - u8 value = 0; - - if (ch > 4) { - snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); - return -EINVAL; - } - - rt->output_mute &= ~(3 << ch); - if (ucontrol->value.integer.value[0]) - value |= 1; - if (ucontrol->value.integer.value[1]) - value |= 2; - rt->output_mute |= value << ch; - - if (rt->output_mute != old) - usb6fire_control_output_mute_update(rt); - - return rt->output_mute != old; -} - -static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - unsigned int ch = kcontrol->private_value; - u8 value = rt->output_mute >> ch; - - if (ch > 4) { - snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); - return -EINVAL; - } - - ucontrol->value.integer.value[0] = 1 & value; - value >>= 1; - ucontrol->value.integer.value[1] = 1 & value; - - return 0; -} - -static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; + uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 30; + uinfo->value.integer.max = 127; return 0; } -static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol, +static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); int changed = 0; - - if (rt->input_vol[0] != ucontrol->value.integer.value[0]) { - rt->input_vol[0] = ucontrol->value.integer.value[0] - 15; - rt->ivol_updated &= ~(1 << 0); + if (rt->master_vol != ucontrol->value.integer.value[0]) { + rt->master_vol = ucontrol->value.integer.value[0]; + usb6fire_control_master_vol_update(rt); changed = 1; } - if (rt->input_vol[1] != ucontrol->value.integer.value[1]) { - rt->input_vol[1] = ucontrol->value.integer.value[1] - 15; - rt->ivol_updated &= ~(1 << 1); - changed = 1; - } - - if (changed) - usb6fire_control_input_vol_update(rt); - return changed; } -static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol, +static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = rt->input_vol[0] + 15; - ucontrol->value.integer.value[1] = rt->input_vol[1] + 15; - + ucontrol->value.integer.value[0] = rt->master_vol; return 0; } @@ -411,81 +287,16 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } -static struct __devinitdata snd_kcontrol_new vol_elements[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Volume", - .index = 0, - .private_value = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = usb6fire_control_output_vol_info, - .get = usb6fire_control_output_vol_get, - .put = usb6fire_control_output_vol_put, - .tlv = { .p = tlv_output } - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Volume", - .index = 1, - .private_value = 2, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = usb6fire_control_output_vol_info, - .get = usb6fire_control_output_vol_get, - .put = usb6fire_control_output_vol_put, - .tlv = { .p = tlv_output } - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Volume", - .index = 2, - .private_value = 4, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = usb6fire_control_output_vol_info, - .get = usb6fire_control_output_vol_get, - .put = usb6fire_control_output_vol_put, - .tlv = { .p = tlv_output } - }, - {} -}; - -static struct __devinitdata snd_kcontrol_new mute_elements[] = { +static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Switch", + .name = "Master Playback Volume", .index = 0, - .private_value = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_ctl_boolean_stereo_info, - .get = usb6fire_control_output_mute_get, - .put = usb6fire_control_output_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Switch", - .index = 1, - .private_value = 2, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_ctl_boolean_stereo_info, - .get = usb6fire_control_output_mute_get, - .put = usb6fire_control_output_mute_put, + .info = usb6fire_control_master_vol_info, + .get = usb6fire_control_master_vol_get, + .put = usb6fire_control_master_vol_put }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Playback Switch", - .index = 2, - .private_value = 4, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_ctl_boolean_stereo_info, - .get = usb6fire_control_output_mute_get, - .put = usb6fire_control_output_mute_put, - }, - {} -}; - -static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", @@ -513,54 +324,9 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .get = usb6fire_control_digital_thru_get, .put = usb6fire_control_digital_thru_put }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Capture Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = usb6fire_control_input_vol_info, - .get = usb6fire_control_input_vol_get, - .put = usb6fire_control_input_vol_put, - .tlv = { .p = tlv_input } - }, {} }; -static int usb6fire_control_add_virtual( - struct control_runtime *rt, - struct snd_card *card, - char *name, - struct snd_kcontrol_new *elems) -{ - int ret; - int i; - struct snd_kcontrol *vmaster = - snd_ctl_make_virtual_master(name, tlv_output); - struct snd_kcontrol *control; - - if (!vmaster) - return -ENOMEM; - ret = snd_ctl_add(card, vmaster); - if (ret < 0) - return ret; - - i = 0; - while (elems[i].name) { - control = snd_ctl_new1(&elems[i], rt); - if (!control) - return -ENOMEM; - ret = snd_ctl_add(card, control); - if (ret < 0) - return ret; - ret = snd_ctl_add_slave(vmaster, control); - if (ret < 0) - return ret; - i++; - } - return 0; -} - int __devinit usb6fire_control_init(struct sfire_chip *chip) { int i; @@ -586,26 +352,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); - usb6fire_control_output_vol_update(rt); - usb6fire_control_output_mute_update(rt); - usb6fire_control_input_vol_update(rt); + usb6fire_control_master_vol_update(rt); usb6fire_control_streaming_update(rt); - ret = usb6fire_control_add_virtual(rt, chip->card, - "Master Playback Volume", vol_elements); - if (ret) { - snd_printk(KERN_ERR PREFIX "cannot add control.\n"); - kfree(rt); - return ret; - } - ret = usb6fire_control_add_virtual(rt, chip->card, - "Master Playback Switch", mute_elements); - if (ret) { - snd_printk(KERN_ERR PREFIX "cannot add control.\n"); - kfree(rt); - return ret; - } - i = 0; while (elements[i].name) { ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); diff --git a/trunk/sound/usb/6fire/control.h b/trunk/sound/usb/6fire/control.h index 9a596d95474a..8f5aeead2e3d 100644 --- a/trunk/sound/usb/6fire/control.h +++ b/trunk/sound/usb/6fire/control.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify @@ -43,11 +44,7 @@ struct control_runtime { bool line_phono_switch; bool digital_thru_switch; bool usb_streaming; - u8 output_vol[6]; - u8 ovol_updated; - u8 output_mute; - s8 input_vol[2]; - u8 ivol_updated; + u8 master_vol; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); diff --git a/trunk/sound/usb/6fire/firmware.c b/trunk/sound/usb/6fire/firmware.c index 6f9715ab32fe..3b5f517a3972 100644 --- a/trunk/sound/usb/6fire/firmware.c +++ b/trunk/sound/usb/6fire/firmware.c @@ -5,6 +5,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/midi.c b/trunk/sound/usb/6fire/midi.c index f0e5179b242b..13f4509dce2b 100644 --- a/trunk/sound/usb/6fire/midi.c +++ b/trunk/sound/usb/6fire/midi.c @@ -5,6 +5,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/midi.h b/trunk/sound/usb/6fire/midi.h index 5114eccc1d8e..97a7bf669135 100644 --- a/trunk/sound/usb/6fire/midi.h +++ b/trunk/sound/usb/6fire/midi.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/pcm.c b/trunk/sound/usb/6fire/pcm.c index c97d05f0e966..d144cdb2f159 100644 --- a/trunk/sound/usb/6fire/pcm.c +++ b/trunk/sound/usb/6fire/pcm.c @@ -5,6 +5,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/6fire/pcm.h b/trunk/sound/usb/6fire/pcm.h index 3104301b257d..2bee81374002 100644 --- a/trunk/sound/usb/6fire/pcm.h +++ b/trunk/sound/usb/6fire/pcm.h @@ -3,6 +3,7 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 + * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/trunk/sound/usb/Kconfig b/trunk/sound/usb/Kconfig index ff77b28f3da1..3efc21c3d67c 100644 --- a/trunk/sound/usb/Kconfig +++ b/trunk/sound/usb/Kconfig @@ -106,7 +106,6 @@ config SND_USB_6FIRE select BITREVERSE select SND_RAWMIDI select SND_PCM - select SND_VMASTER help Say Y here to include support for TerraTec 6fire DMX USB interface. diff --git a/trunk/sound/usb/caiaq/audio.c b/trunk/sound/usb/caiaq/audio.c index fde9a7a29cb6..2cf87f5afed4 100644 --- a/trunk/sound/usb/caiaq/audio.c +++ b/trunk/sound/usb/caiaq/audio.c @@ -311,10 +311,8 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) spin_lock(&dev->spinlock); - if (dev->input_panic || dev->output_panic) { + if (dev->input_panic || dev->output_panic) ptr = SNDRV_PCM_POS_XRUN; - goto unlock; - } if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ptr = bytes_to_frames(sub->runtime, @@ -323,7 +321,6 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) ptr = bytes_to_frames(sub->runtime, dev->audio_in_buf_pos[index]); -unlock: spin_unlock(&dev->spinlock); return ptr; } diff --git a/trunk/sound/usb/card.h b/trunk/sound/usb/card.h index da5fa1ac4eda..a39edcc32a93 100644 --- a/trunk/sound/usb/card.h +++ b/trunk/sound/usb/card.h @@ -1,7 +1,6 @@ #ifndef __USBAUDIO_CARD_H #define __USBAUDIO_CARD_H -#define MAX_NR_RATES 1024 #define MAX_PACKS 20 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ #define MAX_URBS 8 diff --git a/trunk/sound/usb/format.c b/trunk/sound/usb/format.c index ddfef57c4c9f..e09aba19375c 100644 --- a/trunk/sound/usb/format.c +++ b/trunk/sound/usb/format.c @@ -209,6 +209,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof return 0; } +#define MAX_UAC2_NR_RATES 1024 + /* * Helper function to walk the array of sample rate triplets reported by * the device. The problem is that we need to parse whole array first to @@ -253,7 +255,7 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets, fp->rates |= snd_pcm_rate_to_rate_bit(rate); nr_rates++; - if (nr_rates >= MAX_NR_RATES) { + if (nr_rates >= MAX_UAC2_NR_RATES) { snd_printk(KERN_ERR "invalid uac2 rates\n"); break; } diff --git a/trunk/sound/usb/pcm.c b/trunk/sound/usb/pcm.c index 0eed6115c2d4..0220b0f335b9 100644 --- a/trunk/sound/usb/pcm.c +++ b/trunk/sound/usb/pcm.c @@ -695,7 +695,6 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct audioformat *fp; - int *rate_list; int count = 0, needs_knot = 0; int err; @@ -709,8 +708,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, if (!needs_knot) return 0; - subs->rate_list.list = rate_list = - kmalloc(sizeof(int) * count, GFP_KERNEL); + subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); if (!subs->rate_list.list) return -ENOMEM; subs->rate_list.count = count; @@ -719,7 +717,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, list_for_each_entry(fp, &subs->fmt_list, list) { int i; for (i = 0; i < fp->nr_rates; i++) - rate_list[count++] = fp->rate_table[i]; + subs->rate_list.list[count++] = fp->rate_table[i]; } err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &subs->rate_list); diff --git a/trunk/sound/usb/quirks-table.h b/trunk/sound/usb/quirks-table.h index d89ab4c7d44b..8edc5035fc8f 100644 --- a/trunk/sound/usb/quirks-table.h +++ b/trunk/sound/usb/quirks-table.h @@ -1617,14 +1617,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - /* Edirol UM-3G */ - USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .ifnum = 0, - .type = QUIRK_MIDI_STANDARD_INTERFACE - } -}, { /* Boss JS-8 Jam Station */ USB_DEVICE(0x0582, 0x0109), diff --git a/trunk/sound/usb/quirks.c b/trunk/sound/usb/quirks.c index 27817266867a..a3ddac0deffd 100644 --- a/trunk/sound/usb/quirks.c +++ b/trunk/sound/usb/quirks.c @@ -132,14 +132,10 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, unsigned *rate_table = NULL; fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); - if (!fp) { + if (! fp) { snd_printk(KERN_ERR "cannot memdup\n"); return -ENOMEM; } - if (fp->nr_rates > MAX_NR_RATES) { - kfree(fp); - return -EINVAL; - } if (fp->nr_rates > 0) { rate_table = kmemdup(fp->rate_table, sizeof(int) * fp->nr_rates, GFP_KERNEL); diff --git a/trunk/sound/usb/usx2y/usbusx2yaudio.c b/trunk/sound/usb/usx2y/usbusx2yaudio.c index 520ef96d7c75..6ffb3713b60c 100644 --- a/trunk/sound/usb/usx2y/usbusx2yaudio.c +++ b/trunk/sound/usb/usx2y/usbusx2yaudio.c @@ -80,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ snd_printk(KERN_ERR "active frame status %i. " - "Most probably some hardware problem.\n", + "Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, { snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" -"Most probably some urb of usb-frame %i is still missing.\n" +"Most propably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", diff --git a/trunk/sound/usb/usx2y/usx2yhwdeppcm.c b/trunk/sound/usb/usx2y/usx2yhwdeppcm.c index 8e40b6e67e9e..a51340f6f2db 100644 --- a/trunk/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/trunk/sound/usb/usx2y/usx2yhwdeppcm.c @@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) } for (i = 0; i < nr_of_packs(); i++) { if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;