diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 64 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_eld.c | 13 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 19 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 23 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 55 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 15 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 44 | ||||
-rw-r--r-- | sound/pci/intel8x0.c | 58 |
10 files changed, 186 insertions, 107 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 916a1863af7..e44b107fdc7 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2331,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } +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, + map_slave_func_t func, void *data) +{ + struct hda_nid_item *items; + const char * const *s; + int i, err; + + items = codec->mixers.list; + for (i = 0; i < codec->mixers.used; i++) { + struct snd_kcontrol *sctl = items[i].kctl; + if (!sctl || !sctl->id.name || + sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) + continue; + for (s = slaves; *s; s++) { + if (!strcmp(sctl->id.name, *s)) { + err = func(data, sctl); + if (err) + return err; + break; + } + } + } + return 0; +} + +static int check_slave_present(void *data, struct snd_kcontrol *sctl) +{ + return 1; +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2351,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char * const *slaves) { struct snd_kcontrol *kctl; - const char * const *s; int err; - for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) - ; - if (!*s) { + err = map_slaves(codec, slaves, check_slave_present, NULL); + if (err != 1) { snd_printdd("No slave found for %s\n", name); return 0; } @@ -2367,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - for (s = slaves; *s; s++) { - struct snd_kcontrol *sctl; - int i = 0; - for (;;) { - sctl = _snd_hda_find_mixer_ctl(codec, *s, i); - if (!sctl) { - if (!i) - snd_printdd("Cannot find slave %s, " - "skipped\n", *s); - break; - } - err = snd_ctl_add_slave(kctl, sctl); - if (err < 0) - return err; - i++; - } - } + err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave, + kctl); + if (err < 0) + return err; return 0; } EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); @@ -4752,6 +4770,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, memset(sequences_hp, 0, sizeof(sequences_hp)); assoc_line_out = 0; + codec->ignore_misc_bit = true; end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { unsigned int wid_caps = get_wcaps(codec, nid); @@ -4767,6 +4786,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + codec->ignore_misc_bit = false; conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) continue; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 755f2b0f9d8..564471169ca 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -854,6 +854,7 @@ struct hda_codec { unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */ 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 */ #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/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 1c8ddf547a2..7ae7578bdcc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -297,10 +297,18 @@ static int hdmi_update_eld(struct hdmi_eld *e, buf + ELD_FIXED_BYTES + mnl + 3 * i); } + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!e->spk_alloc) + e->spk_alloc = 0xffff; + + e->eld_valid = true; return 0; out_fail: - e->eld_ver = 0; return -EINVAL; } @@ -323,9 +331,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, * ELD is valid, actual eld_size is assigned in hdmi_update_eld() */ - if (!eld->eld_valid) - return -ENOENT; - size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index dcbea0da0fa..618ddad1723 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -510,13 +510,15 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) { - return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) && - /* disable MISC_NO_PRESENCE check because it may break too - * many devices - */ - /*(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) & - AC_DEFCFG_MISC_NO_PRESENCE)) &&*/ - (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP); + 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; } /* flags for hda_nid_item */ @@ -651,6 +653,9 @@ struct hdmi_eld { int spk_alloc; int sad_count; struct cea_sad sad[ELD_MAX_SAD]; + /* + * all fields above eld_buffer will be cleared before updating ELD + */ char eld_buffer[ELD_MAX_SIZE]; #ifdef CONFIG_PROC_FS struct snd_info_entry *proc_entry; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 2a2d8645ba0..2fbab8e2957 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); } +static void cs_update_input_select(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + if (spec->cur_adc) + snd_hda_codec_write(codec, spec->cur_adc, 0, + AC_VERB_SET_CONNECT_SEL, + spec->adc_idx[spec->cur_input]); +} + /* * Analog capture */ @@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, spec->cur_adc = spec->adc_nid[spec->cur_input]; spec->cur_adc_stream_tag = stream_tag; spec->cur_adc_format = format; + cs_update_input_select(codec); snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); return 0; } @@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, spec->cur_adc_stream_tag, 0, spec->cur_adc_format); } - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[idx]); spec->cur_input = idx; + cs_update_input_select(codec); return 1; } @@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec) } else { spec->cur_input = spec->last_input; } - - snd_hda_codec_write_cache(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); + cs_update_input_select(codec); } else { if (present) change_cur_input(codec, spec->automic_idx, 0); @@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec) cs_automic(codec); else { spec->cur_adc = spec->adc_nid[spec->cur_input]; - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); + cs_update_input_select(codec); } } else { change_cur_input(codec, spec->cur_input, 1); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5e706e4d173..0de21193a2b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3062,7 +3062,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), - SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5066_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 81b7b791b3c..9850c5b481e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -65,7 +65,10 @@ struct hdmi_spec_per_pin { hda_nid_t pin_nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; + + struct hda_codec *codec; struct hdmi_eld sink_eld; + struct delayed_work work; }; struct hdmi_spec { @@ -745,8 +748,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, * Unsolicited events */ -static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld); +static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry); static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { @@ -755,7 +757,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pd = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); int pin_idx; - struct hdmi_eld *eld; printk(KERN_INFO "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", @@ -764,17 +765,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) pin_idx = pin_nid_to_pin_index(spec, pin_nid); if (pin_idx < 0) return; - eld = &spec->pins[pin_idx].sink_eld; - - hdmi_present_sense(codec, pin_nid, eld); - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!eld->spk_alloc) - eld->spk_alloc = 0xffff; + hdmi_present_sense(&spec->pins[pin_idx], true); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -968,9 +960,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return 0; } -static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_eld *eld) +static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry) { + struct hda_codec *codec = per_pin->codec; + struct hdmi_eld *eld = &per_pin->sink_eld; + hda_nid_t pin_nid = per_pin->pin_nid; /* * Always execute a GetPinSense verb here, even when called from * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited @@ -980,26 +974,39 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, * the unsolicited response to avoid custom WARs. */ int present = snd_hda_pin_sense(codec, pin_nid); + bool eld_valid = false; - memset(eld, 0, sizeof(*eld)); + memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer)); eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); if (eld->monitor_present) - eld->eld_valid = !!(present & AC_PINSENSE_ELDV); - else - eld->eld_valid = 0; + eld_valid = !!(present & AC_PINSENSE_ELDV); printk(KERN_INFO "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); + codec->addr, pin_nid, eld->monitor_present, eld_valid); - if (eld->eld_valid) + if (eld_valid) { if (!snd_hdmi_get_eld(eld, codec, pin_nid)) snd_hdmi_show_eld(eld); + else if (retry) { + queue_delayed_work(codec->bus->workq, + &per_pin->work, + msecs_to_jiffies(300)); + } + } snd_hda_input_jack_report(codec, pin_nid); } +static void hdmi_repoll_eld(struct work_struct *work) +{ + struct hdmi_spec_per_pin *per_pin = + container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); + + hdmi_present_sense(per_pin, false); +} + static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; @@ -1228,7 +1235,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) if (err < 0) return err; - hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld); + hdmi_present_sense(per_pin, false); return 0; } @@ -1279,6 +1286,8 @@ static int generic_hdmi_init(struct hda_codec *codec) AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | pin_nid); + per_pin->codec = codec; + INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); snd_hda_eld_proc_new(codec, eld, pin_idx); } return 0; @@ -1293,10 +1302,12 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_eld *eld = &per_pin->sink_eld; + cancel_delayed_work(&per_pin->work); snd_hda_eld_proc_free(codec, eld); } snd_hda_input_jack_free(codec); + flush_workqueue(codec->bus->workq); kfree(spec); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a24e068a021..336d14eb72a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -284,7 +284,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux; unsigned int mux_idx; - int i, type; + int i, type, num_conns; hda_nid_t nid; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; @@ -307,16 +307,17 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; /* no selection? */ - if (snd_hda_get_conn_list(codec, nid, NULL) <= 1) + num_conns = snd_hda_get_conn_list(codec, nid, NULL); + if (num_conns <= 1) return 1; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, - imux->items[i].index, + int active = imux->items[idx].index; + for (i = 0; i < num_conns; i++) { + unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i, HDA_AMP_MUTE, v); } } else { @@ -1451,7 +1452,7 @@ static void alc_apply_fixup(struct hda_codec *codec, int action) switch (fix->type) { case ALC_FIXUP_SKU: if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku) - break;; + break; snd_printdd(KERN_INFO "hda_codec: %s: " "Apply sku override for %s\n", codec->chip_name, modelname); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4e715fefebe..470f6f286e8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -95,6 +95,7 @@ enum { STAC_92HD83XXX_REF, STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, + STAC_DELL_VOSTRO_3500, STAC_92HD83XXX_HP, STAC_92HD83XXX_HP_cNB11_INTQUAD, STAC_HP_DV7_4000, @@ -226,7 +227,6 @@ struct sigmatel_spec { /* power management */ unsigned int num_pwrs; - const unsigned int *pwr_mapping; const hda_nid_t *pwr_nids; const hda_nid_t *dac_list; @@ -373,18 +373,15 @@ static const unsigned long stac92hd73xx_capvols[] = { #define STAC92HD83_DAC_COUNT 3 -static const hda_nid_t stac92hd83xxx_pwr_nids[4] = { - 0xa, 0xb, 0xd, 0xe, +static const hda_nid_t stac92hd83xxx_pwr_nids[7] = { + 0x0a, 0x0b, 0x0c, 0xd, 0x0e, + 0x0f, 0x10 }; static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { 0x1e, 0, }; -static const unsigned int stac92hd83xxx_pwr_mapping[4] = { - 0x03, 0x0c, 0x20, 0x40, -}; - static const hda_nid_t stac92hd83xxx_dmic_nids[] = { 0x11, 0x20, }; @@ -1659,6 +1656,12 @@ static const unsigned int dell_s14_pin_configs[10] = { 0x40f000f0, 0x40f000f0, }; +static const unsigned int dell_vostro_3500_pin_configs[10] = { + 0x02a11020, 0x0221101f, 0x400000f0, 0x90170110, + 0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160, + 0x400000f4, 0x400000f5, +}; + static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, @@ -1675,6 +1678,7 @@ static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, + [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, }; @@ -1684,6 +1688,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = "ref", [STAC_92HD83XXX_PWR_REF] = "mic-ref", [STAC_DELL_S14] = "dell-s14", + [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500", [STAC_92HD83XXX_HP] = "hp", [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", [STAC_HP_DV7_4000] = "hp-dv7-4000", @@ -1697,6 +1702,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD83XXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028, + "Dell Vostro 3500", STAC_DELL_VOSTRO_3500), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, "HP", STAC_92HD83XXX_HP), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656, @@ -4459,8 +4466,12 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) + if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) { stac_issue_unsol_event(codec, nid); + continue; + } + /* none of the above, turn the port OFF */ + stac_toggle_power_map(codec, nid, 0); } /* sync mute LED */ @@ -4716,11 +4727,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, if (idx >= spec->num_pwrs) return; - /* several codecs have two power down bits */ - if (spec->pwr_mapping) - idx = spec->pwr_mapping[idx]; - else - idx = 1 << idx; + idx = 1 << idx; val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff; if (enable) @@ -5618,9 +5625,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); } - /* reset pin power-down; Windows may leave these bits after reboot */ - snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0); - snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0); codec->no_trigger_sense = 1; codec->spec = spec; @@ -5630,7 +5634,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; spec->pwr_nids = stac92hd83xxx_pwr_nids; - spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->multiout.dac_nids = spec->dac_nids; spec->init = stac92hd83xxx_core_init; @@ -5647,9 +5650,6 @@ again: stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - if (spec->board_config != STAC_92HD83XXX_PWR_REF) - spec->num_pwrs = 0; - codec->patch_ops = stac92xx_patch_ops; if (find_mute_led_gpio(codec, 0)) @@ -5858,8 +5858,6 @@ again: (codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - /* no output amps */ - spec->num_pwrs = 0; /* disable VSW */ spec->init = stac92hd71bxx_core_init; unmute_init++; @@ -5874,8 +5872,6 @@ again: if ((codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - /* no output amps */ - spec->num_pwrs = 0; /* fallthru */ default: spec->init = stac92hd71bxx_core_init; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 29e312597f2..11718b49b2e 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1077,6 +1077,13 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs } if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV)) continue; + + /* IO read operation is very expensive inside virtual machine + * as it is emulated. The probability that subsequent PICB read + * will return different result is high enough to loop till + * timeout here. + * Same CIV is strict enough condition to be sure that PICB + * is valid inside VM on emulated card. */ if (chip->inside_vm) break; if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) @@ -2930,6 +2937,45 @@ static unsigned int sis_codec_bits[3] = { ICH_PCR, ICH_SCR, ICH_SIS_TCR }; +static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci) +{ + int result = inside_vm; + char *msg = NULL; + + /* check module parameter first (override detection) */ + if (result >= 0) { + msg = result ? "enable (forced) VM" : "disable (forced) VM"; + goto fini; + } + + /* detect KVM and Parallels virtual environments */ + result = kvm_para_available(); +#ifdef X86_FEATURE_HYPERVISOR + result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR); +#endif + if (!result) + goto fini; + + /* check for known (emulated) devices */ + if (pci->subsystem_vendor == 0x1af4 && + pci->subsystem_device == 0x1100) { + /* KVM emulated sound, PCI SSID: 1af4:1100 */ + msg = "enable KVM"; + } else if (pci->subsystem_vendor == 0x1ab8) { + /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */ + msg = "enable Parallels VM"; + } else { + msg = "disable (unknown or VT-d) VM"; + result = 0; + } + +fini: + if (msg != NULL) + printk(KERN_INFO "intel8x0: %s optimization\n", msg); + + return result; +} + static int __devinit snd_intel8x0_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, @@ -2997,9 +3043,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, if (xbox) chip->xbox = 1; - chip->inside_vm = inside_vm; - if (inside_vm) - printk(KERN_INFO "intel8x0: enable KVM optimization\n"); + chip->inside_vm = snd_intel8x0_inside_vm(pci); if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) @@ -3243,14 +3287,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, buggy_irq = 0; } - if (inside_vm < 0) { - /* detect KVM and Parallels virtual environments */ - inside_vm = kvm_para_available(); -#if defined(__i386__) || defined(__x86_64__) - inside_vm = inside_vm || boot_cpu_has(X86_FEATURE_HYPERVISOR); -#endif - } - if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); |