Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f189089 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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.
parents 793ea49c 5cb543db
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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

/*
+13 −26
Original line number Diff line number Diff line
@@ -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);
+61 −8
Original line number Diff line number Diff line
@@ -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) {
Loading