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

Commit 111d3af5 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] hda-intel - Automatic correction to single_cmd mode



Modules: HDA Codec driver,HDA Intel driver

Switch to single_cmd mode automatically as a fallback when CORB/RIRB
communication doesn't work well.  It may make the driver working on
some devices with broken BIOS/ACPI support.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 353b9e66
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -531,6 +531,12 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
	bus->caddr_tbl[codec_addr] = codec;

	codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID);
	if (codec->vendor_id == -1)
		/* read again, hopefully the access method was corrected
		 * in the last read...
		 */
		codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
						      AC_PAR_VENDOR_ID);
	codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
	codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);

+43 −17
Original line number Diff line number Diff line
@@ -446,7 +446,7 @@ static void azx_free_cmd_io(struct azx *chip)
}

/* send a command */
static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
			     unsigned int verb, unsigned int para)
{
	struct azx *chip = codec->bus->private_data;
@@ -503,18 +503,21 @@ static void azx_update_rirb(struct azx *chip)
}

/* receive a response */
static unsigned int azx_get_response(struct hda_codec *codec)
static unsigned int azx_rirb_get_response(struct hda_codec *codec)
{
	struct azx *chip = codec->bus->private_data;
	int timeout = 50;

	while (chip->rirb.cmds) {
		if (! --timeout) {
			if (printk_ratelimit())
			snd_printk(KERN_ERR
					"azx_get_response timeout\n");
				   "hda_intel: azx_get_response timeout, "
				   "switching to single_cmd mode...\n");
			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);
			return -1;
		}
		msleep(1);
@@ -578,6 +581,36 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
	return (unsigned int)-1;
}

/*
 * The below are the main callbacks from hda_codec.
 *
 * They are just the skeleton to call sub-callbacks according to the
 * current setting of chip->single_cmd.
 */

/* send a command */
static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
			int direct, unsigned int verb,
			unsigned int para)
{
	struct azx *chip = codec->bus->private_data;
	if (chip->single_cmd)
		return azx_single_send_cmd(codec, nid, direct, verb, para);
	else
		return azx_corb_send_cmd(codec, nid, direct, verb, para);
}

/* get a response */
static unsigned int azx_get_response(struct hda_codec *codec)
{
	struct azx *chip = codec->bus->private_data;
	if (chip->single_cmd)
		return azx_single_get_response(codec);
	else
		return azx_rirb_get_response(codec);
}


/* reset codec link */
static int azx_reset(struct azx *chip)
{
@@ -900,13 +933,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
	bus_temp.private_data = chip;
	bus_temp.modelname = model;
	bus_temp.pci = chip->pci;
	if (chip->single_cmd) {
		bus_temp.ops.command = azx_single_send_cmd;
		bus_temp.ops.get_response = azx_single_get_response;
	} else {
	bus_temp.ops.command = azx_send_cmd;
	bus_temp.ops.get_response = azx_get_response;
	}

	if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0)
		return err;
@@ -1308,7 +1336,6 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
	for (i = 0; i < chip->pcm_devs; i++)
		snd_pcm_suspend_all(chip->pcm[i]);
	snd_hda_suspend(chip->bus, state);
	if (! chip->single_cmd)
	azx_free_cmd_io(chip);
	pci_disable_device(pci);
	pci_save_state(pci);
@@ -1347,7 +1374,6 @@ static int azx_free(struct azx *chip)
		azx_int_clear(chip);

		/* disable CORB/RIRB */
		if (! chip->single_cmd)
		azx_free_cmd_io(chip);

		/* disable position buffer */