diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 66a7d3de9fa0..b649033a4c81 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -175,14 +175,23 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, unsigned int verb, unsigned int parm) { struct hda_bus *bus = codec->bus; - unsigned int res; + unsigned int cmd, res; + int repeated = 0; - res = make_codec_cmd(codec, nid, direct, verb, parm); + cmd = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); - if (!bus->ops.command(bus, res)) + again: + if (!bus->ops.command(bus, cmd)) { res = bus->ops.get_response(bus); - else + if (res == -1 && bus->rirb_error) { + if (repeated++ < 1) { + snd_printd(KERN_WARNING "hda_codec: " + "Trying verb 0x%08x again\n", cmd); + goto again; + } + } + } else res = (unsigned int)-1; mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); @@ -1056,6 +1065,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* FIXME: more better hash key? */ #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) +#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) +#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) #define INFO_AMP_CAPS (1<<0) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) @@ -1146,19 +1157,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, } EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); -u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) +static unsigned int +query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, + unsigned int (*func)(struct hda_codec *, hda_nid_t)) { struct hda_amp_info *info; - info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); + info = get_alloc_amp_hash(codec, key); if (!info) return 0; if (!info->head.val) { - info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); info->head.val |= INFO_AMP_CAPS; + info->amp_caps = func(codec, nid); } return info->amp_caps; } + +static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); +} + +u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), + read_pin_cap); +} EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); /* @@ -2547,6 +2571,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); +static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int val = 0; + if (nid != codec->afg && + (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (!val || val == -1) + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + if (!val || val == -1) + return 0; + return val; +} + +static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), + get_pcm_param); +} + +static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (!streams || streams == -1) + streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); + if (!streams || streams == -1) + return 0; + return streams; +} + +static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), + get_stream_param); +} + /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats * @codec: the HDA codec @@ -2565,15 +2624,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, { unsigned int i, val, wcaps; - val = 0; wcaps = get_wcaps(codec, nid); - if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return -EIO; - } - if (!val) - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + val = query_pcm_param(codec, nid); if (ratesp) { u32 rates = 0; @@ -2595,15 +2647,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u64 formats = 0; unsigned int streams, bps; - streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (streams == -1) + streams = query_stream_param(codec, nid); + if (!streams) return -EIO; - if (!streams) { - streams = snd_hda_param_read(codec, codec->afg, - AC_PAR_STREAM); - if (streams == -1) - return -EIO; - } bps = 0; if (streams & AC_SUPFMT_PCM) { @@ -2677,17 +2723,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, int i; unsigned int val = 0, rate, stream; - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return 0; - } - if (!val) { - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - if (val == -1) - return 0; - } + val = query_pcm_param(codec, nid); + if (!val) + return 0; rate = format & 0xff00; for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) @@ -2699,12 +2737,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, if (i >= AC_PAR_PCM_RATE_BITS) return 0; - stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (stream == -1) - return 0; - if (!stream && nid != codec->afg) - stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (!stream || stream == -1) + stream = query_stream_param(codec, nid); + if (!stream) return 0; if (stream & AC_SUPFMT_PCM) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2fdecf4b0eb6..cd8979c7670b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -623,6 +623,7 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; unsigned int shutdown :1; /* being unloaded */ + unsigned int rirb_error:1; /* error in codec communication */ }; /* diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 41db5d4da478..04f19f8cad84 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -606,6 +606,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (!chip->rirb.cmds) { smp_rmb(); + bus->rirb_error = 0; return chip->rirb.res; /* the last value */ } if (time_after(jiffies, timeout)) @@ -625,8 +626,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) chip->irq = -1; pci_disable_msi(chip->pci); chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) + if (azx_acquire_irq(chip, 1) < 0) { + bus->rirb_error = 1; return -1; + } goto again; } @@ -646,14 +649,12 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) return -1; } - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " - "switching to single_cmd mode: last cmd=0x%08x\n", - chip->last_cmd); - chip->rirb.rp = azx_readb(chip, RIRBWP); - chip->rirb.cmds = 0; - /* switch to single_cmd mode */ - chip->single_cmd = 1; - azx_free_cmd_io(chip); + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout (ERROR): " + "last cmd=0x%08x\n", chip->last_cmd); + spin_lock_irq(&chip->reg_lock); + chip->rirb.cmds = 0; /* reset the index */ + bus->rirb_error = 1; + spin_unlock_irq(&chip->reg_lock); return -1; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c9300a3427ea..a6ec87a5c066 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1024,6 +1024,9 @@ static void alc_subsystem_id(struct hda_codec *codec, if (codec->vendor_id == 0x10ec0260) nid = 0x17; ass = snd_hda_codec_get_pincfg(codec, nid); + snd_printd("realtek: No valid SSID, " + "checking pincfg 0x%08x for NID 0x%x\n", + nid, ass); if (!(ass & 1) && !(ass & 0x100000)) return; if ((ass >> 30) != 1) /* no physical connection */ @@ -1038,6 +1041,8 @@ static void alc_subsystem_id(struct hda_codec *codec, if (((ass >> 16) & 0xf) != tmp) return; do_sku: + snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", + ass & 0xffff, codec->vendor_id); /* * 0 : override * 1 : Swap Jack