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

Commit cd372fb3 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Make common input-jack helper functions



Since multiple codec drivers already use the input-jack stuff, let's
make common helper functions to reduce the duplicated codes.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d207df2d
Loading
Loading
Loading
Loading
+105 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include <sound/asoundef.h>
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/initval.h>
#include <sound/jack.h>
#include "hda_local.h"
#include "hda_local.h"
#include "hda_beep.h"
#include "hda_beep.h"
#include <sound/hda_hwdep.h>
#include <sound/hda_hwdep.h>
@@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
}
}
EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
EXPORT_SYMBOL_HDA(snd_print_pcm_bits);


#ifdef CONFIG_SND_HDA_INPUT_JACK
/*
 * Input-jack notification support
 */
struct hda_jack_item {
	hda_nid_t nid;
	int type;
	struct snd_jack *jack;
};

static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
					 int type)
{
	switch (type) {
	case SND_JACK_HEADPHONE:
		return "Headphone";
	case SND_JACK_MICROPHONE:
		return "Mic";
	case SND_JACK_LINEOUT:
		return "Line-out";
	case SND_JACK_HEADSET:
		return "Headset";
	default:
		return "Misc";
	}
}

static void hda_free_jack_priv(struct snd_jack *jack)
{
	struct hda_jack_item *jacks = jack->private_data;
	jacks->nid = 0;
	jacks->jack = NULL;
}

int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
			   const char *name)
{
	struct hda_jack_item *jack;
	int err;

	snd_array_init(&codec->jacks, sizeof(*jack), 32);
	jack = snd_array_new(&codec->jacks);
	if (!jack)
		return -ENOMEM;

	jack->nid = nid;
	jack->type = type;
	if (!name)
		name = get_jack_default_name(codec, nid, type);
	err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
	if (err < 0) {
		jack->nid = 0;
		return err;
	}
	jack->jack->private_data = jack;
	jack->jack->private_free = hda_free_jack_priv;
	return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);

void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
{
	struct hda_jack_item *jacks = codec->jacks.list;
	int i;

	if (!jacks)
		return;

	for (i = 0; i < codec->jacks.used; i++, jacks++) {
		unsigned int pin_ctl;
		unsigned int present;
		int type;

		if (jacks->nid != nid)
			continue;
		present = snd_hda_jack_detect(codec, nid);
		type = jacks->type;
		if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) {
			pin_ctl = snd_hda_codec_read(codec, nid, 0,
					     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
			type = (pin_ctl & AC_PINCTL_HP_EN) ?
				SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
		}
		snd_jack_report(jacks->jack, present ? type : 0);
	}
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);

/* free jack instances manually when clearing/reconfiguring */
void snd_hda_input_jack_free(struct hda_codec *codec)
{
	if (!codec->bus->shutdown && codec->jacks.list) {
		struct hda_jack_item *jacks = codec->jacks.list;
		int i;
		for (i = 0; i < codec->jacks.used; i++, jacks++) {
			if (jacks->jack)
				snd_device_free(codec->bus->card, jacks->jack);
		}
	}
	snd_array_free(&codec->jacks);
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
#endif /* CONFIG_SND_HDA_INPUT_JACK */

MODULE_DESCRIPTION("HDA codec core");
MODULE_DESCRIPTION("HDA codec core");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
+5 −0
Original line number Original line Diff line number Diff line
@@ -866,6 +866,11 @@ struct hda_codec {
	/* codec-specific additional proc output */
	/* codec-specific additional proc output */
	void (*proc_widget_hook)(struct snd_info_buffer *buffer,
	void (*proc_widget_hook)(struct snd_info_buffer *buffer,
				 struct hda_codec *codec, hda_nid_t nid);
				 struct hda_codec *codec, hda_nid_t nid);

#ifdef CONFIG_SND_HDA_INPUT_JACK
	/* jack detection */
	struct snd_array jacks;
#endif
};
};


/* direction */
/* direction */
+24 −0
Original line number Original line Diff line number Diff line
@@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);


/*
 * Input-jack notification support
 */
#ifdef CONFIG_SND_HDA_INPUT_JACK
int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
			   const char *name);
