diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-08-09 14:30:13 (GMT) |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-08-09 14:30:13 (GMT) |
commit | 5f1890897cd184cc9a0000476279fd01d572ff4b (patch) | |
tree | 25ce10b71ec25a4a5ca01f12f1bececc3f9a75eb /sound | |
parent | 793ea49c476ebacfefabf78af9ea88a19da6ecdb (diff) | |
parent | 5cb543dba9867588786f87af2e64fca371b69283 (diff) | |
download | linux-5f1890897cd184cc9a0000476279fd01d572ff4b.tar.xz |
Merge branch 'topic/hda-probe-defer' into for-next
This branch fixes the stall during probing the HD-audio driver when
the specified "patch" firmware doesn't exist. It's basically a long-
standing issue, but mostly harmless until the recent rework of
firmware loader base code.
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 39 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 69 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 12 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 8 |
9 files changed, 100 insertions, 50 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 647218d..4f7d2df 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -332,13 +332,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, if (cfg->dig_outs) snd_printd(" dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs:"); + snd_printd(" inputs:\n"); for (i = 0; i < cfg->num_inputs; i++) { - snd_printd(" %s=0x%x", + snd_printd(" %s=0x%x\n", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } - snd_printd("\n"); if (cfg->dig_in_pin) snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 88a9c20..408babc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4184,7 +4184,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) * * This function returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_build_pcms(struct hda_bus *bus) +int snd_hda_build_pcms(struct hda_bus *bus) { struct hda_codec *codec; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c422d33..39e43753 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -1072,7 +1072,7 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} /* * patch firmware */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch); +int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf); #endif /* diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6b2efb8..b9a644c 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -25,7 +25,6 @@ #include <linux/mutex.h> #include <linux/ctype.h> #include <linux/string.h> -#include <linux/firmware.h> #include <linux/export.h> #include <sound/core.h> #include "hda_codec.h" @@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus) * * the spaces at the beginning and the end of the line are stripped */ -static int get_line_from_fw(char *buf, int size, struct firmware *fw) +static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, + const void **fw_data_p) { int len; - const char *p = fw->data; - while (isspace(*p) && fw->size) { + size_t fw_size = *fw_size_p; + const char *p = *fw_data_p; + + while (isspace(*p) && fw_size) { p++; - fw->size--; + fw_size--; } - if (!fw->size) + if (!fw_size) return 0; - for (len = 0; len < fw->size; len++) { + for (len = 0; len < fw_size; len++) { if (!*p) break; if (*p == '\n') { @@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw) *buf++ = *p++; } *buf = 0; - fw->size -= len; - fw->data = p; + *fw_size_p = fw_size - len; + *fw_data_p = p; remove_trail_spaces(buf); return 1; } @@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw) /* * load a "patch" firmware file and parse it */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch) +int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) { - int err; - const struct firmware *fw; - struct firmware tmp; char buf[128]; struct hda_codec *codec; int line_mode; - struct device *dev = bus->card->dev; - - if (snd_BUG_ON(!dev)) - return -ENODEV; - err = request_firmware(&fw, patch, dev); - if (err < 0) { - printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n", - patch); - return err; - } - tmp = *fw; line_mode = LINE_MODE_NONE; codec = NULL; - while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) { + while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) { if (!*buf || *buf == '#' || *buf == '\n') continue; if (*buf == '[') @@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch) (codec || !patch_items[line_mode].need_codec)) patch_items[line_mode].parser(buf, bus, &codec); } - release_firmware(fw); return 0; } EXPORT_SYMBOL_HDA(snd_hda_load_patch); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c8aced1..3de3a5c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -55,6 +55,7 @@ #include <sound/initval.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> +#include <linux/firmware.h> #include "hda_codec.h" @@ -470,6 +471,10 @@ struct azx { struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; +#ifdef CONFIG_SND_HDA_PATCH_LOADER + const struct firmware *fw; +#endif + /* flags */ int position_fix[2]; /* for both playback/capture streams */ int poll_count; @@ -559,13 +564,17 @@ enum { * VGA-switcher support */ #ifdef SUPPORT_VGA_SWITCHEROO +#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) +#else +#define use_vga_switcheroo(chip) 0 +#endif + +#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER) #define DELAYED_INIT_MARK #define DELAYED_INITDATA_MARK -#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) #else #define DELAYED_INIT_MARK __devinit #define DELAYED_INITDATA_MARK __devinitdata -#define use_vga_switcheroo(chip) 0 #endif static char *driver_short_names[] DELAYED_INITDATA_MARK = { @@ -2639,6 +2648,10 @@ static int azx_free(struct azx *chip) pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip->azx_dev); +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (chip->fw) + release_firmware(chip->fw); +#endif kfree(chip); return 0; @@ -3146,12 +3159,38 @@ static void power_down_all_codecs(struct azx *chip) #endif } +/* callback from request_firmware_nowait() */ +static void azx_firmware_cb(const struct firmware *fw, void *context) +{ + struct snd_card *card = context; + struct azx *chip = card->private_data; + struct pci_dev *pci = chip->pci; + + if (!fw) { + snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n"); + goto error; + } + + chip->fw = fw; + if (!chip->disabled) { + /* continue probing */ + if (azx_probe_continue(chip)) + goto error; + } + return; /* OK */ + + error: + snd_card_free(card); + pci_set_drvdata(pci, NULL); +} + static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; struct azx *chip; + bool probe_now; int err; if (dev >= SNDRV_CARDS) @@ -3167,15 +3206,28 @@ static int __devinit azx_probe(struct pci_dev *pci, return err; } - /* set this here since it's referred in snd_hda_load_patch() */ snd_card_set_dev(card, &pci->dev); err = azx_create(card, pci, dev, pci_id->driver_data, &chip); if (err < 0) goto out_free; card->private_data = chip; + probe_now = !chip->disabled; - if (!chip->disabled) { +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (patch[dev] && *patch[dev]) { + snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", + patch[dev]); + err = request_firmware_nowait(THIS_MODULE, true, patch[dev], + &pci->dev, GFP_KERNEL, card, + azx_firmware_cb); + if (err < 0) + goto out_free; + probe_now = false; /* continued in azx_firmware_cb() */ + } +#endif /* CONFIG_SND_HDA_PATCH_LOADER */ + + if (probe_now) { err = azx_probe_continue(chip); if (err < 0) goto out_free; @@ -3205,12 +3257,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) if (err < 0) goto out_free; #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (patch[dev] && *patch[dev]) { - snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", - patch[dev]); - err = snd_hda_load_patch(chip->bus, patch[dev]); + if (chip->fw) { + err = snd_hda_load_patch(chip->bus, chip->fw->size, + chip->fw->data); if (err < 0) goto out_free; + release_firmware(chip->fw); /* no longer needed */ + chip->fw = NULL; } #endif if ((probe_only[dev] & 1) == 0) { diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1436118..5e22a8f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2967,12 +2967,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { }; static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO), SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), @@ -2988,14 +2986,10 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO), - SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), - SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO), {} }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 69b9284..8f23374 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -877,8 +877,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; - hinfo->nid = 0; /* clear the leftover value */ - /* Validate hinfo */ pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) @@ -1163,6 +1161,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } +static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + return 0; +} + static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -1202,6 +1208,7 @@ static const struct hda_pcm_ops generic_ops = { .open = hdmi_pcm_open, .close = hdmi_pcm_close, .prepare = generic_hdmi_playback_pcm_prepare, + .cleanup = generic_hdmi_playback_pcm_cleanup, }; static int generic_hdmi_build_pcms(struct hda_codec *codec) @@ -1220,7 +1227,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr->substreams = 1; pstr->ops = generic_ops; - pstr->nid = 1; /* FIXME: just for avoiding a debug WARNING */ /* other pstr fields are set in open */ } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b9a5c45..4f81dd4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6099,6 +6099,8 @@ static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_PCM_44K] = { .type = ALC_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, + .chained = true, + .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_STEREO_DMIC] = { .type = ALC_FIXUP_FUNC, @@ -6207,9 +6209,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), #if 0 diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 80d90cb..4307717 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1752,6 +1752,14 @@ static int via_suspend(struct hda_codec *codec) { struct via_spec *spec = codec->spec; vt1708_stop_hp_work(spec); + + if (spec->codec_type == VT1802) { + /* Fix pop noise on headphones */ + int i; + for (i = 0; i < spec->autocfg.hp_outs; i++) + snd_hda_set_pin_ctl(codec, spec->autocfg.hp_pins[i], 0); + } + return 0; } #endif |