diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Kconfig | 5 | ||||
-rw-r--r-- | sound/pci/hda/Makefile | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 106 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 204 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 130 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel_trace.h | 62 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.c | 93 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 17 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 73 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 47 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 98 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 22 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 171 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 150 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 27 |
17 files changed, 822 insertions, 396 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7105c3d..6eeb889 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -37,8 +37,8 @@ config SND_HDA_HWDEP with codecs for debugging purposes. config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL + bool "Allow dynamic codec reconfiguration" + depends on SND_HDA_HWDEP help Say Y here to enable the HD-audio codec re-configuration feature. This adds the sysfs interfaces to allow user to clear the whole @@ -72,7 +72,6 @@ config SND_HDA_INPUT_JACK config SND_HDA_PATCH_LOADER bool "Support initialization patch loading for HD-audio" - depends on EXPERIMENTAL select FW_LOADER select SND_HDA_HWDEP select SND_HDA_RECONFIG diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index bd4149f..24a2514 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -8,6 +8,7 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o # for trace-points CFLAGS_hda_codec.o := -I$(src) +CFLAGS_hda_intel.o := -I$(src) snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4ec6dc8..7da883a 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/export.h> +#include <linux/sort.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -30,29 +31,30 @@ static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) return 0; } +/* a pair of input pin and its sequence */ +struct auto_out_pin { + hda_nid_t pin; + short seq; +}; + +static int compare_seq(const void *ap, const void *bp) +{ + const struct auto_out_pin *a = ap; + const struct auto_out_pin *b = bp; + return (int)(a->seq - b->seq); +} /* * Sort an associated group of pins according to their sequence numbers. + * then store it to a pin array. */ -static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, +static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, int num_pins) { - int i, j; - short seq; - hda_nid_t nid; - - for (i = 0; i < num_pins; i++) { - for (j = i + 1; j < num_pins; j++) { - if (sequences[i] > sequences[j]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = pins[i]; - pins[i] = pins[j]; - pins[j] = nid; - } - } - } + int i; + sort(list, num_pins, sizeof(list[0]), compare_seq, NULL); + for (i = 0; i < num_pins; i++) + pins[i] = list[i].pin; } @@ -67,21 +69,11 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, } } -/* sort inputs in the order of AUTO_PIN_* type */ -static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +static int compare_input_type(const void *ap, const void *bp) { - int i, j; - - for (i = 0; i < cfg->num_inputs; i++) { - for (j = i + 1; j < cfg->num_inputs; j++) { - if (cfg->inputs[i].type > cfg->inputs[j].type) { - struct auto_pin_cfg_item tmp; - tmp = cfg->inputs[i]; - cfg->inputs[i] = cfg->inputs[j]; - cfg->inputs[j] = tmp; - } - } - } + const struct auto_pin_cfg_item *a = ap; + const struct auto_pin_cfg_item *b = bp; + return (int)(a->type - b->type); } /* Reorder the surround channels @@ -129,16 +121,16 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, { hda_nid_t nid, end_nid; short seq, assoc_line_out; - short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; - short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; - short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; + struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; + struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; int i; memset(cfg, 0, sizeof(*cfg)); - memset(sequences_line_out, 0, sizeof(sequences_line_out)); - memset(sequences_speaker, 0, sizeof(sequences_speaker)); - memset(sequences_hp, 0, sizeof(sequences_hp)); + memset(line_out, 0, sizeof(line_out)); + memset(speaker_out, 0, sizeof(speaker_out)); + memset(hp_out, 0, sizeof(hp_out)); assoc_line_out = 0; end_nid = codec->start_nid + codec->num_nodes; @@ -184,8 +176,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, continue; if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences_line_out[cfg->line_outs] = seq; + line_out[cfg->line_outs].pin = nid; + line_out[cfg->line_outs].seq = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: @@ -193,8 +185,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, assoc = get_defcfg_association(def_conf); if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + speaker_out[cfg->speaker_outs].pin = nid; + speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: @@ -202,8 +194,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, assoc = get_defcfg_association(def_conf); if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) continue; - cfg->hp_pins[cfg->hp_outs] = nid; - sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; + hp_out[cfg->hp_outs].pin = nid; + hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: @@ -248,34 +240,28 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ - if ((sequences_hp[i] & 0x0f) == 0x0f) { + if ((hp_out[i].seq & 0x0f) == 0x0f) { i++; continue; } /* Move it to the line-out table */ - cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; - sequences_line_out[cfg->line_outs] = sequences_hp[i]; - cfg->line_outs++; + line_out[cfg->line_outs++] = hp_out[i]; cfg->hp_outs--; - memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, - sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i, sequences_hp + i + 1, - sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); + memmove(hp_out + i, hp_out + i + 1, + sizeof(hp_out[0]) * (cfg->hp_outs - i)); } - memset(cfg->hp_pins + cfg->hp_outs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + memset(hp_out + cfg->hp_outs, 0, + sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); if (!cfg->hp_outs) cfg->line_out_type = AUTO_PIN_HP_OUT; } /* sort by sequence */ - sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, - cfg->line_outs); - sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, + sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); + sort_pins_by_sequence(cfg->speaker_pins, speaker_out, cfg->speaker_outs); - sort_pins_by_sequence(cfg->hp_pins, sequences_hp, - cfg->hp_outs); + sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin @@ -304,7 +290,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, reorder_outputs(cfg->hp_outs, cfg->hp_pins); reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); - sort_autocfg_input_pins(cfg); + /* sort inputs in the order of AUTO_PIN_* type */ + sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), + compare_input_type, NULL); /* * debug prints of the parsed results diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d010de1..c5d0472 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -993,19 +993,6 @@ static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, return NULL; } -/* write a config value for the given NID */ -static void set_pincfg(struct hda_codec *codec, hda_nid_t nid, - unsigned int cfg) -{ - int i; - for (i = 0; i < 4; i++) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, - cfg & 0xff); - cfg >>= 8; - } -} - /* set the current pin config value for the given NID. * the value is cached, and read via snd_hda_codec_get_pincfg() */ @@ -1013,12 +1000,10 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg) { struct hda_pincfg *pin; - unsigned int oldcfg; if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) return -EINVAL; - oldcfg = snd_hda_codec_get_pincfg(codec, nid); pin = look_up_pincfg(codec, list, nid); if (!pin) { pin = snd_array_new(list); @@ -1027,13 +1012,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, pin->nid = nid; } pin->cfg = cfg; - - /* change only when needed; e.g. if the pincfg is already present - * in user_pins[], don't write it - */ - cfg = snd_hda_codec_get_pincfg(codec, nid); - if (oldcfg != cfg) - set_pincfg(codec, nid, cfg); return 0; } @@ -1082,17 +1060,6 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); -/* restore all current pin configs */ -static void restore_pincfgs(struct hda_codec *codec) -{ - int i; - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - set_pincfg(codec, pin->nid, - snd_hda_codec_get_pincfg(codec, pin->nid)); - } -} - /** * snd_hda_shutup_pins - Shut up all pins * @codec: the HDA codec @@ -1137,21 +1104,30 @@ static void restore_shutup_pins(struct hda_codec *codec) } #endif +static void hda_jackpoll_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, jackpoll_work.work); + if (!codec->jackpoll_interval) + return; + + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_poll_all(codec); + queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, + codec->jackpoll_interval); +} + static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); -/* restore the initial pin cfgs and release all pincfg lists */ -static void restore_init_pincfgs(struct hda_codec *codec) +/* release all pincfg lists */ +static void free_init_pincfgs(struct hda_codec *codec) { - /* first free driver_pins and user_pins, then call restore_pincfg - * so that only the values in init_pins are restored - */ snd_array_free(&codec->driver_pins); #ifdef CONFIG_SND_HDA_HWDEP snd_array_free(&codec->user_pins); #endif - restore_pincfgs(codec); snd_array_free(&codec->init_pins); } @@ -1192,8 +1168,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; + cancel_delayed_work_sync(&codec->jackpoll_work); snd_hda_jack_tbl_clear(codec); - restore_init_pincfgs(codec); + free_init_pincfgs(codec); #ifdef CONFIG_PM cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); @@ -1275,6 +1252,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); + snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); + INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); @@ -2153,12 +2132,12 @@ EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * -_snd_hda_find_mixer_ctl(struct hda_codec *codec, - const char *name, int idx) +find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + id.device = dev; id.index = idx; if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) return NULL; @@ -2176,15 +2155,16 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name) { - return _snd_hda_find_mixer_ctl(codec, name, 0); + return find_mixer_ctl(codec, name, 0, 0); } EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); -static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) +static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name, + int dev) { int idx; for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ - if (!_snd_hda_find_mixer_ctl(codec, name, idx)) + if (!find_mixer_ctl(codec, name, dev, idx)) return idx; } return -EBUSY; @@ -2351,7 +2331,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return -EBUSY; /* OK, let it free */ - + cancel_delayed_work_sync(&codec->jackpoll_work); #ifdef CONFIG_PM cancel_delayed_work_sync(&codec->power_work); codec->power_on = 0; @@ -2380,7 +2360,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); /* free only driver_pins so that init_pins + user_pins are restored */ snd_array_free(&codec->driver_pins); - restore_pincfgs(codec); snd_array_free(&codec->cvt_setups); snd_array_free(&codec->spdif_out); codec->num_pcms = 0; @@ -3135,26 +3114,48 @@ static struct snd_kcontrol_new dig_mixes[] = { }; /** - * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls + * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls * @codec: the HDA codec - * @nid: audio out widget NID - * - * Creates controls related with the SPDIF output. - * Called from each patch supporting the SPDIF out. + * @associated_nid: NID that new ctls associated with + * @cvt_nid: converter NID + * @type: HDA_PCM_TYPE_* + * Creates controls related with the digital output. + * Called from each patch supporting the digital out. * * Returns 0 if successful, or a negative error code. */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid) +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, + int type) { int err; struct snd_kcontrol *kctl; struct snd_kcontrol_new *dig_mix; - int idx; + int idx, dev = 0; + const int spdif_pcm_dev = 1; struct hda_spdif_out *spdif; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); + if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI && + type == HDA_PCM_TYPE_SPDIF) { + dev = spdif_pcm_dev; + } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF && + type == HDA_PCM_TYPE_HDMI) { + for (idx = 0; idx < codec->spdif_out.used; idx++) { + spdif = snd_array_elem(&codec->spdif_out, idx); + for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { + kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx); + if (!kctl) + break; + kctl->id.device = spdif_pcm_dev; + } + } + codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI; + } + if (!codec->primary_dig_out_type) + codec->primary_dig_out_type = type; + + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); return -EBUSY; @@ -3164,6 +3165,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, kctl = snd_ctl_new1(dig_mix, codec); if (!kctl) return -ENOMEM; + kctl->id.device = dev; kctl->id.index = idx; kctl->private_value = codec->spdif_out.used - 1; err = snd_hda_ctl_add(codec, associated_nid, kctl); @@ -3176,7 +3178,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, spdif->status = convert_to_spdif_status(spdif->ctls); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls); /* get the hda_spdif_out entry from the given NID * call within spdif_mutex lock @@ -3351,7 +3353,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) struct snd_kcontrol_new *dig_mix; int idx; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch"); + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0); if (idx < 0) { printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); return -EBUSY; @@ -3650,10 +3652,8 @@ static void hda_call_codec_resume(struct hda_codec *codec) */ hda_keep_power_on(codec); hda_set_power_state(codec, AC_PWRST_D0); - restore_pincfgs(codec); /* restore all current pin configs */ restore_shutup_pins(codec); hda_exec_init_verbs(codec); - snd_hda_jack_set_dirty_all(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { @@ -3662,7 +3662,13 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); } - snd_hda_jack_report_sync(codec); + + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else { + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_report_sync(codec); + } codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ @@ -3712,13 +3718,14 @@ static int add_std_chmaps(struct hda_codec *codec) struct hda_pcm_stream *hinfo = &codec->pcm_info[i].stream[str]; struct snd_pcm_chmap *chmap; + const struct snd_pcm_chmap_elem *elem; if (codec->pcm_info[i].own_chmap) continue; if (!pcm || !hinfo->substreams) continue; - err = snd_pcm_add_chmap_ctls(pcm, str, - snd_pcm_std_chmaps, + elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; + err = snd_pcm_add_chmap_ctls(pcm, str, elem, hinfo->channels_max, 0, &chmap); if (err < 0) @@ -3729,6 +3736,19 @@ static int add_std_chmaps(struct hda_codec *codec) return 0; } +/* default channel maps for 2.1 speakers; + * since HD-audio supports only stereo, odd number channels are omitted + */ +const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, + SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } }, + { } +}; +EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); + int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; @@ -3746,7 +3766,10 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) if (err < 0) return err; - snd_hda_jack_report_sync(codec); /* call at the last init point */ + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else + snd_hda_jack_report_sync(codec); /* call at the last init point */ return 0; } @@ -4458,7 +4481,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, addr = codec->addr; else if (!idx && !knew->index) { idx = find_empty_mixer_ctl_idx(codec, - knew->name); + knew->name, 0); if (idx <= 0) return err; } else @@ -4771,6 +4794,34 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); /* + * process kcontrol info callback of a simple string enum array + * when @num_items is 0 or @texts is NULL, assume a boolean enum array + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_items, const char * const *texts) +{ + static const char * const texts_default[] = { + "Disabled", "Enabled" + }; + + if (!texts || !num_items) { + num_items = 2; + texts = texts_default; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = num_items; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_enum_helper_info); + +/* * Multi-channel / digital-out PCM helper functions */ @@ -4778,10 +4829,20 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format) { - struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid); - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + struct hda_spdif_out *spdif; + unsigned int curr_fmt; + bool reset; + + spdif = snd_hda_spdif_out_of_nid(codec, nid); + curr_fmt = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_STREAM_FORMAT, 0); + reset = codec->spdif_status_reset && + (spdif->ctls & AC_DIG1_ENABLE) && + curr_fmt != format; + + /* turn off SPDIF if needed; otherwise the IEC958 bits won't be + updated */ + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & ~AC_DIG1_ENABLE & 0xff, -1); @@ -4793,7 +4854,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, format); } /* turn on again (if needed) */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & 0xff, -1); } @@ -5137,6 +5198,7 @@ int snd_hda_suspend(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { + cancel_delayed_work_sync(&codec->jackpoll_work); if (hda_codec_is_power_on(codec)) hda_call_codec_suspend(codec, false); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 4f4e545..8665540 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -757,6 +757,7 @@ struct hda_pcm_stream { u32 rates; /* supported rates */ u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ unsigned int maxbps; /* supported max. bit per sample */ + const struct snd_pcm_chmap_elem *chmap; /* chmap to override */ struct hda_pcm_ops ops; }; @@ -836,6 +837,7 @@ struct hda_codec { struct mutex hash_mutex; struct snd_array spdif_out; unsigned int spdif_in_enable; /* SPDIF input enable? */ + int primary_dig_out_type; /* primary digital out PCM type */ const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ struct snd_array init_pins; /* initial (BIOS) pin configurations */ struct snd_array driver_pins; /* pin configs set by codec parser */ @@ -885,6 +887,8 @@ struct hda_codec { /* jack detection */ struct snd_array jacktbl; + unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ + struct delayed_work jackpoll_work; #ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ @@ -1024,6 +1028,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); +extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[]; + /* * Misc */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f9d870e..4bb52da 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -47,6 +47,9 @@ #include <linux/reboot.h> #include <linux/io.h> #include <linux/pm_runtime.h> +#include <linux/clocksource.h> +#include <linux/time.h> + #ifdef CONFIG_X86 /* for snoop control */ #include <asm/pgtable.h> @@ -68,6 +71,7 @@ static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; +static int jackpoll_ms[SNDRV_CARDS]; static bool single_cmd; static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER @@ -95,6 +99,8 @@ module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param_array(probe_only, int, NULL, 0444); MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); +module_param_array(jackpoll_ms, int, NULL, 0444); +MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)"); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); @@ -416,6 +422,9 @@ struct azx_dev { unsigned int insufficient :1; unsigned int wc_marked:1; unsigned int no_period_wakeup:1; + + struct timecounter azx_tc; + struct cyclecounter azx_cc; }; /* CORB/RIRB */ @@ -518,6 +527,9 @@ struct azx { struct list_head list; }; +#define CREATE_TRACE_POINTS +#include "hda_intel_trace.h" + /* driver types */ enum { AZX_DRIVER_ICH, @@ -835,8 +847,9 @@ static void azx_update_rirb(struct azx *chip) smp_wmb(); chip->rirb.cmds[addr]--; } else - snd_printk(KERN_ERR SFX "spurious response %#x:%#x, " + snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, " "last cmd=%#08x\n", + pci_name(chip->pci), res, res_ex, chip->last_cmd[addr]); } @@ -1588,6 +1601,22 @@ static void azx_bus_reset(struct hda_bus *bus) bus->in_reset = 0; } +static int get_jackpoll_interval(struct azx *chip) +{ + int i = jackpoll_ms[chip->dev_index]; + unsigned int j; + if (i == 0) + return 0; + if (i < 50 || i > 60000) + j = 0; + else + j = msecs_to_jiffies(i); + if (j == 0) + snd_printk(KERN_WARNING SFX + "jackpoll_ms value out of range: %d\n", i); + return j; +} + /* * Codec initialization */ @@ -1672,6 +1701,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; + codec->jackpoll_interval = get_jackpoll_interval(chip); codec->beep_mode = chip->beep_mode; codecs++; } @@ -1734,6 +1764,64 @@ static inline void azx_release_device(struct azx_dev *azx_dev) azx_dev->opened = 0; } +static cycle_t azx_cc_read(const struct cyclecounter *cc) +{ + struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc); + struct snd_pcm_substream *substream = azx_dev->substream; + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + + return azx_readl(chip, WALLCLK); +} + +static void azx_timecounter_init(struct snd_pcm_substream *substream, + bool force, cycle_t last) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + struct timecounter *tc = &azx_dev->azx_tc; + struct cyclecounter *cc = &azx_dev->azx_cc; + u64 nsec; + + cc->read = azx_cc_read; + cc->mask = CLOCKSOURCE_MASK(32); + + /* + * Converting from 24 MHz to ns means applying a 125/3 factor. + * To avoid any saturation issues in intermediate operations, + * the 125 factor is applied first. The division is applied + * last after reading the timecounter value. + * Applying the 1/3 factor as part of the multiplication + * requires at least 20 bits for a decent precision, however + * overflows occur after about 4 hours or less, not a option. + */ + + cc->mult = 125; /* saturation after 195 years */ + cc->shift = 0; + + nsec = 0; /* audio time is elapsed time since trigger */ + timecounter_init(tc, cc, nsec); + if (force) + /* + * force timecounter to use predefined value, + * used for synchronized starts + */ + tc->cycle_last = last; +} + +static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, + struct timespec *ts) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + u64 nsec; + + nsec = timecounter_read(&azx_dev->azx_tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + + *ts = ns_to_timespec(nsec); + + return 0; +} + static struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -1743,6 +1831,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { /* SNDRV_PCM_INFO_RESUME |*/ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_HAS_WALL_CLOCK | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -1782,6 +1871,12 @@ 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); + + /* avoid wrap-around with wall-clock */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, + 20, + 178000000); + if (chip->align_buffer_size) /* constrain buffer sizes to be multiple of 128 bytes. This is more efficient in terms of memory @@ -1821,6 +1916,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&chip->open_mutex); return -EINVAL; } + + /* disable WALLCLOCK timestamps for capture streams + until we figure out how to handle digital inputs */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; + spin_lock_irqsave(&chip->reg_lock, flags); azx_dev->substream = substream; azx_dev->running = 0; @@ -1967,6 +2068,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int rstart = 0, start, nsync = 0, sbits = 0; int nwait, timeout; + azx_dev = get_azx_dev(substream); + trace_azx_pcm_trigger(chip, azx_dev, cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: rstart = 1; @@ -2057,6 +2161,22 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) azx_readl(chip, OLD_SSYNC) & ~sbits); else azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); + if (start) { + azx_timecounter_init(substream, 0, 0); + if (nsync > 1) { + cycle_t cycle_last; + + /* same start cycle for master and group */ + azx_dev = get_azx_dev(substream); + cycle_last = azx_dev->azx_tc.cycle_last; + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_timecounter_init(s, 1, cycle_last); + } + } + } spin_unlock(&chip->reg_lock); return 0; } @@ -2123,6 +2243,7 @@ static unsigned int azx_get_position(struct azx *chip, { unsigned int pos; int stream = azx_dev->substream->stream; + int delay = 0; switch (chip->position_fix[stream]) { case POS_FIX_LPIB: @@ -2156,7 +2277,6 @@ static unsigned int azx_get_position(struct azx *chip, chip->position_fix[stream] == POS_FIX_POSBUF && (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); - int delay; if (stream == SNDRV_PCM_STREAM_PLAYBACK) delay = pos - lpib_pos; else @@ -2174,6 +2294,7 @@ static unsigned int azx_get_position(struct azx *chip, azx_dev->substream->runtime->delay = bytes_to_frames(azx_dev->substream->runtime, delay); } + trace_azx_get_position(chip, azx_dev, pos, delay); return pos; } @@ -2199,13 +2320,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { u32 wallclk; unsigned int pos; - int stream; wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev, true); if (WARN_ONCE(!azx_dev->period_bytes, @@ -2296,6 +2415,7 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, + .wall_clock = azx_get_wallclock_tstamp, .mmap = azx_pcm_mmap, .page = snd_pcm_sgbuf_ops_page, }; @@ -3387,8 +3507,10 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) chip->fw->data); if (err < 0) goto out_free; +#ifndef CONFIG_PM release_firmware(chip->fw); /* no longer needed */ chip->fw = NULL; +#endif } #endif if ((probe_only[dev] & 1) == 0) { diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/pci/hda/hda_intel_trace.h new file mode 100644 index 0000000..7b5e4c2 --- /dev/null +++ b/sound/pci/hda/hda_intel_trace.h @@ -0,0 +1,62 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hda_intel +#define TRACE_INCLUDE_FILE hda_intel_trace + +#if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HDA_INTEL_H + +#include <linux/tracepoint.h> + +struct azx; +struct azx_dev; + +TRACE_EVENT(azx_pcm_trigger, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, int cmd), + + TP_ARGS(chip, dev, cmd), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( int, cmd ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->cmd = cmd; + ), + + TP_printk("[%d:%d] cmd=%d", __entry->card, __entry->idx, __entry->cmd) +); + +TRACE_EVENT(azx_get_position, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, unsigned int pos, unsigned int delay), + + TP_ARGS(chip, dev, pos, delay), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( unsigned int, pos ) + __field( unsigned int, delay ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->pos = pos; + __entry->delay = delay; + ), + + TP_printk("[%d:%d] pos=%u, delay=%u", __entry->card, __entry->idx, __entry->pos, __entry->delay) +); + +#endif /* _TRACE_HDA_INTEL_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 5c690cb..6e9f57b 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -95,7 +95,6 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack) return jack; - snd_array_init(&codec->jacktbl, sizeof(*jack), 16); jack = snd_array_new(&codec->jacktbl); if (!jack) return NULL; @@ -122,6 +121,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) snd_array_free(&codec->jacktbl); } +#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) + /* update the cached value and notification flag if needed */ static void jack_detect_update(struct hda_codec *codec, struct hda_jack_tbl *jack) @@ -134,7 +135,21 @@ static void jack_detect_update(struct hda_codec *codec, else jack->pin_sense = read_pin_sense(codec, jack->nid); + /* A gating jack indicates the jack is invalid if gating is unplugged */ + if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) + jack->pin_sense &= ~AC_PINSENSE_PRESENCE; + jack->jack_dirty = 0; + + /* If a jack is gated by this one update it. */ + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated) { + gated->jack_dirty = 1; + jack_detect_update(codec, gated); + } + } } /** @@ -173,8 +188,6 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_pin_sense); -#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) - /** * snd_hda_jack_detect - query pin Presence Detect status * @codec: the CODEC to sense @@ -206,6 +219,8 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, jack->action = action; if (cb) jack->callback = cb; + if (codec->jackpoll_interval > 0) + return 0; /* No unsol if we're polling instead */ return snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); @@ -220,16 +235,46 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); /** + * snd_hda_jack_set_gating_jack - Set gating jack. + * + * Indicates the gated jack is only valid when the gating jack is plugged. + */ +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_nid) +{ + struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid); + struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid); + + if (!gated || !gating) + return -EINVAL; + + gated->gating_jack = gating_nid; + gating->gated_jack = gated_nid; + + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack); + +/** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed */ void snd_hda_jack_report_sync(struct hda_codec *codec) { - struct hda_jack_tbl *jack = codec->jacktbl.list; + struct hda_jack_tbl *jack; int i, state; + /* update all jacks at first */ + jack = codec->jacktbl.list; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->nid) { + if (jack->nid) jack_detect_update(codec, jack); + + /* report the updated jacks; it's done after updating all jacks + * to make sure that all gating jacks properly have been set + */ + jack = codec->jacktbl.list; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid) { if (!jack->kctl) continue; state = get_jack_plug_state(jack->pin_sense); @@ -422,6 +467,19 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); +static void call_jack_callback(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + if (jack->callback) + jack->callback(codec, jack); + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated && gated->callback) + gated->callback(codec, gated); + } +} + void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct hda_jack_tbl *event; @@ -432,10 +490,29 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) return; event->jack_dirty = 1; - if (event->callback) - event->callback(codec, event); - + call_jack_callback(codec, event); snd_hda_jack_report_sync(codec); } EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event); +void snd_hda_jack_poll_all(struct hda_codec *codec) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i, changes = 0; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + unsigned int old_sense; + if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) + continue; + old_sense = get_jack_plug_state(jack->pin_sense); + jack_detect_update(codec, jack); + if (old_sense == get_jack_plug_state(jack->pin_sense)) + continue; + changes = 1; + call_jack_callback(codec, jack); + } + if (changes) + snd_hda_jack_report_sync(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_poll_all); + diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index af8dd47..ec12abd 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -28,6 +28,8 @@ struct hda_jack_tbl { unsigned int jack_detect:1; /* capable of jack-detection? */ unsigned int jack_dirty:1; /* needs to update? */ unsigned int phantom_jack:1; /* a fixed, always present port? */ + hda_nid_t gating_jack; /* valid when gating jack plugged */ + hda_nid_t gated_jack; /* gated is dependent on this jack */ struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ #ifdef CONFIG_SND_HDA_INPUT_JACK int type; @@ -69,6 +71,8 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, unsigned char action, hda_jack_callback cb); +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_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); @@ -84,4 +88,6 @@ void snd_hda_jack_report_sync(struct hda_codec *codec); void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res); +void snd_hda_jack_poll_all(struct hda_codec *codec); + #endif /* __SOUND_HDA_JACK_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 09dbdc3..4b40a5e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -240,9 +240,11 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid); +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, int type); +#define snd_hda_create_spdif_out_ctls(codec, anid, cnid) \ + snd_hda_create_dig_out_ctls(codec, anid, cnid, HDA_PCM_TYPE_SPDIF) int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* @@ -599,6 +601,15 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1) /* + * enum control helper + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_entries, const char * const *texts); +#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ + snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) + +/* * CEA Short Audio Descriptor data */ struct cea_sad { diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1eeba73..89fc503 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -636,7 +636,6 @@ static void ad198x_free(struct hda_codec *codec) if (!spec) return; - ad198x_shutup(codec); ad198x_free_kctls(codec); kfree(spec); snd_hda_detach_beep_device(codec); @@ -1247,16 +1246,27 @@ static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; } -static int patch_ad1986a(struct hda_codec *codec) +static int alloc_ad_spec(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + if (!spec) return -ENOMEM; - codec->spec = spec; + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return 0; +} + +static int patch_ad1986a(struct hda_codec *codec) +{ + struct ad198x_spec *spec; + int err, board_config; + + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x19); if (err < 0) { @@ -1549,11 +1559,10 @@ static int patch_ad1983(struct hda_codec *codec) struct ad198x_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -1955,11 +1964,10 @@ static int patch_ad1981(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + err = alloc_ad_spec(codec); + if (err < 0) return -ENOMEM; - - codec->spec = spec; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -2837,7 +2845,6 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); knew = snd_array_new(&spec->kctls); if (!knew) return -ENOMEM; @@ -3255,11 +3262,10 @@ static int patch_ad1988(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; if (is_rev2(codec)) snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); @@ -3575,11 +3581,10 @@ static int patch_ad1884(struct hda_codec *codec) struct ad198x_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -4575,11 +4580,10 @@ static int patch_ad1884a(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { @@ -4988,11 +4992,10 @@ static int patch_ad1882(struct hda_codec *codec) struct ad198x_spec *spec; int err, board_config; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; err = snd_hda_attach_beep_device(codec, 0x10); if (err < 0) { diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 3bcb671..a2537b2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -68,6 +68,7 @@ struct cs_spec { unsigned int hp_detect:1; unsigned int mic_detect:1; + unsigned int speaker_2_1:1; /* CS421x */ unsigned int spdif_detect:1; unsigned int sense_b:1; @@ -84,7 +85,7 @@ enum { CS420X_GPIO_13, CS420X_GPIO_23, CS420X_MBP101, - CS420X_MBP101_COEF, + CS420X_MBP81, CS420X_AUTO, /* aliases */ CS420X_IMAC27_122 = CS420X_GPIO_23, @@ -343,6 +344,9 @@ static int cs_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; + if (spec->speaker_2_1) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid[spec->cur_input]; @@ -443,6 +447,9 @@ static int parse_output(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nid; spec->multiout.max_channels = i * 2; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && i == 2) + spec->speaker_2_1 = 1; /* assume 2.1 speakers */ + /* add HP and speakers */ extra_nids = 0; for (i = 0; i < cfg->hp_outs; i++) { @@ -633,7 +640,9 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, index = idx; break; case AUTO_PIN_SPEAKER_OUT: - if (num_ctls > 1) + if (spec->speaker_2_1) + name = idx ? "Bass Speaker" : "Speaker"; + else if (num_ctls > 1) name = speakers[idx]; else name = "Speaker"; @@ -874,8 +883,9 @@ static int build_digital_output(struct hda_codec *codec) if (!spec->multiout.dig_out_nid) return 0; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_dig_out_ctls(codec, spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid, + spec->pcm_rec[1].pcm_type); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); @@ -1079,9 +1089,6 @@ static void init_input(struct hda_codec *codec) if (spec->mic_detect) cs_automic(codec, NULL); - coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); - coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG); if (is_active_pin(codec, CS_DMIC2_PIN_NID)) coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */ @@ -1111,6 +1118,9 @@ static const struct hda_verb cs_coef_init_verbs[] = { | 0x1000 /* Enable DACs High Pass Filter */ | 0x0400 /* Disable Coefficient Auto increment */ )}, + /* ADC1/2 - Digital and Analog Soft Ramp */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x000a}, /* Beep */ {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG}, {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ @@ -1167,14 +1177,6 @@ static const struct hda_verb cs_errata_init_verbs[] = { {} /* terminator */ }; -static const struct hda_verb mbp101_init_verbs[] = { - {0x11, AC_VERB_SET_COEF_INDEX, 0x0002}, - {0x11, AC_VERB_SET_PROC_COEF, 0x100a}, - {0x11, AC_VERB_SET_COEF_INDEX, 0x0004}, - {0x11, AC_VERB_SET_PROC_COEF, 0x000f}, - {} -}; - /* SPDIF setup */ static void init_digital(struct hda_codec *codec) { @@ -1199,6 +1201,8 @@ static int cs_init(struct hda_codec *codec) snd_hda_sequence_write(codec, cs_coef_init_verbs); + snd_hda_gen_apply_verbs(codec); + if (spec->gpio_mask) { snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, spec->gpio_mask); @@ -1291,6 +1295,7 @@ static const struct hda_model_fixup cs420x_models[] = { { .id = CS420X_IMAC27_122, .name = "imac27_122" }, { .id = CS420X_APPLE, .name = "apple" }, { .id = CS420X_MBP101, .name = "mbp101" }, + { .id = CS420X_MBP81, .name = "mbp81" }, {} }; @@ -1303,6 +1308,7 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ /* codec SSID */ + SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), @@ -1413,11 +1419,16 @@ static const struct hda_fixup cs420x_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = mbp101_pincfgs, .chained = true, - .chain_id = CS420X_MBP101_COEF, + .chain_id = CS420X_GPIO_13, }, - [CS420X_MBP101_COEF] = { + [CS420X_MBP81] = { .type = HDA_FIXUP_VERBS, - .v.verbs = mbp101_init_verbs, + .v.verbs = (const struct hda_verb[]) { + /* internal mic ADC2: right only, single ended */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x102a}, + {} + }, .chained = true, .chain_id = CS420X_GPIO_13, }, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 03b1dc3..a3a2263 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -337,6 +337,8 @@ static const struct hda_pcm_stream cx5051_pcm_analog_capture = { }, }; +static bool is_2_1_speaker(struct conexant_spec *spec); + static int conexant_build_pcms(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -351,6 +353,9 @@ static int conexant_build_pcms(struct hda_codec *codec) spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + if (is_2_1_speaker(spec)) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; if (spec->capture_stream) info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; else { @@ -472,7 +477,7 @@ static const struct snd_kcontrol_new cxt_beep_mixer[] = { #endif static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Front", "Surround", "CLFE", + "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", NULL }; @@ -3430,28 +3435,13 @@ static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; static const char * const texts3[] = { "Disabled", "Speaker Only", "Line Out+Speaker" }; - const char * const *texts; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_hp_lo) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + if (spec->automute_hp_lo) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); } static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, @@ -4116,11 +4106,26 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, return 0; } +static bool is_2_1_speaker(struct conexant_spec *spec) +{ + int i, type, num_spk = 0; + + for (i = 0; i < spec->dac_info_filled; i++) { + type = spec->dac_info[i].type; + if (type == AUTO_PIN_LINE_OUT) + type = spec->autocfg.line_out_type; + if (type == AUTO_PIN_SPEAKER_OUT) + num_spk++; + } + return (num_spk == 2 && spec->autocfg.line_out_type != AUTO_PIN_LINE_OUT); +} + static int cx_auto_build_output_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; int i, err; int num_line = 0, num_hp = 0, num_spk = 0; + bool speaker_2_1; static const char * const texts[3] = { "Front", "Surround", "CLFE" }; if (spec->dac_info_filled == 1) @@ -4128,6 +4133,8 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) spec->dac_info[0].pin, "Master", 0); + speaker_2_1 = is_2_1_speaker(spec); + for (i = 0; i < spec->dac_info_filled; i++) { const char *label; int idx, type; @@ -4146,8 +4153,13 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) idx = num_hp++; break; case AUTO_PIN_SPEAKER_OUT: - label = "Speaker"; - idx = num_spk++; + if (speaker_2_1) { + label = num_spk++ ? "Bass Speaker" : "Speaker"; + idx = 0; + } else { + label = "Speaker"; + idx = num_spk++; + } break; } err = try_add_pb_volume(codec, dac, @@ -4405,7 +4417,10 @@ static const struct hda_codec_ops cx_auto_patch_ops = { enum { CXT_PINCFG_LENOVO_X200, CXT_PINCFG_LENOVO_TP410, + CXT_PINCFG_LEMOTE_A1004, + CXT_PINCFG_LEMOTE_A1205, CXT_FIXUP_STEREO_DMIC, + CXT_FIXUP_INC_MIC_BOOST, }; static void cxt_fixup_stereo_dmic(struct hda_codec *codec, @@ -4415,6 +4430,19 @@ static void cxt_fixup_stereo_dmic(struct hda_codec *codec, spec->fixup_stereo_dmic = 1; } +static void cxt5066_increase_mic_boost(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT, + (0x3 << AC_AMPCAP_OFFSET_SHIFT) | + (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); +} + /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ @@ -4432,6 +4460,18 @@ static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { {} }; +/* Lemote A1004/A1205 with cxt5066 */ +static const struct hda_pintbl cxt_pincfg_lemote[] = { + { 0x1a, 0x90a10020 }, /* Internal mic */ + { 0x1b, 0x03a11020 }, /* External mic */ + { 0x1d, 0x400101f0 }, /* Not used */ + { 0x1e, 0x40a701f0 }, /* Not used */ + { 0x20, 0x404501f0 }, /* Not used */ + { 0x22, 0x404401f0 }, /* Not used */ + { 0x23, 0x40a701f0 }, /* Not used */ + {} +}; + static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -4441,10 +4481,24 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_lenovo_tp410, }, + [CXT_PINCFG_LEMOTE_A1004] = { + .type = HDA_FIXUP_PINS, + .chained = true, + .chain_id = CXT_FIXUP_INC_MIC_BOOST, + .v.pins = cxt_pincfg_lemote, + }, + [CXT_PINCFG_LEMOTE_A1205] = { + .type = HDA_FIXUP_PINS, + .v.pins = cxt_pincfg_lemote, + }, [CXT_FIXUP_STEREO_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, }, + [CXT_FIXUP_INC_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt5066_increase_mic_boost, + }, }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -4461,6 +4515,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), + SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), {} }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc..0fcfa6f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1193,12 +1193,11 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) struct hdmi_spec_per_pin *per_pin; int err; - caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); + caps = snd_hda_query_pin_caps(codec, pin_nid); if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) return 0; - config = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + config = snd_hda_codec_get_pincfg(codec, pin_nid); if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) return 0; @@ -1272,7 +1271,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) unsigned int caps; unsigned int type; - caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); + caps = get_wcaps(codec, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) @@ -1288,13 +1287,17 @@ static int hdmi_parse_codec(struct hda_codec *codec) } } +#ifdef CONFIG_PM + /* We're seeing some problems with unsolicited hot plug events on + * PantherPoint after S3, if this is not enabled */ + if (codec->vendor_id == 0x80862806) + codec->bus->power_keep_link_on = 1; /* * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event * can be lost and presence sense verb will become inaccurate if the * HDA link is powered off at hot plug or hw initialization time. */ -#ifdef CONFIG_PM - if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & + else if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & AC_PWRST_EPSS)) codec->bus->power_keep_link_on = 1; #endif @@ -1589,9 +1592,10 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) if (err < 0) return err; - err = snd_hda_create_spdif_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0]); + err = snd_hda_create_dig_out_ctls(codec, + per_pin->pin_nid, + per_pin->mux_nids[0], + HDA_PCM_TYPE_HDMI); if (err < 0) return err; snd_hda_spdif_ctls_unassign(codec, pin_idx); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ad68d22..5d8044d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -815,28 +815,13 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; static const char * const texts3[] = { "Disabled", "Speaker Only", "Line Out+Speaker" }; - const char * const *texts; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_speaker_possible && spec->automute_lo_possible) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + if (spec->automute_speaker_possible && spec->automute_lo_possible) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); } static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, @@ -903,23 +888,25 @@ static const struct snd_kcontrol_new alc_automute_mode_enum = { .put = alc_automute_mode_put, }; -static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) +static struct snd_kcontrol_new * +alc_kcontrol_new(struct alc_spec *spec, const char *name, + const struct snd_kcontrol_new *temp) { - snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); - return snd_array_new(&spec->kctls); + struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *temp; + knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) + return NULL; + return knew; } static int alc_add_automute_mode_enum(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_automute_mode_enum; - knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL); - if (!knew->name) + if (!alc_kcontrol_new(spec, "Auto-Mute Mode", &alc_automute_mode_enum)) return -ENOMEM; return 0; } @@ -928,12 +915,12 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec) * Check the availability of HP/line-out auto-mute; * Set up appropriately if really supported */ -static void alc_init_automute(struct hda_codec *codec) +static int alc_init_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int present = 0; - int i; + int i, err; if (cfg->hp_pins[0]) present++; @@ -942,7 +929,7 @@ static void alc_init_automute(struct hda_codec *codec) if (cfg->speaker_pins[0]) present++; if (present < 2) /* need two different output types */ - return; + return 0; if (!cfg->speaker_pins[0] && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { @@ -992,9 +979,13 @@ static void alc_init_automute(struct hda_codec *codec) spec->automute_lo = spec->automute_lo_possible; spec->automute_speaker = spec->automute_speaker_possible; - if (spec->automute_speaker_possible || spec->automute_lo_possible) + if (spec->automute_speaker_possible || spec->automute_lo_possible) { /* create a control for automute mode */ - alc_add_automute_mode_enum(codec); + err = alc_add_automute_mode_enum(codec); + if (err < 0) + return err; + } + return 0; } /* return the position of NID in the list, or -1 if not found */ @@ -1094,7 +1085,7 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec) * Check the availability of auto-mic switch; * Set up if really supported */ -static void alc_init_auto_mic(struct hda_codec *codec) +static int alc_init_auto_mic(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -1102,7 +1093,7 @@ static void alc_init_auto_mic(struct hda_codec *codec) int i; if (spec->shared_mic_hp) - return; /* no auto-mic for the shared I/O */ + return 0; /* no auto-mic for the shared I/O */ spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; @@ -1114,25 +1105,25 @@ static void alc_init_auto_mic(struct hda_codec *codec) switch (snd_hda_get_input_pin_attr(defcfg)) { case INPUT_PIN_ATTR_INT: if (fixed) - return; /* already occupied */ + return 0; /* already occupied */ if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ + return 0; /* invalid type */ fixed = nid; break; case INPUT_PIN_ATTR_UNUSED: - return; /* invalid entry */ + return 0; /* invalid entry */ case INPUT_PIN_ATTR_DOCK: if (dock) - return; /* already occupied */ + return 0; /* already occupied */ if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) - return; /* invalid type */ + return 0; /* invalid type */ dock = nid; break; default: if (ext) - return; /* already occupied */ + return 0; /* already occupied */ if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ + return 0; /* invalid type */ ext = nid; break; } @@ -1142,11 +1133,11 @@ static void alc_init_auto_mic(struct hda_codec *codec) dock = 0; } if (!ext || !fixed) - return; + return 0; if (!is_jack_detectable(codec, ext)) - return; /* no unsol support */ + return 0; /* no unsol support */ if (dock && !is_jack_detectable(codec, dock)) - return; /* no unsol support */ + return 0; /* no unsol support */ /* check imux indices */ spec->ext_mic_pin = ext; @@ -1155,17 +1146,26 @@ static void alc_init_auto_mic(struct hda_codec *codec) spec->auto_mic = 1; if (!alc_auto_mic_check_imux(codec)) - return; + return 0; snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", ext, fixed, dock); + + return 0; } /* check the availabilities of auto-mute and auto-mic switches */ -static void alc_auto_check_switches(struct hda_codec *codec) +static int alc_auto_check_switches(struct hda_codec *codec) { - alc_init_automute(codec); - alc_init_auto_mic(codec); + int err; + + err = alc_init_automute(codec); + if (err < 0) + return err; + err = alc_init_auto_mic(codec); + if (err < 0) + return err; + return 0; } /* @@ -1757,12 +1757,9 @@ static const struct snd_kcontrol_new alc_inv_dmic_sw = { static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_inv_dmic_sw; - knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL); - if (!knew->name) + + if (!alc_kcontrol_new(spec, "Inverted Internal Mic Capture Switch", + &alc_inv_dmic_sw)) return -ENOMEM; spec->inv_dmic_fixup = 1; spec->inv_dmic_muted = 0; @@ -1836,9 +1833,10 @@ static int __alc_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_dig_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid, + spec->pcm_rec[1].pcm_type); if (err < 0) return err; if (!spec->no_analog) { @@ -2259,6 +2257,10 @@ static int alc_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && + spec->autocfg.line_outs == 2) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; } if (spec->adc_nids) { p = spec->stream_analog_capture; @@ -2399,7 +2401,6 @@ static void alc_free(struct hda_codec *codec) if (!spec) return; - alc_shutup(codec); alc_free_kctls(codec); alc_free_bind_ctls(codec); snd_hda_gen_free(&spec->gen); @@ -2534,13 +2535,9 @@ static int add_control(struct alc_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - knew = alc_kcontrol_new(spec); + knew = alc_kcontrol_new(spec, name, &alc_control_templates[type]); if (!knew) return -ENOMEM; - *knew = alc_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return -ENOMEM; knew->index = cidx; if (get_amp_nid_(val)) knew->subdevice = HDA_SUBDEV_AMP_FLAG; @@ -3601,7 +3598,6 @@ static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; struct hda_bind_ctls **ctlp, *ctl; - snd_array_init(&spec->bind_ctls, sizeof(ctl), 8); ctlp = snd_array_new(&spec->bind_ctls); if (!ctlp) return NULL; @@ -3984,14 +3980,8 @@ static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) struct alc_spec *spec = codec->spec; if (spec->multi_ios > 0) { - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_auto_channel_mode_enum; - knew->name = kstrdup("Channel Mode", GFP_KERNEL); - if (!knew->name) + if (!alc_kcontrol_new(spec, "Channel Mode", + &alc_auto_channel_mode_enum)) return -ENOMEM; } return 0; @@ -4346,7 +4336,9 @@ static int alc_parse_auto_config(struct hda_codec *codec, alc_ssid_check(codec, ssid_nids); if (!spec->no_analog) { - alc_auto_check_switches(codec); + err = alc_auto_check_switches(codec); + if (err < 0) + return err; err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -4372,6 +4364,8 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) codec->spec = spec; spec->mixer_nid = mixer_nid; snd_hda_gen_init(&spec->gen); + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + snd_array_init(&spec->bind_ctls, sizeof(struct hda_bind_ctls *), 8); err = alc_codec_rename_from_preset(codec); if (err < 0) { @@ -6009,6 +6003,16 @@ static void alc269_fixup_mic2_mute(struct hda_codec *codec, } } +static void alc271_hp_gate_mic_jack(struct hda_codec *codec, + const struct alc_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == ALC_FIXUP_ACT_PROBE) + snd_hda_jack_set_gating_jack(codec, spec->ext_mic_pin, + spec->autocfg.hp_pins[0]); +} enum { ALC269_FIXUP_SONY_VAIO, @@ -6031,6 +6035,8 @@ enum { ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, + ALC271_FIXUP_AMIC_MIC2, + ALC271_FIXUP_HP_GATE_MIC_JACK, }; static const struct alc_fixup alc269_fixups[] = { @@ -6175,6 +6181,22 @@ static const struct alc_fixup alc269_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_pincfg_no_hp_to_lineout, }, + [ALC271_FIXUP_AMIC_MIC2] = { + .type = ALC_FIXUP_PINS, + .v.pins = (const struct alc_pincfg[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x19, 0x01a19c20 }, /* mic */ + { 0x1b, 0x99a7012f }, /* int-mic */ + { 0x21, 0x0121401f }, /* HP out */ + { } + }, + }, + [ALC271_FIXUP_HP_GATE_MIC_JACK] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_hp_gate_mic_jack, + .chained = true, + .chain_id = ALC271_FIXUP_AMIC_MIC2, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -6195,6 +6217,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9ba8af0..df13c0f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1081,7 +1081,7 @@ static struct snd_kcontrol_new stac_smux_mixer = { static const char * const slave_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", "PCM", + "Headphone", "Speaker", "Bass Speaker", "IEC958", "PCM", NULL }; @@ -1136,9 +1136,10 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); + err = snd_hda_create_dig_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid, + spec->autocfg.dig_out_type[0]); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, @@ -2515,6 +2516,11 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && + spec->autocfg.line_outs == 2) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; @@ -2805,7 +2811,6 @@ stac_control_new(struct sigmatel_spec *spec, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); knew = snd_array_new(&spec->kctls); if (!knew) return NULL; @@ -3268,9 +3273,9 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, idx = i; break; case AUTO_PIN_SPEAKER_OUT: - if (num_outs <= 1) { - name = "Speaker"; - idx = i; + if (num_outs <= 2) { + name = i ? "Bass Speaker" : "Speaker"; + idx = 0; break; } /* Fall through in case of multi speaker outs */ @@ -4569,8 +4574,6 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - stac92xx_shutup(codec); - kfree(spec); snd_hda_detach_beep_device(codec); } @@ -5155,20 +5158,34 @@ static const struct hda_codec_ops stac92xx_patch_ops = { .reboot_notify = stac92xx_shutup, }; +static int alloc_stac_spec(struct hda_codec *codec, int num_pins, + const hda_nid_t *pin_nids) +{ + struct sigmatel_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ + spec->num_pins = num_pins; + spec->pin_nids = pin_nids; + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + return 0; +} + static int patch_stac9200(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac9200_pin_nids), + stac9200_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); - spec->pin_nids = stac9200_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, stac9200_models, stac9200_cfg_tbl); @@ -5224,15 +5241,13 @@ static int patch_stac925x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac925x_pin_nids), + stac925x_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); - spec->pin_nids = stac925x_pin_nids; /* Check first for codec ID */ spec->board_config = snd_hda_check_board_codec_sid_config(codec, @@ -5307,19 +5322,17 @@ static int patch_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; - int err = 0; + int err; int num_dacs; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac92hd73xx_pin_nids), + stac92hd73xx_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); - spec->pin_nids = stac92hd73xx_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_92HD73XX_MODELS, stac92hd73xx_models, @@ -5596,9 +5609,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) int default_polarity = -1; /* no default cfg */ int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, 0, NULL); /* pins filled later */ + if (err < 0) + return err; if (hp_bnb2011_with_dock(codec)) { snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); @@ -5606,11 +5619,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) } codec->epss = 0; /* longer delay needed for D3 */ - codec->no_trigger_sense = 1; - codec->spec = spec; - stac92hd8x_fill_auto_spec(codec); + spec = codec->spec; spec->linear_tone_beep = 0; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; @@ -5779,21 +5790,19 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) struct sigmatel_spec *spec; const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; unsigned int pin_cfg; - int err = 0; + int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, STAC92HD71BXX_NUM_PINS, + stac92hd71bxx_pin_nids_4port); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; codec->patch_ops = stac92xx_patch_ops; - spec->num_pins = STAC92HD71BXX_NUM_PINS; switch (codec->vendor_id) { case 0x111d76b6: case 0x111d76b7: - spec->pin_nids = stac92hd71bxx_pin_nids_4port; break; case 0x111d7603: case 0x111d7608: @@ -6024,15 +6033,13 @@ static int patch_stac922x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac922x_pin_nids), + stac922x_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); - spec->pin_nids = stac922x_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, stac922x_models, stac922x_cfg_tbl); @@ -6129,16 +6136,14 @@ static int patch_stac927x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac927x_pin_nids), + stac927x_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; codec->slave_dig_outs = stac927x_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); - spec->pin_nids = stac927x_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, stac927x_models, stac927x_cfg_tbl); @@ -6265,15 +6270,13 @@ static int patch_stac9205(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac9205_pin_nids), + stac9205_pin_nids); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); - spec->pin_nids = stac9205_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, stac9205_models, stac9205_cfg_tbl); @@ -6421,14 +6424,13 @@ static int patch_stac9872(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - codec->no_trigger_sense = 1; - codec->spec = spec; + err = alloc_stac_spec(codec, ARRAY_SIZE(stac9872_pin_nids), + stac9872_pin_nids); + if (err < 0) + return err; + + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); - spec->pin_nids = stac9872_pin_nids; spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, stac9872_models, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 019e1a0..dd8cd6a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -241,6 +241,7 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) if (spec == NULL) return NULL; + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); mutex_init(&spec->config_mutex); codec->spec = spec; spec->codec = codec; @@ -387,7 +388,6 @@ static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); knew = snd_array_new(&spec->kctls); if (!knew) return NULL; @@ -739,18 +739,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Disabled", "Enabled" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); } static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, @@ -1454,7 +1443,7 @@ static const struct hda_pcm_stream via_pcm_digital_capture = { */ static const char * const via_slave_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", + "Headphone", "Speaker", "Bass Speaker", NULL, }; @@ -1555,6 +1544,10 @@ static int via_build_pcms(struct hda_codec *codec) spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT + && spec->autocfg.line_outs == 2) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; } if (!spec->stream_analog_capture) { @@ -1934,7 +1927,7 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; struct nid_path *path; static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" + "Front", "Surround", NULL /* "CLFE" */, "Side" }; int i, idx, err; int old_line_outs; @@ -1969,8 +1962,8 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec) } else { const char *pfx = chname[i]; if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs == 1) - pfx = "Speaker"; + cfg->line_outs <= 2) + pfx = i ? "Bass Speaker" : "Speaker"; err = create_ch_ctls(codec, pfx, 3, true, path); if (err < 0) return err; |