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

Commit 3911a4c1 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Takashi Iwai
Browse files

ALSA: hda - proc - introduce Control: lines to show mixer<->NID assignment



This is an initial patch to show universal control<->NID assigment in
proc codec file. The change helps to debug codec related problems.

Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2dca0bba
Loading
Loading
Loading
Loading
+17 −15
Original line number Original line Diff line number Diff line
@@ -946,7 +946,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
	mutex_init(&codec->control_mutex);
	mutex_init(&codec->control_mutex);
	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
	snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
	if (codec->bus->modelname) {
	if (codec->bus->modelname) {
@@ -1517,18 +1517,20 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);


/* Add a control element and assign to the codec */
/* Add a control element and assign to the codec */
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
		    struct snd_kcontrol *kctl)
{
{
	int err;
	int err;
	struct snd_kcontrol **knewp;
	struct hda_nid_item *item;


	err = snd_ctl_add(codec->bus->card, kctl);
	err = snd_ctl_add(codec->bus->card, kctl);
	if (err < 0)
	if (err < 0)
		return err;
		return err;
	knewp = snd_array_new(&codec->mixers);
	item = snd_array_new(&codec->mixers);
	if (!knewp)
	if (!item)
		return -ENOMEM;
		return -ENOMEM;
	*knewp = kctl;
	item->kctl = kctl;
	item->nid = nid;
	return 0;
	return 0;
}
}
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
@@ -1537,9 +1539,9 @@ EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
void snd_hda_ctls_clear(struct hda_codec *codec)
void snd_hda_ctls_clear(struct hda_codec *codec)
{
{
	int i;
	int i;
	struct snd_kcontrol **kctls = codec->mixers.list;
	struct hda_nid_item *items = codec->mixers.list;
	for (i = 0; i < codec->mixers.used; i++)
	for (i = 0; i < codec->mixers.used; i++)
		snd_ctl_remove(codec->bus->card, kctls[i]);
		snd_ctl_remove(codec->bus->card, items[i].kctl);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->mixers);
}
}


@@ -1645,7 +1647,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
	kctl = snd_ctl_make_virtual_master(name, tlv);
	kctl = snd_ctl_make_virtual_master(name, tlv);
	if (!kctl)
	if (!kctl)
		return -ENOMEM;
		return -ENOMEM;
	err = snd_hda_ctl_add(codec, kctl);
	err = snd_hda_ctl_add(codec, 0, kctl);
	if (err < 0)
	if (err < 0)
		return err;
		return err;
	
	
@@ -2139,7 +2141,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
			return -ENOMEM;
			return -ENOMEM;
		kctl->id.index = idx;
		kctl->id.index = idx;
		kctl->private_value = nid;
		kctl->private_value = nid;
		err = snd_hda_ctl_add(codec, kctl);
		err = snd_hda_ctl_add(codec, nid, kctl);
		if (err < 0)
		if (err < 0)
			return err;
			return err;
	}
	}
@@ -2184,7 +2186,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
	if (!mout->dig_out_nid)
	if (!mout->dig_out_nid)
		return 0;
		return 0;
	/* ATTENTION: here mout is passed as private_data, instead of codec */
	/* ATTENTION: here mout is passed as private_data, instead of codec */
	return snd_hda_ctl_add(codec,
	return snd_hda_ctl_add(codec, mout->dig_out_nid,
			      snd_ctl_new1(&spdif_share_sw, mout));
			      snd_ctl_new1(&spdif_share_sw, mout));
}
}
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
@@ -2289,7 +2291,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
		if (!kctl)
		if (!kctl)
			return -ENOMEM;
			return -ENOMEM;
		kctl->private_value = nid;
		kctl->private_value = nid;
		err = snd_hda_ctl_add(codec, kctl);
		err = snd_hda_ctl_add(codec, nid, kctl);
		if (err < 0)
		if (err < 0)
			return err;
			return err;
	}
	}
