Merge branch 'topic/hda-probe-defer' into for-next
authorTakashi Iwai <tiwai@suse.de>
Thu, 9 Aug 2012 14:30:13 +0000 (16:30 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 9 Aug 2012 14:30:13 +0000 (16:30 +0200)
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.

sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_via.c

index 647218d69f6890862b5fcfd690dc9e09d29bc3ea..4f7d2dfcef7b16357ead4185b7b62e3463d5f1a5 100644 (file)
@@ -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);
 
index 88a9c20eb7a29cbff43745f5a64afefefb52b76e..408babc1043764d9bbf487502e148be5662d652e 100644 (file)
@@ -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;
 
index c422d330ca54fe018379e5b14b24dcd03a4e208e..39e43753ddbf4f692d0ac1f05d954f2c83e6ba3d 100644 (file)
@@ -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
 
 /*
index 6b2efb8cb1f9c6bded4e7d318467f8825be75903..b9a644ca03b34faee8940a6ebbfcc74bce40e9fc 100644 (file)
@@ -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);
index c8aced182fd15738cf165505d532e24e89bcd906..3de3a5cbf1dced0b1a2408d22bfb945278bc555e 100644 (file)
@@ -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) {
index 14361184ae1e0e17ac2483dcac3c525289369f1f..5e22a8f43d2eebc288083142b355feffb61ffedb 100644 (file)
@@ -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),
        {}
 };
 
index 69b928449789e22afcaef39a67dea3323bc5e5e7..8f23374fa6427198735f91b987656986052a8773 100644 (file)
@@ -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 */
        }
 
index b9a5c45033367429a532e55ae14e6888bd53eb62..4f81dd44c837e1de6b1de327f457bcb0fcc8f16f 100644 (file)
@@ -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
index 80d90cb42853bd50abfac7349361142e71185a7c..43077177691588ab03590cd0576369c54b55d266 100644 (file)
@@ -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