void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_input_jack_free(struct hda_codec *codec);
#else /* CONFIG_SND_HDA_INPUT_JACK */
static inline int snd_hda_input_jack_add(struct hda_codec *codec,
					 hda_nid_t nid, int type,
					 const char *name)
{
	return 0;
}
static inline void snd_hda_input_jack_report(struct hda_codec *codec,
					     hda_nid_t nid)
{
}
static inline void snd_hda_input_jack_free(struct hda_codec *codec)
{
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */

#endif /* __SOUND_HDA_LOCAL_H */
#endif /* __SOUND_HDA_LOCAL_H */
+14 −110
Original line number Original line Diff line number Diff line
@@ -49,14 +49,6 @@
#define AUTO_MIC_PORTB		(1 << 1)
#define AUTO_MIC_PORTB		(1 << 1)
#define AUTO_MIC_PORTC		(1 << 2)
#define AUTO_MIC_PORTC		(1 << 2)


struct conexant_jack {

	hda_nid_t nid;
	int type;
	struct snd_jack *jack;

};

struct pin_dac_pair {
struct pin_dac_pair {
	hda_nid_t pin;
	hda_nid_t pin;
	hda_nid_t dac;
	hda_nid_t dac;
@@ -111,9 +103,6 @@ struct conexant_spec {


	unsigned int spdif_route;
	unsigned int spdif_route;


	/* jack detection */
	struct snd_array jacks;

	/* dynamic controls, init_verbs and input_mux */
	/* dynamic controls, init_verbs and input_mux */
	struct auto_pin_cfg autocfg;
	struct auto_pin_cfg autocfg;
	struct hda_input_mux private_imux;
	struct hda_input_mux private_imux;
@@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
				     &spec->cur_mux[adc_idx]);
				     &spec->cur_mux[adc_idx]);
}
}


#ifdef CONFIG_SND_HDA_INPUT_JACK
static void conexant_free_jack_priv(struct snd_jack *jack)
{
	struct conexant_jack *jacks = jack->private_data;
	jacks->nid = 0;
	jacks->jack = NULL;
}

static int conexant_add_jack(struct hda_codec *codec,
		hda_nid_t nid, int type)
{
	struct conexant_spec *spec;
	struct conexant_jack *jack;
	const char *name;
	int i, err;

	spec = codec->spec;
	snd_array_init(&spec->jacks, sizeof(*jack), 32);

	jack = spec->jacks.list;
	for (i = 0; i < spec->jacks.used; i++, jack++)
		if (jack->nid == nid)
			return 0 ; /* already present */

	jack = snd_array_new(&spec->jacks);
	name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;

	if (!jack)
		return -ENOMEM;

	jack->nid = nid;
	jack->type = type;

	err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
	if (err < 0)
		return err;
	jack->jack->private_data = jack;
	jack->jack->private_free = conexant_free_jack_priv;
	return 0;
}

static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
	struct conexant_spec *spec = codec->spec;
	struct conexant_jack *jacks = spec->jacks.list;

	if (jacks) {
		int i;
		for (i = 0; i < spec->jacks.used; i++) {
			if (jacks->nid == nid) {
				unsigned int present;
				present = snd_hda_jack_detect(codec, nid);

				present = (present) ? jacks->type : 0 ;

				snd_jack_report(jacks->jack,
						present);
			}
			jacks++;
		}
	}
}

static int conexant_init_jacks(struct hda_codec *codec)
static int conexant_init_jacks(struct hda_codec *codec)
{
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
	struct conexant_spec *spec = codec->spec;
	struct conexant_spec *spec = codec->spec;
	int i;
	int i;


@@ -469,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec)
			int err = 0;
			int err = 0;
			switch (hv->param ^ AC_USRSP_EN) {
			switch (hv->param ^ AC_USRSP_EN) {
			case CONEXANT_HP_EVENT:
			case CONEXANT_HP_EVENT:
				err = conexant_add_jack(codec, hv->nid,
				err = snd_hda_input_jack_add(codec, hv->nid,
						SND_JACK_HEADPHONE);
						SND_JACK_HEADPHONE, NULL);
				conexant_report_jack(codec, hv->nid);
				snd_hda_input_jack_report(codec, hv->nid);
				break;
				break;
			case CXT5051_PORTC_EVENT:
			case CXT5051_PORTC_EVENT:
			case CONEXANT_MIC_EVENT:
			case CONEXANT_MIC_EVENT:
				err = conexant_add_jack(codec, hv->nid,
				err = snd_hda_input_jack_add(codec, hv->nid,
						SND_JACK_MICROPHONE);
						SND_JACK_MICROPHONE, NULL);
				conexant_report_jack(codec, hv->nid);
				snd_hda_input_jack_report(codec, hv->nid);
				break;
				break;
			}
			}
			if (err < 0)
			if (err < 0)