@@ -3165,7 +3167,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
		kctl = snd_ctl_new1(knew, codec);
		kctl = snd_ctl_new1(knew, codec);
		if (!kctl)
		if (!kctl)
			return -ENOMEM;
			return -ENOMEM;
		err = snd_hda_ctl_add(codec, kctl);
		err = snd_hda_ctl_add(codec, 0, kctl);
		if (err < 0) {
		if (err < 0) {
			if (!codec->addr)
			if (!codec->addr)
				return err;
				return err;
@@ -3173,7 +3175,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
			if (!kctl)
			if (!kctl)
				return -ENOMEM;
				return -ENOMEM;
			kctl->id.device = codec->addr;
			kctl->id.device = codec->addr;
			err = snd_hda_ctl_add(codec, kctl);
			err = snd_hda_ctl_add(codec, 0, kctl);
			if (err < 0)
			if (err < 0)
				return err;
				return err;
		}
		}
+11 −6
Original line number Original line Diff line number Diff line
@@ -727,7 +727,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
		if (is_loopback)
		if (is_loopback)
			add_input_loopback(codec, node->nid, HDA_INPUT, index);
			add_input_loopback(codec, node->nid, HDA_INPUT, index);
		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
		err = snd_hda_ctl_add(codec, node->nid,
					snd_ctl_new1(&knew, codec));
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		created = 1;
		created = 1;
@@ -737,7 +738,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
		if (is_loopback)
		if (is_loopback)
			add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
			add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
		err = snd_hda_ctl_add(codec, node->nid,
					snd_ctl_new1(&knew, codec));
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		created = 1;
		created = 1;
@@ -751,7 +753,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
		err = snd_hda_ctl_add(codec, node->nid,
					snd_ctl_new1(&knew, codec));
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		created = 1;
		created = 1;
@@ -759,7 +762,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
		err = snd_hda_ctl_add(codec, node->nid,
					snd_ctl_new1(&knew, codec));
		if (err < 0)
		if (err < 0)
			return err;
			return err;
		created = 1;
		created = 1;
@@ -857,7 +861,7 @@ static int build_input_controls(struct hda_codec *codec)
	}
	}


	/* create input MUX if multiple sources are available */
	/* create input MUX if multiple sources are available */
	err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
	err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
	if (err < 0)
	if (err < 0)
		return err;
		return err;


@@ -875,7 +879,8 @@ static int build_input_controls(struct hda_codec *codec)
			HDA_CODEC_VOLUME(name, adc_node->nid,
			HDA_CODEC_VOLUME(name, adc_node->nid,
					 spec->input_mux.items[i].index,
					 spec->input_mux.items[i].index,
					 HDA_INPUT);
					 HDA_INPUT);
		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
		err = snd_hda_ctl_add(codec, adc_node->nid,
					snd_ctl_new1(&knew, codec));
		if (err < 0)
		if (err < 0)
			return err;
			return err;
	}
	}
+9 −2
Original line number Original line Diff line number Diff line
@@ -440,7 +440,13 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
			      unsigned int caps);
			      unsigned int caps);
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);


int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
struct hda_nid_item {
	struct snd_kcontrol *kctl;
	hda_nid_t nid;
};

int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
		    struct snd_kcontrol *kctl);
void snd_hda_ctls_clear(struct hda_codec *codec);
void snd_hda_ctls_clear(struct hda_codec *codec);


/*
/*
@@ -514,7 +520,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 * AMP control callbacks
 * AMP control callbacks
 */
 */
/* retrieve parameters from private_value */
/* retrieve parameters from private_value */
#define get_amp_nid(kc)		((kc)->private_value & 0xffff)
#define get_amp_nid_(pv)	((pv) & 0xffff)
#define get_amp_nid(kc)		get_amp_nid_((kc)->private_value)
#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
+40 −15
Original line number Original line Diff line number Diff line
@@ -46,6 +46,41 @@ static const char *get_wid_type_name(unsigned int wid_value)
		return "UNKNOWN Widget";
		return "UNKNOWN Widget";
}
}


