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

Commit 26a6cb6c authored by David Henningsson's avatar David Henningsson Committed by Takashi Iwai
Browse files

ALSA: hda - Implement a poll loop for jacks as a module parameter



Now that we have a generic unsol mechanism, we can implement a generic
poll loop, which can be used for debugging, or if a codec's unsol
mechanism is broken.

Signed-off-by: default avatarDavid Henningsson <david.henningsson@canonical.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 239fb862
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -1135,6 +1135,19 @@ static void restore_shutup_pins(struct hda_codec *codec)
}
#endif

static void hda_jackpoll_work(struct work_struct *work)
{
	struct hda_codec *codec =
		container_of(work, struct hda_codec, jackpoll_work.work);
	if (!codec->jackpoll_interval)
		return;

	snd_hda_jack_set_dirty_all(codec);
	snd_hda_jack_poll_all(codec);
	queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
			   codec->jackpoll_interval);
}

static void init_hda_cache(struct hda_cache_rec *cache,
			   unsigned int record_size);
static void free_hda_cache(struct hda_cache_rec *cache);
@@ -1190,6 +1203,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
{
	if (!codec)
		return;
	cancel_delayed_work_sync(&codec->jackpoll_work);
	snd_hda_jack_tbl_clear(codec);
	restore_init_pincfgs(codec);
#ifdef CONFIG_PM
@@ -1273,6 +1287,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
	snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
	INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);

#ifdef CONFIG_PM
	spin_lock_init(&codec->power_lock);
@@ -2349,7 +2364,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
		return -EBUSY;

	/* OK, let it free */

	cancel_delayed_work_sync(&codec->jackpoll_work);
#ifdef CONFIG_PM
	cancel_delayed_work_sync(&codec->power_work);
	codec->power_on = 0;
@@ -3646,7 +3661,6 @@ static void hda_call_codec_resume(struct hda_codec *codec)
	restore_pincfgs(codec); /* restore all current pin configs */
	restore_shutup_pins(codec);
	hda_exec_init_verbs(codec);
	snd_hda_jack_set_dirty_all(codec);
	if (codec->patch_ops.resume)
		codec->patch_ops.resume(codec);
	else {
@@ -3655,7 +3669,13 @@ static void hda_call_codec_resume(struct hda_codec *codec)
		snd_hda_codec_resume_amp(codec);
		snd_hda_codec_resume_cache(codec);
	}

	if (codec->jackpoll_interval)
		hda_jackpoll_work(&codec->jackpoll_work.work);
	else {
		snd_hda_jack_set_dirty_all(codec);
		snd_hda_jack_report_sync(codec);
	}
	snd_hda_power_down(codec); /* flag down before returning */
}
#endif /* CONFIG_PM */
@@ -3737,6 +3757,9 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
	if (err < 0)
		return err;

	if (codec->jackpoll_interval)
		hda_jackpoll_work(&codec->jackpoll_work.work);
	else
		snd_hda_jack_report_sync(codec); /* call at the last init point */
	return 0;
}
@@ -5128,6 +5151,7 @@ int snd_hda_suspend(struct hda_bus *bus)
	struct hda_codec *codec;

	list_for_each_entry(codec, &bus->codec_list, list) {
		cancel_delayed_work_sync(&codec->jackpoll_work);
		if (hda_codec_is_power_on(codec))
			hda_call_codec_suspend(codec, false);
	}
+2 −0
Original line number Diff line number Diff line
@@ -884,6 +884,8 @@ struct hda_codec {

	/* jack detection */
	struct snd_array jacktbl;
	unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */
	struct delayed_work jackpoll_work;

#ifdef CONFIG_SND_HDA_INPUT_JACK
	/* jack detection */
+20 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS];
static int jackpoll_ms[SNDRV_CARDS];
static bool single_cmd;
static int enable_msi = -1;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
@@ -95,6 +96,8 @@ module_param_array(probe_mask, int, NULL, 0444);
MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
module_param_array(probe_only, int, NULL, 0444);
MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
module_param_array(jackpoll_ms, int, NULL, 0444);
MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
module_param(single_cmd, bool, 0444);
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
		 "(for debugging only).");
@@ -1582,6 +1585,22 @@ static void azx_bus_reset(struct hda_bus *bus)
	bus->in_reset = 0;
}

static int get_jackpoll_interval(struct azx *chip)
{
	int i = jackpoll_ms[chip->dev_index];
	unsigned int j;
	if (i == 0)
		return 0;
	if (i < 50 || i > 60000)
		j = 0;
	else
		j = msecs_to_jiffies(i);
	if (j == 0)
		snd_printk(KERN_WARNING SFX
			   "jackpoll_ms value out of range: %d\n", i);
	return j;
}

/*
 * Codec initialization
 */
@@ -1666,6 +1685,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode
			err = snd_hda_codec_new(chip->bus, c, &codec);
			if (err < 0)
				continue;
			codec->jackpoll_interval = get_jackpoll_interval(chip);
			codec->beep_mode = chip->beep_mode;
			codecs++;
		}
+22 −0
Original line number Diff line number Diff line
@@ -439,3 +439,25 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
}
EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event);

void snd_hda_jack_poll_all(struct hda_codec *codec)
{
	struct hda_jack_tbl *jack = codec->jacktbl.list;
	int i, changes = 0;

	for (i = 0; i < codec->jacktbl.used; i++, jack++) {
		unsigned int old_sense;
		if (!jack->nid || !jack->jack_dirty || jack->phantom_jack)
			continue;
		old_sense = get_jack_plug_state(jack->pin_sense);
		jack_detect_update(codec, jack);
		if (old_sense == get_jack_plug_state(jack->pin_sense))
			continue;
		changes = 1;
		if (jack->callback)
			jack->callback(codec, jack);
	}
	if (changes)
		snd_hda_jack_report_sync(codec);
}
EXPORT_SYMBOL_HDA(snd_hda_jack_poll_all);
+2 −0
Original line number Diff line number Diff line
@@ -84,4 +84,6 @@ void snd_hda_jack_report_sync(struct hda_codec *codec);

void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);

void snd_hda_jack_poll_all(struct hda_codec *codec);

#endif /* __SOUND_HDA_JACK_H */