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

Commit 1a4f69d5 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Allow multiple callbacks for jack



So far, hda_jack infrastructure allows only one callback per jack, and
this makes things slightly complicated when a driver wants to assign
multiple tasks to a jack, e.g. the standard auto-mute with a power
up/down sequence.  This can be simplified if the hda_jack accepts
multiple callbacks.

This patch is such an extension: the callback-specific part (the
function and private_data) is split to another struct from
hda_jack_tbl, and multiple such objects can be assigned to a single
hda_jack_tbl entry.

The new struct hda_jack_callback is passed to each callback function
now, thus the patch became bigger than expected.  But these changes
are mostly trivial.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bda17b82
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -2032,7 +2032,8 @@ static int create_speaker_out_ctls(struct hda_codec *codec)
 * independent HP controls
 */

static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack);
static void call_hp_automute(struct hda_codec *codec,
			     struct hda_jack_callback *jack);
static int indep_hp_info(struct snd_kcontrol *kcontrol,
			 struct snd_ctl_elem_info *uinfo)
{
@@ -3948,7 +3949,8 @@ static void call_update_outputs(struct hda_codec *codec)
}

/* standard HP-automute helper */
void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
void snd_hda_gen_hp_automute(struct hda_codec *codec,
			     struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;
	hda_nid_t *pins = spec->autocfg.hp_pins;
@@ -3968,7 +3970,8 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);

/* standard line-out-automute helper */
void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
void snd_hda_gen_line_automute(struct hda_codec *codec,
			       struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;

@@ -3988,7 +3991,8 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jac
EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);

/* standard mic auto-switch helper */
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
				struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;
	int i;
@@ -4011,7 +4015,8 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);

/* call appropriate hooks */
static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
static void call_hp_automute(struct hda_codec *codec,
			     struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;
	if (spec->hp_automute_hook)
@@ -4021,7 +4026,7 @@ static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
}

static void call_line_automute(struct hda_codec *codec,
			       struct hda_jack_tbl *jack)
			       struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;
	if (spec->line_automute_hook)
@@ -4031,7 +4036,7 @@ static void call_line_automute(struct hda_codec *codec,
}

static void call_mic_autoswitch(struct hda_codec *codec,
				struct hda_jack_tbl *jack)
				struct hda_jack_callback *jack)
{
	struct hda_gen_spec *spec = codec->spec;
	if (spec->mic_autoswitch_hook)
+6 −6
Original line number Diff line number Diff line
@@ -284,11 +284,11 @@ struct hda_gen_spec {

	/* automute / autoswitch hooks */
	void (*hp_automute_hook)(struct hda_codec *codec,
				 struct hda_jack_tbl *tbl);
				 struct hda_jack_callback *cb);
	void (*line_automute_hook)(struct hda_codec *codec,
				   struct hda_jack_tbl *tbl);
				   struct hda_jack_callback *cb);
	void (*mic_autoswitch_hook)(struct hda_codec *codec,
				    struct hda_jack_tbl *tbl);
				    struct hda_jack_callback *cb);
};

int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
@@ -320,11 +320,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec);

/* standard jack event callbacks */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
			     struct hda_jack_tbl *jack);
			     struct hda_jack_callback *jack);
void snd_hda_gen_line_automute(struct hda_codec *codec,
			       struct hda_jack_tbl *jack);
			       struct hda_jack_callback *jack);
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
				struct hda_jack_tbl *jack);
				struct hda_jack_callback *jack);
void snd_hda_gen_update_outputs(struct hda_codec *codec);

#ifdef CONFIG_PM
+38 −20
Original line number Diff line number Diff line
@@ -111,17 +111,21 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)