static void print_nid_mixers(struct snd_info_buffer *buffer,
			     struct hda_codec *codec, hda_nid_t nid)
{
	int i;
	struct hda_nid_item *items = codec->mixers.list;
	struct snd_kcontrol *kctl;
	for (i = 0; i < codec->mixers.used; i++) {
		if (items[i].nid == nid) {
			kctl = items[i].kctl;
			snd_iprintf(buffer,
			  "  Control: name=\"%s\", index=%i, device=%i\n",
			  kctl->id.name, kctl->id.index, kctl->id.device);
		}
	}
}

static void print_nid_pcms(struct snd_info_buffer *buffer,
			   struct hda_codec *codec, hda_nid_t nid)
{
	int pcm, type;
	struct hda_pcm *cpcm;
	for (pcm = 0; pcm < codec->num_pcms; pcm++) {
		cpcm = &codec->pcm_info[pcm];
		for (type = 0; type < 2; type++) {
			if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
				continue;
			snd_iprintf(buffer, "  Device: name=\"%s\", "
				    "type=\"%s\", device=%i\n",
				    cpcm->name,
				    snd_hda_pcm_type_name[cpcm->pcm_type],
				    cpcm->pcm->device);
		}
	}
}

static void print_amp_caps(struct snd_info_buffer *buffer,
static void print_amp_caps(struct snd_info_buffer *buffer,
			   struct hda_codec *codec, hda_nid_t nid, int dir)
			   struct hda_codec *codec, hda_nid_t nid, int dir)
{
{
@@ -309,21 +344,7 @@ static void print_audio_io(struct snd_info_buffer *buffer,
			   struct hda_codec *codec, hda_nid_t nid,
			   struct hda_codec *codec, hda_nid_t nid,
			   unsigned int wid_type)
			   unsigned int wid_type)
{
{
	int pcm, conv;
	int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
	for (pcm = 0; pcm < codec->num_pcms; pcm++) {
		int type;
		struct hda_pcm *cpcm = &codec->pcm_info[pcm];
		for (type = 0; type < 2; type++) {
			if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
				continue;
			snd_iprintf(buffer, "  Device: name=\"%s\", "
				    "type=\"%s\", device=%i\n",
				    cpcm->name,
				    snd_hda_pcm_type_name[cpcm->pcm_type],
				    cpcm->pcm->device);
		}
	}
	conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
	snd_iprintf(buffer,
	snd_iprintf(buffer,
		    "  Converter: stream=%d, channel=%d\n",
		    "  Converter: stream=%d, channel=%d\n",
		    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
		    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
@@ -471,6 +492,7 @@ static void print_gpio(struct snd_info_buffer *buffer,
			    (data & (1<<i)) ? 1 : 0,
			    (data & (1<<i)) ? 1 : 0,
			    (unsol & (1<<i)) ? 1 : 0);
			    (unsol & (1<<i)) ? 1 : 0);
	/* FIXME: add GPO and GPI pin information */
	/* FIXME: add GPO and GPI pin information */
	print_nid_mixers(buffer, codec, nid);
}
}


static void print_codec_info(struct snd_info_entry *entry,
static void print_codec_info(struct snd_info_entry *entry,
@@ -550,6 +572,9 @@ static void print_codec_info(struct snd_info_entry *entry,
			snd_iprintf(buffer, " CP");
			snd_iprintf(buffer, " CP");
		snd_iprintf(buffer, "\n");
		snd_iprintf(buffer, "\n");


		print_nid_mixers(buffer, codec, nid);
		print_nid_pcms(buffer, codec, nid);

		/* volume knob is a special widget that always have connection
		/* volume knob is a special widget that always have connection
		 * list
		 * list
		 */
		 */
+3 −1
Original line number Original line Diff line number Diff line
@@ -202,7 +202,9 @@ static int ad198x_build_controls(struct hda_codec *codec)
			if (!kctl)
			if (!kctl)
				return -ENOMEM;
				return -ENOMEM;
			kctl->private_value = spec->beep_amp;
			kctl->private_value = spec->beep_amp;
			err = snd_hda_ctl_add(codec, kctl);
			err = snd_hda_ctl_add(codec,
						get_amp_nid_(spec->beep_amp),
						kctl);
			if (err < 0)
			if (err < 0)
				return err;
				return err;
		}
		}
Loading