@@ -485,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec)
			++hv;
			++hv;
		}
		}
	}
	}
	return 0;
#endif /* CONFIG_SND_HDA_INPUT_JACK */

}
#else
static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}

static inline int conexant_init_jacks(struct hda_codec *codec)
{
	return 0;
	return 0;
}
}
#endif


static int conexant_init(struct hda_codec *codec)
static int conexant_init(struct hda_codec *codec)
{
{
@@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec)


static void conexant_free(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
	snd_hda_input_jack_free(codec);
	struct conexant_spec *spec = codec->spec;
	if (spec->jacks.list) {
		struct conexant_jack *jacks = spec->jacks.list;
		int i;
		for (i = 0; i < spec->jacks.used; i++, jacks++) {
			if (jacks->jack)
				snd_device_free(codec->bus->card, jacks->jack);
		}
		snd_array_free(&spec->jacks);
	}
#endif
	snd_hda_detach_beep_device(codec);
	snd_hda_detach_beep_device(codec);
	kfree(codec->spec);
	kfree(codec->spec);
}
}
@@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
		cxt5051_portc_automic(codec);
		cxt5051_portc_automic(codec);
		break;
		break;
	}
	}
	conexant_report_jack(codec, nid);
	snd_hda_input_jack_report(codec, nid);
}
}


static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
@@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
	snd_hda_codec_write(codec, nid, 0,
	snd_hda_codec_write(codec, nid, 0,
			    AC_VERB_SET_UNSOLICITED_ENABLE,
			    AC_VERB_SET_UNSOLICITED_ENABLE,
			    AC_USRSP_EN | event);
			    AC_USRSP_EN | event);
#ifdef CONFIG_SND_HDA_INPUT_JACK
	snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
	conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
	snd_hda_input_jack_report(codec, nid);
	conexant_report_jack(codec, nid);
#endif
}
}