void snd_hda_jack_tbl_clear(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
	/* free jack instances manually when clearing/reconfiguring */
	if (!codec->bus->shutdown && codec->jacktbl.list) {
	struct hda_jack_tbl *jack = codec->jacktbl.list;
	int i;

	for (i = 0; i < codec->jacktbl.used; i++, jack++) {
			if (jack->jack)
		struct hda_jack_callback *cb, *next;
#ifdef CONFIG_SND_HDA_INPUT_JACK
		/* free jack instances manually when clearing/reconfiguring */
		if (!codec->bus->shutdown && jack->jack)
			snd_device_free(codec->bus->card, jack->jack);
#endif
		for (cb = jack->callback; cb; cb = next) {
			next = cb->next;
			kfree(cb);
		}
	}
#endif
	snd_array_free(&codec->jacktbl);
}

@@ -219,28 +223,38 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
 * errno.  Check and handle the return value appropriately with standard
 * macros such as @IS_ERR() and @PTR_ERR().
 */
struct hda_jack_tbl *
struct hda_jack_callback *
snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
				    hda_jack_callback cb)
				    hda_jack_callback_fn func)
{
	struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
	struct hda_jack_tbl *jack;
	struct hda_jack_callback *callback = NULL;
	int err;

	jack = snd_hda_jack_tbl_new(codec, nid);
	if (!jack)
		return ERR_PTR(-ENOMEM);
	if (func) {
		callback = kzalloc(sizeof(*callback), GFP_KERNEL);
		if (!callback)
			return ERR_PTR(-ENOMEM);
		callback->func = func;
		callback->tbl = jack;
		callback->next = jack->callback;
		jack->callback = callback;
	}

	if (jack->jack_detect)
		return jack; /* already registered */
		return callback; /* already registered */
	jack->jack_detect = 1;
	if (cb)
		jack->callback = cb;
	if (codec->jackpoll_interval > 0)
		return jack; /* No unsol if we're polling instead */
		return callback; /* No unsol if we're polling instead */
	err = snd_hda_codec_write_cache(codec, nid, 0,
					 AC_VERB_SET_UNSOLICITED_ENABLE,
					 AC_USRSP_EN | jack->tag);
	if (err < 0)
		return ERR_PTR(err);
	return jack;
	return callback;
}
EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);

@@ -503,13 +517,17 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
static void call_jack_callback(struct hda_codec *codec,
			       struct hda_jack_tbl *jack)
{
	if (jack->callback)
		jack->callback(codec, jack);
	struct hda_jack_callback *cb;

	for (cb = jack->callback; cb; cb = cb->next)
		cb->func(codec, cb);
	if (jack->gated_jack) {
		struct hda_jack_tbl *gated =
			snd_hda_jack_tbl_get(codec, jack->gated_jack);
		if (gated && gated->callback)
			gated->callback(codec, gated);
		if (gated) {
			for (cb = gated->callback; cb; cb = cb->next)
				cb->func(codec, cb);
		}
	}
}

+12 −5
Original line number Diff line number Diff line
@@ -14,14 +14,21 @@

struct auto_pin_cfg;
struct hda_jack_tbl;
struct hda_jack_callback;

typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *);
typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *);

struct hda_jack_callback {
	struct hda_jack_tbl *tbl;
	hda_jack_callback_fn func;
	unsigned int private_data;	/* arbitrary data */
	struct hda_jack_callback *next;
};

struct hda_jack_tbl {
	hda_nid_t nid;
	unsigned char tag;		/* unsol event tag */
	unsigned int private_data;	/* arbitrary data */
	hda_jack_callback callback;
	struct hda_jack_callback *callback;
	/* jack-detection stuff */
	unsigned int pin_sense;		/* cached pin-sense value */
	unsigned int jack_detect:1;	/* capable of jack-detection? */
@@ -47,9 +54,9 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec);
void snd_hda_jack_set_dirty_all(struct hda_codec *codec);

int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid);
struct hda_jack_tbl *
struct hda_jack_callback *
snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
				    hda_jack_callback cb);
				    hda_jack_callback_fn cb);

int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
				 hda_nid_t gating_nid);
+1 −1
Original line number Diff line number Diff line
@@ -982,7 +982,7 @@ static void cs4210_pinmux_init(struct hda_codec *codec)
}

static void cs4210_spdif_automute(struct hda_codec *codec,
				  struct hda_jack_tbl *tbl)
				  struct hda_jack_callback *tbl)
{
	struct cs_spec *spec = codec->spec;
	bool spdif_present = false;
Loading