static struct hda_verb cxt5051_ideapad_init_verbs[] = {
static struct hda_verb cxt5051_ideapad_init_verbs[] = {
@@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
	switch (res >> 26) {
	switch (res >> 26) {
	case CONEXANT_HP_EVENT:
	case CONEXANT_HP_EVENT:
		cx_auto_hp_automute(codec);
		cx_auto_hp_automute(codec);
		conexant_report_jack(codec, nid);
		snd_hda_input_jack_report(codec, nid);
		break;
		break;
	case CONEXANT_MIC_EVENT:
	case CONEXANT_MIC_EVENT:
		cx_auto_automic(codec);
		cx_auto_automic(codec);
		conexant_report_jack(codec, nid);
		snd_hda_input_jack_report(codec, nid);
		break;
		break;
	}
	}
}
}
+12 −82
Original line number Original line Diff line number Diff line
@@ -282,12 +282,6 @@ struct alc_mic_route {
	unsigned char amix_idx;
	unsigned char amix_idx;
};
};
struct alc_jack {
	hda_nid_t nid;
	int type;
	struct snd_jack *jack;
};
#define MUX_IDX_UNDEF	((unsigned char)-1)
#define MUX_IDX_UNDEF	((unsigned char)-1)
struct alc_customize_define {
struct alc_customize_define {
@@ -366,9 +360,6 @@ struct alc_spec {
	/* PCM information */
	/* PCM information */
	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
	/* jack detection */
	struct snd_array jacks;
	/* dynamic controls, init_verbs and input_mux */
	/* dynamic controls, init_verbs and input_mux */
	struct auto_pin_cfg autocfg;
	struct auto_pin_cfg autocfg;
	struct alc_customize_define cdefine;
	struct alc_customize_define cdefine;
@@ -1032,94 +1023,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
	alc_fix_pll(codec);
	alc_fix_pll(codec);
}
}
#ifdef CONFIG_SND_HDA_INPUT_JACK
static void alc_free_jack_priv(struct snd_jack *jack)
{
	struct alc_jack *jacks = jack->private_data;
	jacks->nid = 0;
	jacks->jack = NULL;
}
static int alc_add_jack(struct hda_codec *codec,
		hda_nid_t nid, int type)
{
	struct alc_spec *spec;
	struct alc_jack *jack;
	const char *name;
	int err;
	spec = codec->spec;
	snd_array_init(&spec->jacks, sizeof(*jack), 32);
	jack = snd_array_new(&spec->jacks);
	if (!jack)
		return -ENOMEM;
	jack->nid = nid;
	jack->type = type;
	name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
	err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
	if (err < 0)
		return err;
	jack->jack->private_data = jack;
	jack->jack->private_free = alc_free_jack_priv;
	return 0;
}
static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
	struct alc_spec *spec = codec->spec;
	struct alc_jack *jacks = spec->jacks.list;
	if (jacks) {
		int i;
		for (i = 0; i < spec->jacks.used; i++) {
			if (jacks->nid == nid) {
				unsigned int present;
				present = snd_hda_jack_detect(codec, nid);
				present = (present) ? jacks->type : 0;
				snd_jack_report(jacks->jack, present);
			}
			jacks++;
		}
	}
}
static int alc_init_jacks(struct hda_codec *codec)
static int alc_init_jacks(struct hda_codec *codec)
{
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
	struct alc_spec *spec = codec->spec;
	struct alc_spec *spec = codec->spec;
	int err;
	int err;
	unsigned int hp_nid = spec->autocfg.hp_pins[0];
	unsigned int hp_nid = spec->autocfg.hp_pins[0];
	unsigned int mic_nid = spec->ext_mic.pin;
	unsigned int mic_nid = spec->ext_mic.pin;
	if (hp_nid) {
	if (hp_nid) {
		err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
		err = snd_hda_input_jack_add(codec, hp_nid,
					     SND_JACK_HEADPHONE, NULL);
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		alc_report_jack(codec, hp_nid);
		snd_hda_input_jack_report(codec, hp_nid);
	}
	}
	if (mic_nid) {
	if (mic_nid) {
		err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
		err = snd_hda_input_jack_add(codec, mic_nid,
					     SND_JACK_MICROPHONE, NULL);
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		alc_report_jack(codec, mic_nid);
		snd_hda_input_jack_report(codec, mic_nid);
	}
	}
#endif /* CONFIG_SND_HDA_INPUT_JACK */
	return 0;
	return 0;
}
}
#else
static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}
static inline int alc_init_jacks(struct hda_codec *codec)
{
	return 0;
}
#endif
static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
{
{
@@ -1133,7 +1062,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
		nid = spec->autocfg.hp_pins[i];
		nid = spec->autocfg.hp_pins[i];
		if (!nid)
		if (!nid)
			break;
			break;
		alc_report_jack(codec, nid);
		snd_hda_input_jack_report(codec, nid);
		spec->jack_present |= snd_hda_jack_detect(codec, nid);
		spec->jack_present |= snd_hda_jack_detect(codec, nid);
	}
	}
@@ -1240,7 +1169,7 @@ static void alc_mic_automute(struct hda_codec *codec)
					  AC_VERB_SET_CONNECT_SEL,
					  AC_VERB_SET_CONNECT_SEL,
					  alive->mux_idx);
					  alive->mux_idx);
	}
	}
	alc_report_jack(codec, spec->ext_mic.pin);
	snd_hda_input_jack_report(codec, spec->ext_mic.pin);
	/* FIXME: analog mixer */
	/* FIXME: analog mixer */
}
}
@@ -4283,6 +4212,7 @@ static void alc_free(struct hda_codec *codec)
		return;
		return;
	alc_shutup(codec);
	alc_shutup(codec);
	snd_hda_input_jack_free(codec);
	alc_free_kctls(codec);
	alc_free_kctls(codec);
	kfree(spec);
	kfree(spec);
	snd_hda_detach_beep_device(codec);
	snd_hda_detach_beep_device(codec);
@@ -14494,7 +14424,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
				 HDA_AMP_MUTE, bits);
				 HDA_AMP_MUTE, bits);
	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
				 HDA_AMP_MUTE, bits);
				 HDA_AMP_MUTE, bits);
	alc_report_jack(codec, nid);
	snd_hda_input_jack_report(codec, nid);
}
}
/* unsolicited event for HP jack sensing */
/* unsolicited event for HP jack sensing */
Loading