xref: /openbmc/linux/sound/pci/hda/hda_proc.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1d0fa1179SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Universal Interface for Intel High Definition Audio Codec
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Generic proc interface
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/init.h>
114eea3091STakashi Iwai #include <linux/slab.h>
121da177e4SLinus Torvalds #include <sound/core.h>
13cd262518SDavid Henningsson #include <linux/module.h>
14be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h>
1518612048SAdrian Bunk #include "hda_local.h"
161da177e4SLinus Torvalds 
17cd262518SDavid Henningsson static int dump_coef = -1;
18cd262518SDavid Henningsson module_param(dump_coef, int, 0644);
19cd262518SDavid Henningsson MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
20cd262518SDavid Henningsson 
219ba17b4dSTakashi Iwai /* always use noncached version */
229ba17b4dSTakashi Iwai #define param_read(codec, nid, parm) \
239ba17b4dSTakashi Iwai 	snd_hdac_read_parm_uncached(&(codec)->core, nid, parm)
249ba17b4dSTakashi Iwai 
get_wid_type_name(unsigned int wid_value)251da177e4SLinus Torvalds static const char *get_wid_type_name(unsigned int wid_value)
261da177e4SLinus Torvalds {
27cc75cdfeSTakashi Iwai 	static const char * const names[16] = {
281da177e4SLinus Torvalds 		[AC_WID_AUD_OUT] = "Audio Output",
291da177e4SLinus Torvalds 		[AC_WID_AUD_IN] = "Audio Input",
301da177e4SLinus Torvalds 		[AC_WID_AUD_MIX] = "Audio Mixer",
311da177e4SLinus Torvalds 		[AC_WID_AUD_SEL] = "Audio Selector",
321da177e4SLinus Torvalds 		[AC_WID_PIN] = "Pin Complex",
331da177e4SLinus Torvalds 		[AC_WID_POWER] = "Power Widget",
341da177e4SLinus Torvalds 		[AC_WID_VOL_KNB] = "Volume Knob Widget",
351da177e4SLinus Torvalds 		[AC_WID_BEEP] = "Beep Generator Widget",
361da177e4SLinus Torvalds 		[AC_WID_VENDOR] = "Vendor Defined Widget",
371da177e4SLinus Torvalds 	};
383a90274dSTakashi Iwai 	if (wid_value == -1)
393a90274dSTakashi Iwai 		return "UNKNOWN Widget";
401da177e4SLinus Torvalds 	wid_value &= 0xf;
411da177e4SLinus Torvalds 	if (names[wid_value])
421da177e4SLinus Torvalds 		return names[wid_value];
431da177e4SLinus Torvalds 	else
443bc89529STakashi Iwai 		return "UNKNOWN Widget";
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds 
print_nid_array(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,struct snd_array * array)475b0cb1d8SJaroslav Kysela static void print_nid_array(struct snd_info_buffer *buffer,
485b0cb1d8SJaroslav Kysela 			    struct hda_codec *codec, hda_nid_t nid,
495b0cb1d8SJaroslav Kysela 			    struct snd_array *array)
503911a4c1SJaroslav Kysela {
513911a4c1SJaroslav Kysela 	int i;
525b0cb1d8SJaroslav Kysela 	struct hda_nid_item *items = array->list, *item;
533911a4c1SJaroslav Kysela 	struct snd_kcontrol *kctl;
545b0cb1d8SJaroslav Kysela 	for (i = 0; i < array->used; i++) {
555b0cb1d8SJaroslav Kysela 		item = &items[i];
565b0cb1d8SJaroslav Kysela 		if (item->nid == nid) {
575b0cb1d8SJaroslav Kysela 			kctl = item->kctl;
583911a4c1SJaroslav Kysela 			snd_iprintf(buffer,
593911a4c1SJaroslav Kysela 			  "  Control: name=\"%s\", index=%i, device=%i\n",
605b0cb1d8SJaroslav Kysela 			  kctl->id.name, kctl->id.index + item->index,
615b0cb1d8SJaroslav Kysela 			  kctl->id.device);
629e3fd871SJaroslav Kysela 			if (item->flags & HDA_NID_ITEM_AMP)
639e3fd871SJaroslav Kysela 				snd_iprintf(buffer,
649e3fd871SJaroslav Kysela 				  "    ControlAmp: chs=%lu, dir=%s, "
659e3fd871SJaroslav Kysela 				  "idx=%lu, ofs=%lu\n",
669e3fd871SJaroslav Kysela 				  get_amp_channels(kctl),
679e3fd871SJaroslav Kysela 				  get_amp_direction(kctl) ? "Out" : "In",
689e3fd871SJaroslav Kysela 				  get_amp_index(kctl),
699e3fd871SJaroslav Kysela 				  get_amp_offset(kctl));
703911a4c1SJaroslav Kysela 		}
713911a4c1SJaroslav Kysela 	}
723911a4c1SJaroslav Kysela }
733911a4c1SJaroslav Kysela 
print_nid_pcms(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)743911a4c1SJaroslav Kysela static void print_nid_pcms(struct snd_info_buffer *buffer,
753911a4c1SJaroslav Kysela 			   struct hda_codec *codec, hda_nid_t nid)
763911a4c1SJaroslav Kysela {
77bbbc7e85STakashi Iwai 	int type;
783911a4c1SJaroslav Kysela 	struct hda_pcm *cpcm;
79bbbc7e85STakashi Iwai 
80bbbc7e85STakashi Iwai 	list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
813911a4c1SJaroslav Kysela 		for (type = 0; type < 2; type++) {
823911a4c1SJaroslav Kysela 			if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
833911a4c1SJaroslav Kysela 				continue;
843911a4c1SJaroslav Kysela 			snd_iprintf(buffer, "  Device: name=\"%s\", "
853911a4c1SJaroslav Kysela 				    "type=\"%s\", device=%i\n",
863911a4c1SJaroslav Kysela 				    cpcm->name,
873911a4c1SJaroslav Kysela 				    snd_hda_pcm_type_name[cpcm->pcm_type],
883911a4c1SJaroslav Kysela 				    cpcm->pcm->device);
893911a4c1SJaroslav Kysela 		}
903911a4c1SJaroslav Kysela 	}
913911a4c1SJaroslav Kysela }
923911a4c1SJaroslav Kysela 
print_amp_caps(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,int dir)93c8b6bf9bSTakashi Iwai static void print_amp_caps(struct snd_info_buffer *buffer,
941da177e4SLinus Torvalds 			   struct hda_codec *codec, hda_nid_t nid, int dir)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds 	unsigned int caps;
979ba17b4dSTakashi Iwai 	caps = param_read(codec, nid, dir == HDA_OUTPUT ?
987f0e2f8bSJaroslav Kysela 			  AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
991da177e4SLinus Torvalds 	if (caps == -1 || caps == 0) {
1001da177e4SLinus Torvalds 		snd_iprintf(buffer, "N/A\n");
1011da177e4SLinus Torvalds 		return;
1021da177e4SLinus Torvalds 	}
103d01ce99fSTakashi Iwai 	snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, "
104d01ce99fSTakashi Iwai 		    "mute=%x\n",
1051da177e4SLinus Torvalds 		    caps & AC_AMPCAP_OFFSET,
1061da177e4SLinus Torvalds 		    (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
1071da177e4SLinus Torvalds 		    (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
1081da177e4SLinus Torvalds 		    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
111cc261738STakashi Iwai /* is this a stereo widget or a stereo-to-mono mix? */
is_stereo_amps(struct hda_codec * codec,hda_nid_t nid,int dir,unsigned int wcaps,int indices)112cc261738STakashi Iwai static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
113cc261738STakashi Iwai 			   int dir, unsigned int wcaps, int indices)
114cc261738STakashi Iwai {
115cc261738STakashi Iwai 	hda_nid_t conn;
116cc261738STakashi Iwai 
117cc261738STakashi Iwai 	if (wcaps & AC_WCAP_STEREO)
118cc261738STakashi Iwai 		return true;
119cc261738STakashi Iwai 	/* check for a stereo-to-mono mix; it must be:
120cc261738STakashi Iwai 	 * only a single connection, only for input, and only a mixer widget
121cc261738STakashi Iwai 	 */
122cc261738STakashi Iwai 	if (indices != 1 || dir != HDA_INPUT ||
123cc261738STakashi Iwai 	    get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
124cc261738STakashi Iwai 		return false;
125cc261738STakashi Iwai 
126cc261738STakashi Iwai 	if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
127cc261738STakashi Iwai 		return false;
128cc261738STakashi Iwai 	/* the connection source is a stereo? */
129cc261738STakashi Iwai 	wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
130cc261738STakashi Iwai 	return !!(wcaps & AC_WCAP_STEREO);
131cc261738STakashi Iwai }
132cc261738STakashi Iwai 
print_amp_vals(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,int dir,unsigned int wcaps,int indices)133c8b6bf9bSTakashi Iwai static void print_amp_vals(struct snd_info_buffer *buffer,
1341da177e4SLinus Torvalds 			   struct hda_codec *codec, hda_nid_t nid,
135cc261738STakashi Iwai 			   int dir, unsigned int wcaps, int indices)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	unsigned int val;
138cc261738STakashi Iwai 	bool stereo;
1393e289f16STakashi Iwai 	int i;
1403e289f16STakashi Iwai 
141cc261738STakashi Iwai 	stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
142cc261738STakashi Iwai 
1437f0e2f8bSJaroslav Kysela 	dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
1443e289f16STakashi Iwai 	for (i = 0; i < indices; i++) {
1453e289f16STakashi Iwai 		snd_iprintf(buffer, " [");
146d01ce99fSTakashi Iwai 		val = snd_hda_codec_read(codec, nid, 0,
147d01ce99fSTakashi Iwai 					 AC_VERB_GET_AMP_GAIN_MUTE,
1483e289f16STakashi Iwai 					 AC_AMP_GET_LEFT | dir | i);
1491da177e4SLinus Torvalds 		snd_iprintf(buffer, "0x%02x", val);
1502f179721STakashi Iwai 		if (stereo) {
151d01ce99fSTakashi Iwai 			val = snd_hda_codec_read(codec, nid, 0,
152d01ce99fSTakashi Iwai 						 AC_VERB_GET_AMP_GAIN_MUTE,
1533e289f16STakashi Iwai 						 AC_AMP_GET_RIGHT | dir | i);
1542f179721STakashi Iwai 			snd_iprintf(buffer, " 0x%02x", val);
1552f179721STakashi Iwai 		}
1562f179721STakashi Iwai 		snd_iprintf(buffer, "]");
1573e289f16STakashi Iwai 	}
1583e289f16STakashi Iwai 	snd_iprintf(buffer, "\n");
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
print_pcm_rates(struct snd_info_buffer * buffer,unsigned int pcm)16133deeca3SWu Fengguang static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
16233deeca3SWu Fengguang {
163bf82326fSTakashi Iwai 	static const unsigned int rates[] = {
164f71ff0d7STakashi Iwai 		8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
165f71ff0d7STakashi Iwai 		96000, 176400, 192000, 384000
166f71ff0d7STakashi Iwai 	};
167f71ff0d7STakashi Iwai 	int i;
168d39b4352SWu Fengguang 
169b90d7760STakashi Iwai 	pcm &= AC_SUPPCM_RATES;
170b90d7760STakashi Iwai 	snd_iprintf(buffer, "    rates [0x%x]:", pcm);
171f71ff0d7STakashi Iwai 	for (i = 0; i < ARRAY_SIZE(rates); i++)
172f71ff0d7STakashi Iwai 		if (pcm & (1 << i))
173f71ff0d7STakashi Iwai 			snd_iprintf(buffer,  " %d", rates[i]);
174f71ff0d7STakashi Iwai 	snd_iprintf(buffer, "\n");
175b90d7760STakashi Iwai }
176b90d7760STakashi Iwai 
print_pcm_bits(struct snd_info_buffer * buffer,unsigned int pcm)177d39b4352SWu Fengguang static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
178d39b4352SWu Fengguang {
179d39b4352SWu Fengguang 	char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
180b90d7760STakashi Iwai 
181b0e6481aSTakashi Iwai 	snd_iprintf(buffer, "    bits [0x%x]:", (pcm >> 16) & 0xff);
182d39b4352SWu Fengguang 	snd_print_pcm_bits(pcm, buf, sizeof(buf));
183d39b4352SWu Fengguang 	snd_iprintf(buffer, "%s\n", buf);
184b90d7760STakashi Iwai }
185b90d7760STakashi Iwai 
print_pcm_formats(struct snd_info_buffer * buffer,unsigned int streams)186b90d7760STakashi Iwai static void print_pcm_formats(struct snd_info_buffer *buffer,
187b90d7760STakashi Iwai 			      unsigned int streams)
188b90d7760STakashi Iwai {
189b90d7760STakashi Iwai 	snd_iprintf(buffer, "    formats [0x%x]:", streams & 0xf);
190b90d7760STakashi Iwai 	if (streams & AC_SUPFMT_PCM)
191b90d7760STakashi Iwai 		snd_iprintf(buffer, " PCM");
192b90d7760STakashi Iwai 	if (streams & AC_SUPFMT_FLOAT32)
193b90d7760STakashi Iwai 		snd_iprintf(buffer, " FLOAT");
194b90d7760STakashi Iwai 	if (streams & AC_SUPFMT_AC3)
195b90d7760STakashi Iwai 		snd_iprintf(buffer, " AC3");
196b90d7760STakashi Iwai 	snd_iprintf(buffer, "\n");
197b90d7760STakashi Iwai }
198b90d7760STakashi Iwai 
print_pcm_caps(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)199c8b6bf9bSTakashi Iwai static void print_pcm_caps(struct snd_info_buffer *buffer,
2001da177e4SLinus Torvalds 			   struct hda_codec *codec, hda_nid_t nid)
2011da177e4SLinus Torvalds {
2029ba17b4dSTakashi Iwai 	unsigned int pcm = param_read(codec, nid, AC_PAR_PCM);
2039ba17b4dSTakashi Iwai 	unsigned int stream = param_read(codec, nid, AC_PAR_STREAM);
2041da177e4SLinus Torvalds 	if (pcm == -1 || stream == -1) {
2051da177e4SLinus Torvalds 		snd_iprintf(buffer, "N/A\n");
2061da177e4SLinus Torvalds 		return;
2071da177e4SLinus Torvalds 	}
208b90d7760STakashi Iwai 	print_pcm_rates(buffer, pcm);
209b90d7760STakashi Iwai 	print_pcm_bits(buffer, pcm);
210b90d7760STakashi Iwai 	print_pcm_formats(buffer, stream);
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
get_jack_connection(u32 cfg)2131da177e4SLinus Torvalds static const char *get_jack_connection(u32 cfg)
2141da177e4SLinus Torvalds {
215cc75cdfeSTakashi Iwai 	static const char * const names[16] = {
2161da177e4SLinus Torvalds 		"Unknown", "1/8", "1/4", "ATAPI",
2171da177e4SLinus Torvalds 		"RCA", "Optical","Digital", "Analog",
2181da177e4SLinus Torvalds 		"DIN", "XLR", "RJ11", "Comb",
2191da177e4SLinus Torvalds 		NULL, NULL, NULL, "Other"
2201da177e4SLinus Torvalds 	};
2211da177e4SLinus Torvalds 	cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
2221da177e4SLinus Torvalds 	if (names[cfg])
2231da177e4SLinus Torvalds 		return names[cfg];
2241da177e4SLinus Torvalds 	else
2251da177e4SLinus Torvalds 		return "UNKNOWN";
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds 
get_jack_color(u32 cfg)2281da177e4SLinus Torvalds static const char *get_jack_color(u32 cfg)
2291da177e4SLinus Torvalds {
230cc75cdfeSTakashi Iwai 	static const char * const names[16] = {
2311da177e4SLinus Torvalds 		"Unknown", "Black", "Grey", "Blue",
2321da177e4SLinus Torvalds 		"Green", "Red", "Orange", "Yellow",
2331da177e4SLinus Torvalds 		"Purple", "Pink", NULL, NULL,
2341da177e4SLinus Torvalds 		NULL, NULL, "White", "Other",
2351da177e4SLinus Torvalds 	};
2361da177e4SLinus Torvalds 	cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
2371da177e4SLinus Torvalds 	if (names[cfg])
2381da177e4SLinus Torvalds 		return names[cfg];
2391da177e4SLinus Torvalds 	else
2401da177e4SLinus Torvalds 		return "UNKNOWN";
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
243d2c6b63dSTakashi Iwai /*
244d2c6b63dSTakashi Iwai  * Parse the pin default config value and returns the string of the
245d2c6b63dSTakashi Iwai  * jack location, e.g. "Rear", "Front", etc.
246d2c6b63dSTakashi Iwai  */
get_jack_location(u32 cfg)247d2c6b63dSTakashi Iwai static const char *get_jack_location(u32 cfg)
248d2c6b63dSTakashi Iwai {
249cc75cdfeSTakashi Iwai 	static const char * const bases[7] = {
250d2c6b63dSTakashi Iwai 		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
251d2c6b63dSTakashi Iwai 	};
252cc75cdfeSTakashi Iwai 	static const unsigned char specials_idx[] = {
253d2c6b63dSTakashi Iwai 		0x07, 0x08,
254d2c6b63dSTakashi Iwai 		0x17, 0x18, 0x19,
255d2c6b63dSTakashi Iwai 		0x37, 0x38
256d2c6b63dSTakashi Iwai 	};
257cc75cdfeSTakashi Iwai 	static const char * const specials[] = {
258d2c6b63dSTakashi Iwai 		"Rear Panel", "Drive Bar",
259d2c6b63dSTakashi Iwai 		"Riser", "HDMI", "ATAPI",
260d2c6b63dSTakashi Iwai 		"Mobile-In", "Mobile-Out"
261d2c6b63dSTakashi Iwai 	};
262d2c6b63dSTakashi Iwai 	int i;
263d2c6b63dSTakashi Iwai 
264d2c6b63dSTakashi Iwai 	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
265d2c6b63dSTakashi Iwai 	if ((cfg & 0x0f) < 7)
266d2c6b63dSTakashi Iwai 		return bases[cfg & 0x0f];
267d2c6b63dSTakashi Iwai 	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
268d2c6b63dSTakashi Iwai 		if (cfg == specials_idx[i])
269d2c6b63dSTakashi Iwai 			return specials[i];
270d2c6b63dSTakashi Iwai 	}
271d2c6b63dSTakashi Iwai 	return "UNKNOWN";
272d2c6b63dSTakashi Iwai }
273d2c6b63dSTakashi Iwai 
274d2c6b63dSTakashi Iwai /*
275d2c6b63dSTakashi Iwai  * Parse the pin default config value and returns the string of the
276d2c6b63dSTakashi Iwai  * jack connectivity, i.e. external or internal connection.
277d2c6b63dSTakashi Iwai  */
get_jack_connectivity(u32 cfg)278d2c6b63dSTakashi Iwai static const char *get_jack_connectivity(u32 cfg)
279d2c6b63dSTakashi Iwai {
280cc75cdfeSTakashi Iwai 	static const char * const jack_locations[4] = {
281cc75cdfeSTakashi Iwai 		"Ext", "Int", "Sep", "Oth"
282cc75cdfeSTakashi Iwai 	};
283d2c6b63dSTakashi Iwai 
284d2c6b63dSTakashi Iwai 	return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
285d2c6b63dSTakashi Iwai }
286d2c6b63dSTakashi Iwai 
287d2c6b63dSTakashi Iwai /*
288d2c6b63dSTakashi Iwai  * Parse the pin default config value and returns the string of the
289d2c6b63dSTakashi Iwai  * jack type, i.e. the purpose of the jack, such as Line-Out or CD.
290d2c6b63dSTakashi Iwai  */
get_jack_type(u32 cfg)291d2c6b63dSTakashi Iwai static const char *get_jack_type(u32 cfg)
292d2c6b63dSTakashi Iwai {
293cc75cdfeSTakashi Iwai 	static const char * const jack_types[16] = {
294d2c6b63dSTakashi Iwai 		"Line Out", "Speaker", "HP Out", "CD",
295d2c6b63dSTakashi Iwai 		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
296d2c6b63dSTakashi Iwai 		"Line In", "Aux", "Mic", "Telephony",
297d2c6b63dSTakashi Iwai 		"SPDIF In", "Digital In", "Reserved", "Other"
298d2c6b63dSTakashi Iwai 	};
299d2c6b63dSTakashi Iwai 
300d2c6b63dSTakashi Iwai 	return jack_types[(cfg & AC_DEFCFG_DEVICE)
301d2c6b63dSTakashi Iwai 				>> AC_DEFCFG_DEVICE_SHIFT];
302d2c6b63dSTakashi Iwai }
303d2c6b63dSTakashi Iwai 
print_pin_caps(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,int * supports_vref)304c8b6bf9bSTakashi Iwai static void print_pin_caps(struct snd_info_buffer *buffer,
305797760abSAndrew Paprocki 			   struct hda_codec *codec, hda_nid_t nid,
306797760abSAndrew Paprocki 			   int *supports_vref)
3071da177e4SLinus Torvalds {
308cc75cdfeSTakashi Iwai 	static const char * const jack_conns[4] = {
309cc75cdfeSTakashi Iwai 		"Jack", "N/A", "Fixed", "Both"
310cc75cdfeSTakashi Iwai 	};
311e97a5167STakashi Iwai 	unsigned int caps, val;
3121da177e4SLinus Torvalds 
3139ba17b4dSTakashi Iwai 	caps = param_read(codec, nid, AC_PAR_PIN_CAP);
3140481f453SRobin H. Johnson 	snd_iprintf(buffer, "  Pincap 0x%08x:", caps);
3151da177e4SLinus Torvalds 	if (caps & AC_PINCAP_IN)
3161da177e4SLinus Torvalds 		snd_iprintf(buffer, " IN");
3171da177e4SLinus Torvalds 	if (caps & AC_PINCAP_OUT)
3181da177e4SLinus Torvalds 		snd_iprintf(buffer, " OUT");
3191da177e4SLinus Torvalds 	if (caps & AC_PINCAP_HP_DRV)
3201da177e4SLinus Torvalds 		snd_iprintf(buffer, " HP");
3215885492aSTakashi Iwai 	if (caps & AC_PINCAP_EAPD)
3225885492aSTakashi Iwai 		snd_iprintf(buffer, " EAPD");
3235885492aSTakashi Iwai 	if (caps & AC_PINCAP_PRES_DETECT)
3245885492aSTakashi Iwai 		snd_iprintf(buffer, " Detect");
325797760abSAndrew Paprocki 	if (caps & AC_PINCAP_BALANCE)
326797760abSAndrew Paprocki 		snd_iprintf(buffer, " Balanced");
327c4920606STakashi Iwai 	if (caps & AC_PINCAP_HDMI) {
328c4920606STakashi Iwai 		/* Realtek uses this bit as a different meaning */
3297639a06cSTakashi Iwai 		if ((codec->core.vendor_id >> 16) == 0x10ec)
330797760abSAndrew Paprocki 			snd_iprintf(buffer, " R/L");
331b923528eSWu Fengguang 		else {
332b923528eSWu Fengguang 			if (caps & AC_PINCAP_HBR)
333b923528eSWu Fengguang 				snd_iprintf(buffer, " HBR");
334c4920606STakashi Iwai 			snd_iprintf(buffer, " HDMI");
335c4920606STakashi Iwai 		}
336b923528eSWu Fengguang 	}
337728765b3SWu Fengguang 	if (caps & AC_PINCAP_DP)
338728765b3SWu Fengguang 		snd_iprintf(buffer, " DP");
339797760abSAndrew Paprocki 	if (caps & AC_PINCAP_TRIG_REQ)
340797760abSAndrew Paprocki 		snd_iprintf(buffer, " Trigger");
341797760abSAndrew Paprocki 	if (caps & AC_PINCAP_IMP_SENSE)
342797760abSAndrew Paprocki 		snd_iprintf(buffer, " ImpSense");
3431da177e4SLinus Torvalds 	snd_iprintf(buffer, "\n");
344797760abSAndrew Paprocki 	if (caps & AC_PINCAP_VREF) {
345797760abSAndrew Paprocki 		unsigned int vref =
346797760abSAndrew Paprocki 			(caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
347797760abSAndrew Paprocki 		snd_iprintf(buffer, "    Vref caps:");
348797760abSAndrew Paprocki 		if (vref & AC_PINCAP_VREF_HIZ)
349797760abSAndrew Paprocki 			snd_iprintf(buffer, " HIZ");
350797760abSAndrew Paprocki 		if (vref & AC_PINCAP_VREF_50)
351797760abSAndrew Paprocki 			snd_iprintf(buffer, " 50");
352797760abSAndrew Paprocki 		if (vref & AC_PINCAP_VREF_GRD)
353797760abSAndrew Paprocki 			snd_iprintf(buffer, " GRD");
354797760abSAndrew Paprocki 		if (vref & AC_PINCAP_VREF_80)
355797760abSAndrew Paprocki 			snd_iprintf(buffer, " 80");
356797760abSAndrew Paprocki 		if (vref & AC_PINCAP_VREF_100)
357797760abSAndrew Paprocki 			snd_iprintf(buffer, " 100");
358797760abSAndrew Paprocki 		snd_iprintf(buffer, "\n");
359797760abSAndrew Paprocki 		*supports_vref = 1;
360797760abSAndrew Paprocki 	} else
361797760abSAndrew Paprocki 		*supports_vref = 0;
362797760abSAndrew Paprocki 	if (caps & AC_PINCAP_EAPD) {
363797760abSAndrew Paprocki 		val = snd_hda_codec_read(codec, nid, 0,
364797760abSAndrew Paprocki 					 AC_VERB_GET_EAPD_BTLENABLE, 0);
365797760abSAndrew Paprocki 		snd_iprintf(buffer, "  EAPD 0x%x:", val);
366797760abSAndrew Paprocki 		if (val & AC_EAPDBTL_BALANCED)
367797760abSAndrew Paprocki 			snd_iprintf(buffer, " BALANCED");
368797760abSAndrew Paprocki 		if (val & AC_EAPDBTL_EAPD)
369797760abSAndrew Paprocki 			snd_iprintf(buffer, " EAPD");
370797760abSAndrew Paprocki 		if (val & AC_EAPDBTL_LR_SWAP)
371797760abSAndrew Paprocki 			snd_iprintf(buffer, " R/L");
372797760abSAndrew Paprocki 		snd_iprintf(buffer, "\n");
373797760abSAndrew Paprocki 	}
3741da177e4SLinus Torvalds 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
375b0c95f51STakashi Iwai 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
376b0c95f51STakashi Iwai 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
377d2c6b63dSTakashi Iwai 		    get_jack_type(caps),
378d2c6b63dSTakashi Iwai 		    get_jack_connectivity(caps),
379d2c6b63dSTakashi Iwai 		    get_jack_location(caps));
3801da177e4SLinus Torvalds 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
3811da177e4SLinus Torvalds 		    get_jack_connection(caps),
3821da177e4SLinus Torvalds 		    get_jack_color(caps));
383797760abSAndrew Paprocki 	/* Default association and sequence values refer to default grouping
384797760abSAndrew Paprocki 	 * of pin complexes and their sequence within the group. This is used
385797760abSAndrew Paprocki 	 * for priority and resource allocation.
386797760abSAndrew Paprocki 	 */
387797760abSAndrew Paprocki 	snd_iprintf(buffer, "    DefAssociation = 0x%x, Sequence = 0x%x\n",
388797760abSAndrew Paprocki 		    (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
389797760abSAndrew Paprocki 		    caps & AC_DEFCFG_SEQUENCE);
390797760abSAndrew Paprocki 	if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
391797760abSAndrew Paprocki 	    AC_DEFCFG_MISC_NO_PRESENCE) {
392797760abSAndrew Paprocki 		/* Miscellaneous bit indicates external hardware does not
393797760abSAndrew Paprocki 		 * support presence detection even if the pin complex
394797760abSAndrew Paprocki 		 * indicates it is supported.
395797760abSAndrew Paprocki 		 */
396797760abSAndrew Paprocki 		snd_iprintf(buffer, "    Misc = NO_PRESENCE\n");
397e97a5167STakashi Iwai 	}
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
print_pin_ctls(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,int supports_vref)400797760abSAndrew Paprocki static void print_pin_ctls(struct snd_info_buffer *buffer,
401797760abSAndrew Paprocki 			   struct hda_codec *codec, hda_nid_t nid,
402797760abSAndrew Paprocki 			   int supports_vref)
403797760abSAndrew Paprocki {
404797760abSAndrew Paprocki 	unsigned int pinctls;
405797760abSAndrew Paprocki 
406797760abSAndrew Paprocki 	pinctls = snd_hda_codec_read(codec, nid, 0,
407797760abSAndrew Paprocki 				     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
408797760abSAndrew Paprocki 	snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
409797760abSAndrew Paprocki 	if (pinctls & AC_PINCTL_IN_EN)
410797760abSAndrew Paprocki 		snd_iprintf(buffer, " IN");
411797760abSAndrew Paprocki 	if (pinctls & AC_PINCTL_OUT_EN)
412797760abSAndrew Paprocki 		snd_iprintf(buffer, " OUT");
413797760abSAndrew Paprocki 	if (pinctls & AC_PINCTL_HP_EN)
414797760abSAndrew Paprocki 		snd_iprintf(buffer, " HP");
415797760abSAndrew Paprocki 	if (supports_vref) {
416797760abSAndrew Paprocki 		int vref = pinctls & AC_PINCTL_VREFEN;
417797760abSAndrew Paprocki 		switch (vref) {
418797760abSAndrew Paprocki 		case AC_PINCTL_VREF_HIZ:
419797760abSAndrew Paprocki 			snd_iprintf(buffer, " VREF_HIZ");
420797760abSAndrew Paprocki 			break;
421797760abSAndrew Paprocki 		case AC_PINCTL_VREF_50:
422797760abSAndrew Paprocki 			snd_iprintf(buffer, " VREF_50");
423797760abSAndrew Paprocki 			break;
424797760abSAndrew Paprocki 		case AC_PINCTL_VREF_GRD:
425797760abSAndrew Paprocki 			snd_iprintf(buffer, " VREF_GRD");
426797760abSAndrew Paprocki 			break;
427797760abSAndrew Paprocki 		case AC_PINCTL_VREF_80:
428797760abSAndrew Paprocki 			snd_iprintf(buffer, " VREF_80");
429797760abSAndrew Paprocki 			break;
430797760abSAndrew Paprocki 		case AC_PINCTL_VREF_100:
431797760abSAndrew Paprocki 			snd_iprintf(buffer, " VREF_100");
432797760abSAndrew Paprocki 			break;
433797760abSAndrew Paprocki 		}
434797760abSAndrew Paprocki 	}
435797760abSAndrew Paprocki 	snd_iprintf(buffer, "\n");
436797760abSAndrew Paprocki }
437797760abSAndrew Paprocki 
print_vol_knob(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)438797760abSAndrew Paprocki static void print_vol_knob(struct snd_info_buffer *buffer,
439797760abSAndrew Paprocki 			   struct hda_codec *codec, hda_nid_t nid)
440797760abSAndrew Paprocki {
4419ba17b4dSTakashi Iwai 	unsigned int cap = param_read(codec, nid, AC_PAR_VOL_KNB_CAP);
442797760abSAndrew Paprocki 	snd_iprintf(buffer, "  Volume-Knob: delta=%d, steps=%d, ",
443797760abSAndrew Paprocki 		    (cap >> 7) & 1, cap & 0x7f);
444797760abSAndrew Paprocki 	cap = snd_hda_codec_read(codec, nid, 0,
445797760abSAndrew Paprocki 				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
446797760abSAndrew Paprocki 	snd_iprintf(buffer, "direct=%d, val=%d\n",
447797760abSAndrew Paprocki 		    (cap >> 7) & 1, cap & 0x7f);
448797760abSAndrew Paprocki }
449797760abSAndrew Paprocki 
print_audio_io(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,unsigned int wid_type)450797760abSAndrew Paprocki static void print_audio_io(struct snd_info_buffer *buffer,
451797760abSAndrew Paprocki 			   struct hda_codec *codec, hda_nid_t nid,
452797760abSAndrew Paprocki 			   unsigned int wid_type)
453797760abSAndrew Paprocki {
4543911a4c1SJaroslav Kysela 	int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
455797760abSAndrew Paprocki 	snd_iprintf(buffer,
456797760abSAndrew Paprocki 		    "  Converter: stream=%d, channel=%d\n",
457797760abSAndrew Paprocki 		    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
458797760abSAndrew Paprocki 		    conv & AC_CONV_CHANNEL);
459797760abSAndrew Paprocki 
460797760abSAndrew Paprocki 	if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
461797760abSAndrew Paprocki 		int sdi = snd_hda_codec_read(codec, nid, 0,
462797760abSAndrew Paprocki 					     AC_VERB_GET_SDI_SELECT, 0);
463797760abSAndrew Paprocki 		snd_iprintf(buffer, "  SDI-Select: %d\n",
464797760abSAndrew Paprocki 			    sdi & AC_SDI_SELECT);
465797760abSAndrew Paprocki 	}
466797760abSAndrew Paprocki }
467797760abSAndrew Paprocki 
print_digital_conv(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)468797760abSAndrew Paprocki static void print_digital_conv(struct snd_info_buffer *buffer,
469797760abSAndrew Paprocki 			       struct hda_codec *codec, hda_nid_t nid)
470797760abSAndrew Paprocki {
471797760abSAndrew Paprocki 	unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
472797760abSAndrew Paprocki 						AC_VERB_GET_DIGI_CONVERT_1, 0);
47361525979SWang Xingchao 	unsigned char digi2 = digi1 >> 8;
47461525979SWang Xingchao 	unsigned char digi3 = digi1 >> 16;
47561525979SWang Xingchao 
476797760abSAndrew Paprocki 	snd_iprintf(buffer, "  Digital:");
477797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_ENABLE)
478797760abSAndrew Paprocki 		snd_iprintf(buffer, " Enabled");
479797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_V)
480797760abSAndrew Paprocki 		snd_iprintf(buffer, " Validity");
481797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_VCFG)
482797760abSAndrew Paprocki 		snd_iprintf(buffer, " ValidityCfg");
483797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_EMPHASIS)
484797760abSAndrew Paprocki 		snd_iprintf(buffer, " Preemphasis");
485797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_COPYRIGHT)
486088c820bSWang Xingchao 		snd_iprintf(buffer, " Non-Copyright");
487797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_NONAUDIO)
488797760abSAndrew Paprocki 		snd_iprintf(buffer, " Non-Audio");
489797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_PROFESSIONAL)
490797760abSAndrew Paprocki 		snd_iprintf(buffer, " Pro");
491797760abSAndrew Paprocki 	if (digi1 & AC_DIG1_LEVEL)
492797760abSAndrew Paprocki 		snd_iprintf(buffer, " GenLevel");
49361525979SWang Xingchao 	if (digi3 & AC_DIG3_KAE)
49461525979SWang Xingchao 		snd_iprintf(buffer, " KAE");
495797760abSAndrew Paprocki 	snd_iprintf(buffer, "\n");
496a1855d80STakashi Iwai 	snd_iprintf(buffer, "  Digital category: 0x%x\n",
49761525979SWang Xingchao 		    digi2 & AC_DIG2_CC);
49861525979SWang Xingchao 	snd_iprintf(buffer, "  IEC Coding Type: 0x%x\n",
49961525979SWang Xingchao 			digi3 & AC_DIG3_ICT);
500797760abSAndrew Paprocki }
501797760abSAndrew Paprocki 
get_pwr_state(u32 state)502797760abSAndrew Paprocki static const char *get_pwr_state(u32 state)
503797760abSAndrew Paprocki {
504167d2d55STakashi Iwai 	static const char * const buf[] = {
505167d2d55STakashi Iwai 		"D0", "D1", "D2", "D3", "D3cold"
506797760abSAndrew Paprocki 	};
507167d2d55STakashi Iwai 	if (state < ARRAY_SIZE(buf))
508797760abSAndrew Paprocki 		return buf[state];
509797760abSAndrew Paprocki 	return "UNKNOWN";
510797760abSAndrew Paprocki }
511797760abSAndrew Paprocki 
print_power_state(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)512797760abSAndrew Paprocki static void print_power_state(struct snd_info_buffer *buffer,
513797760abSAndrew Paprocki 			      struct hda_codec *codec, hda_nid_t nid)
514797760abSAndrew Paprocki {
515cc75cdfeSTakashi Iwai 	static const char * const names[] = {
51683d605fdSWu Fengguang 		[ilog2(AC_PWRST_D0SUP)]		= "D0",
51783d605fdSWu Fengguang 		[ilog2(AC_PWRST_D1SUP)]		= "D1",
51883d605fdSWu Fengguang 		[ilog2(AC_PWRST_D2SUP)]		= "D2",
51983d605fdSWu Fengguang 		[ilog2(AC_PWRST_D3SUP)]		= "D3",
52083d605fdSWu Fengguang 		[ilog2(AC_PWRST_D3COLDSUP)]	= "D3cold",
52183d605fdSWu Fengguang 		[ilog2(AC_PWRST_S3D3COLDSUP)]	= "S3D3cold",
52283d605fdSWu Fengguang 		[ilog2(AC_PWRST_CLKSTOP)]	= "CLKSTOP",
52383d605fdSWu Fengguang 		[ilog2(AC_PWRST_EPSS)]		= "EPSS",
52483d605fdSWu Fengguang 	};
52583d605fdSWu Fengguang 
5269ba17b4dSTakashi Iwai 	int sup = param_read(codec, nid, AC_PAR_POWER_STATE);
527797760abSAndrew Paprocki 	int pwr = snd_hda_codec_read(codec, nid, 0,
528797760abSAndrew Paprocki 				     AC_VERB_GET_POWER_STATE, 0);
5291d260d7bSTakashi Iwai 	if (sup != -1) {
5301d260d7bSTakashi Iwai 		int i;
5311d260d7bSTakashi Iwai 
5321d260d7bSTakashi Iwai 		snd_iprintf(buffer, "  Power states: ");
5331d260d7bSTakashi Iwai 		for (i = 0; i < ARRAY_SIZE(names); i++) {
5341d260d7bSTakashi Iwai 			if (sup & (1U << i))
5351d260d7bSTakashi Iwai 				snd_iprintf(buffer, " %s", names[i]);
5361d260d7bSTakashi Iwai 		}
5371d260d7bSTakashi Iwai 		snd_iprintf(buffer, "\n");
5381d260d7bSTakashi Iwai 	}
53983d605fdSWu Fengguang 
540ce63f3baSWang Xingchao 	snd_iprintf(buffer, "  Power: setting=%s, actual=%s",
541797760abSAndrew Paprocki 		    get_pwr_state(pwr & AC_PWRST_SETTING),
542797760abSAndrew Paprocki 		    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
543797760abSAndrew Paprocki 				  AC_PWRST_ACTUAL_SHIFT));
544ce63f3baSWang Xingchao 	if (pwr & AC_PWRST_ERROR)
545ce63f3baSWang Xingchao 		snd_iprintf(buffer, ", Error");
546ce63f3baSWang Xingchao 	if (pwr & AC_PWRST_CLK_STOP_OK)
547ce63f3baSWang Xingchao 		snd_iprintf(buffer, ", Clock-stop-OK");
548ce63f3baSWang Xingchao 	if (pwr & AC_PWRST_SETTING_RESET)
549ce63f3baSWang Xingchao 		snd_iprintf(buffer, ", Setting-reset");
550ce63f3baSWang Xingchao 	snd_iprintf(buffer, "\n");
551797760abSAndrew Paprocki }
552797760abSAndrew Paprocki 
print_unsol_cap(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)553797760abSAndrew Paprocki static void print_unsol_cap(struct snd_info_buffer *buffer,
554797760abSAndrew Paprocki 			      struct hda_codec *codec, hda_nid_t nid)
555797760abSAndrew Paprocki {
556797760abSAndrew Paprocki 	int unsol = snd_hda_codec_read(codec, nid, 0,
557797760abSAndrew Paprocki 				       AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
558797760abSAndrew Paprocki 	snd_iprintf(buffer,
559797760abSAndrew Paprocki 		    "  Unsolicited: tag=%02x, enabled=%d\n",
560797760abSAndrew Paprocki 		    unsol & AC_UNSOL_TAG,
561797760abSAndrew Paprocki 		    (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
562797760abSAndrew Paprocki }
563797760abSAndrew Paprocki 
can_dump_coef(struct hda_codec * codec)564cd262518SDavid Henningsson static inline bool can_dump_coef(struct hda_codec *codec)
565cd262518SDavid Henningsson {
566cd262518SDavid Henningsson 	switch (dump_coef) {
567cd262518SDavid Henningsson 	case 0: return false;
568cd262518SDavid Henningsson 	case 1: return true;
569cd262518SDavid Henningsson 	default: return codec->dump_coef;
570cd262518SDavid Henningsson 	}
571cd262518SDavid Henningsson }
572cd262518SDavid Henningsson 
print_proc_caps(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)573797760abSAndrew Paprocki static void print_proc_caps(struct snd_info_buffer *buffer,
574797760abSAndrew Paprocki 			    struct hda_codec *codec, hda_nid_t nid)
575797760abSAndrew Paprocki {
576cd262518SDavid Henningsson 	unsigned int i, ncoeff, oldindex;
5779ba17b4dSTakashi Iwai 	unsigned int proc_caps = param_read(codec, nid, AC_PAR_PROC_CAP);
578cd262518SDavid Henningsson 	ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
579797760abSAndrew Paprocki 	snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
580cd262518SDavid Henningsson 		    proc_caps & AC_PCAP_BENIGN, ncoeff);
581cd262518SDavid Henningsson 
582cd262518SDavid Henningsson 	if (!can_dump_coef(codec))
583cd262518SDavid Henningsson 		return;
584cd262518SDavid Henningsson 
585cd262518SDavid Henningsson 	/* Note: This is racy - another process could run in parallel and change
586cd262518SDavid Henningsson 	   the coef index too. */
587cd262518SDavid Henningsson 	oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0);
588cd262518SDavid Henningsson 	for (i = 0; i < ncoeff; i++) {
589cd262518SDavid Henningsson 		unsigned int val;
590cd262518SDavid Henningsson 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i);
591cd262518SDavid Henningsson 		val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF,
592cd262518SDavid Henningsson 					 0);
593cd262518SDavid Henningsson 		snd_iprintf(buffer, "    Coeff 0x%02x: 0x%04x\n", i, val);
594cd262518SDavid Henningsson 	}
595cd262518SDavid Henningsson 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex);
596797760abSAndrew Paprocki }
597797760abSAndrew Paprocki 
print_conn_list(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,unsigned int wid_type,hda_nid_t * conn,int conn_len)598797760abSAndrew Paprocki static void print_conn_list(struct snd_info_buffer *buffer,
599797760abSAndrew Paprocki 			    struct hda_codec *codec, hda_nid_t nid,
600797760abSAndrew Paprocki 			    unsigned int wid_type, hda_nid_t *conn,
601797760abSAndrew Paprocki 			    int conn_len)
602797760abSAndrew Paprocki {
603797760abSAndrew Paprocki 	int c, curr = -1;
6048b2c7a5cSWang Xingchao 	const hda_nid_t *list;
6058b2c7a5cSWang Xingchao 	int cache_len;
606797760abSAndrew Paprocki 
60707a1e813STakashi Iwai 	if (conn_len > 1 &&
60807a1e813STakashi Iwai 	    wid_type != AC_WID_AUD_MIX &&
60907a1e813STakashi Iwai 	    wid_type != AC_WID_VOL_KNB &&
61007a1e813STakashi Iwai 	    wid_type != AC_WID_POWER)
611797760abSAndrew Paprocki 		curr = snd_hda_codec_read(codec, nid, 0,
612797760abSAndrew Paprocki 					  AC_VERB_GET_CONNECT_SEL, 0);
613797760abSAndrew Paprocki 	snd_iprintf(buffer, "  Connection: %d\n", conn_len);
614797760abSAndrew Paprocki 	if (conn_len > 0) {
615797760abSAndrew Paprocki 		snd_iprintf(buffer, "    ");
616797760abSAndrew Paprocki 		for (c = 0; c < conn_len; c++) {
617797760abSAndrew Paprocki 			snd_iprintf(buffer, " 0x%02x", conn[c]);
618797760abSAndrew Paprocki 			if (c == curr)
619797760abSAndrew Paprocki 				snd_iprintf(buffer, "*");
620797760abSAndrew Paprocki 		}
621797760abSAndrew Paprocki 		snd_iprintf(buffer, "\n");
622797760abSAndrew Paprocki 	}
6238b2c7a5cSWang Xingchao 
6248b2c7a5cSWang Xingchao 	/* Get Cache connections info */
6258b2c7a5cSWang Xingchao 	cache_len = snd_hda_get_conn_list(codec, nid, &list);
626f4d77031SDan Carpenter 	if (cache_len >= 0 && (cache_len != conn_len ||
627f4d77031SDan Carpenter 			      memcmp(list, conn, conn_len) != 0)) {
6288b2c7a5cSWang Xingchao 		snd_iprintf(buffer, "  In-driver Connection: %d\n", cache_len);
6298b2c7a5cSWang Xingchao 		if (cache_len > 0) {
6308b2c7a5cSWang Xingchao 			snd_iprintf(buffer, "    ");
6318b2c7a5cSWang Xingchao 			for (c = 0; c < cache_len; c++)
6328b2c7a5cSWang Xingchao 				snd_iprintf(buffer, " 0x%02x", list[c]);
6338b2c7a5cSWang Xingchao 			snd_iprintf(buffer, "\n");
6348b2c7a5cSWang Xingchao 		}
6358b2c7a5cSWang Xingchao 	}
636797760abSAndrew Paprocki }
637797760abSAndrew Paprocki 
print_gpio(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)638797760abSAndrew Paprocki static void print_gpio(struct snd_info_buffer *buffer,
639797760abSAndrew Paprocki 		       struct hda_codec *codec, hda_nid_t nid)
640797760abSAndrew Paprocki {
641797760abSAndrew Paprocki 	unsigned int gpio =
6429ba17b4dSTakashi Iwai 		param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
643797760abSAndrew Paprocki 	unsigned int enable, direction, wake, unsol, sticky, data;
644797760abSAndrew Paprocki 	int i, max;
645797760abSAndrew Paprocki 	snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
646797760abSAndrew Paprocki 		    "unsolicited=%d, wake=%d\n",
647797760abSAndrew Paprocki 		    gpio & AC_GPIO_IO_COUNT,
648797760abSAndrew Paprocki 		    (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
649797760abSAndrew Paprocki 		    (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
650797760abSAndrew Paprocki 		    (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
651797760abSAndrew Paprocki 		    (gpio & AC_GPIO_WAKE) ? 1 : 0);
652797760abSAndrew Paprocki 	max = gpio & AC_GPIO_IO_COUNT;
653c4dc5071STakashi Iwai 	if (!max || max > 8)
654c4dc5071STakashi Iwai 		return;
655797760abSAndrew Paprocki 	enable = snd_hda_codec_read(codec, nid, 0,
656797760abSAndrew Paprocki 				    AC_VERB_GET_GPIO_MASK, 0);
657797760abSAndrew Paprocki 	direction = snd_hda_codec_read(codec, nid, 0,
658797760abSAndrew Paprocki 				       AC_VERB_GET_GPIO_DIRECTION, 0);
659797760abSAndrew Paprocki 	wake = snd_hda_codec_read(codec, nid, 0,
660797760abSAndrew Paprocki 				  AC_VERB_GET_GPIO_WAKE_MASK, 0);
661797760abSAndrew Paprocki 	unsol  = snd_hda_codec_read(codec, nid, 0,
662797760abSAndrew Paprocki 				    AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
663797760abSAndrew Paprocki 	sticky = snd_hda_codec_read(codec, nid, 0,
664797760abSAndrew Paprocki 				    AC_VERB_GET_GPIO_STICKY_MASK, 0);
665797760abSAndrew Paprocki 	data = snd_hda_codec_read(codec, nid, 0,
666797760abSAndrew Paprocki 				  AC_VERB_GET_GPIO_DATA, 0);
667797760abSAndrew Paprocki 	for (i = 0; i < max; ++i)
668797760abSAndrew Paprocki 		snd_iprintf(buffer,
669797760abSAndrew Paprocki 			    "  IO[%d]: enable=%d, dir=%d, wake=%d, "
67085639646STakashi Iwai 			    "sticky=%d, data=%d, unsol=%d\n", i,
671797760abSAndrew Paprocki 			    (enable & (1<<i)) ? 1 : 0,
672797760abSAndrew Paprocki 			    (direction & (1<<i)) ? 1 : 0,
673797760abSAndrew Paprocki 			    (wake & (1<<i)) ? 1 : 0,
674797760abSAndrew Paprocki 			    (sticky & (1<<i)) ? 1 : 0,
67585639646STakashi Iwai 			    (data & (1<<i)) ? 1 : 0,
67685639646STakashi Iwai 			    (unsol & (1<<i)) ? 1 : 0);
677797760abSAndrew Paprocki 	/* FIXME: add GPO and GPI pin information */
6785b0cb1d8SJaroslav Kysela 	print_nid_array(buffer, codec, nid, &codec->mixers);
6795b0cb1d8SJaroslav Kysela 	print_nid_array(buffer, codec, nid, &codec->nids);
680797760abSAndrew Paprocki }
6811da177e4SLinus Torvalds 
print_dpmst_connections(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid,int dev_num)682*19bb4f78SKai Vehmanen static void print_dpmst_connections(struct snd_info_buffer *buffer, struct hda_codec *codec,
683*19bb4f78SKai Vehmanen 				    hda_nid_t nid, int dev_num)
684*19bb4f78SKai Vehmanen {
685*19bb4f78SKai Vehmanen 	int c, conn_len, curr, dev_id_saved;
686*19bb4f78SKai Vehmanen 	hda_nid_t *conn;
687*19bb4f78SKai Vehmanen 
688*19bb4f78SKai Vehmanen 	conn_len = snd_hda_get_num_raw_conns(codec, nid);
689*19bb4f78SKai Vehmanen 	if (conn_len <= 0)
690*19bb4f78SKai Vehmanen 		return;
691*19bb4f78SKai Vehmanen 
692*19bb4f78SKai Vehmanen 	conn = kmalloc_array(conn_len, sizeof(hda_nid_t), GFP_KERNEL);
693*19bb4f78SKai Vehmanen 	if (!conn)
694*19bb4f78SKai Vehmanen 		return;
695*19bb4f78SKai Vehmanen 
696*19bb4f78SKai Vehmanen 	dev_id_saved = snd_hda_get_dev_select(codec, nid);
697*19bb4f78SKai Vehmanen 
698*19bb4f78SKai Vehmanen 	snd_hda_set_dev_select(codec, nid, dev_num);
699*19bb4f78SKai Vehmanen 	curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
700*19bb4f78SKai Vehmanen 	if (snd_hda_get_raw_connections(codec, nid, conn, conn_len) < 0)
701*19bb4f78SKai Vehmanen 		goto out;
702*19bb4f78SKai Vehmanen 
703*19bb4f78SKai Vehmanen 	for (c = 0; c < conn_len; c++) {
704*19bb4f78SKai Vehmanen 		snd_iprintf(buffer, " 0x%02x", conn[c]);
705*19bb4f78SKai Vehmanen 		if (c == curr)
706*19bb4f78SKai Vehmanen 			snd_iprintf(buffer, "*");
707*19bb4f78SKai Vehmanen 	}
708*19bb4f78SKai Vehmanen 
709*19bb4f78SKai Vehmanen out:
710*19bb4f78SKai Vehmanen 	kfree(conn);
711*19bb4f78SKai Vehmanen 	snd_hda_set_dev_select(codec, nid, dev_id_saved);
712*19bb4f78SKai Vehmanen }
713*19bb4f78SKai Vehmanen 
print_device_list(struct snd_info_buffer * buffer,struct hda_codec * codec,hda_nid_t nid)7147a624ea5SMengdong Lin static void print_device_list(struct snd_info_buffer *buffer,
7157a624ea5SMengdong Lin 			    struct hda_codec *codec, hda_nid_t nid)
7167a624ea5SMengdong Lin {
7177a624ea5SMengdong Lin 	int i, curr = -1;
7187a624ea5SMengdong Lin 	u8 dev_list[AC_MAX_DEV_LIST_LEN];
7197a624ea5SMengdong Lin 	int devlist_len;
7207a624ea5SMengdong Lin 
7217a624ea5SMengdong Lin 	devlist_len = snd_hda_get_devices(codec, nid, dev_list,
7227a624ea5SMengdong Lin 					AC_MAX_DEV_LIST_LEN);
7237a624ea5SMengdong Lin 	snd_iprintf(buffer, "  Devices: %d\n", devlist_len);
7247a624ea5SMengdong Lin 	if (devlist_len <= 0)
7257a624ea5SMengdong Lin 		return;
7267a624ea5SMengdong Lin 
7277a624ea5SMengdong Lin 	curr = snd_hda_codec_read(codec, nid, 0,
7287a624ea5SMengdong Lin 				AC_VERB_GET_DEVICE_SEL, 0);
7297a624ea5SMengdong Lin 
7307a624ea5SMengdong Lin 	for (i = 0; i < devlist_len; i++) {
7317a624ea5SMengdong Lin 		if (i == curr)
7327a624ea5SMengdong Lin 			snd_iprintf(buffer, "    *");
7337a624ea5SMengdong Lin 		else
7347a624ea5SMengdong Lin 			snd_iprintf(buffer, "     ");
7357a624ea5SMengdong Lin 
7367a624ea5SMengdong Lin 		snd_iprintf(buffer,
737*19bb4f78SKai Vehmanen 			"Dev %02d: PD = %d, ELDV = %d, IA = %d, Connections [", i,
7387a624ea5SMengdong Lin 			!!(dev_list[i] & AC_DE_PD),
7397a624ea5SMengdong Lin 			!!(dev_list[i] & AC_DE_ELDV),
7407a624ea5SMengdong Lin 			!!(dev_list[i] & AC_DE_IA));
741*19bb4f78SKai Vehmanen 
742*19bb4f78SKai Vehmanen 		print_dpmst_connections(buffer, codec, nid, i);
743*19bb4f78SKai Vehmanen 
744*19bb4f78SKai Vehmanen 		snd_iprintf(buffer, " ]\n");
7457a624ea5SMengdong Lin 	}
7467a624ea5SMengdong Lin }
7477a624ea5SMengdong Lin 
print_codec_core_info(struct hdac_device * codec,struct snd_info_buffer * buffer)7487639a06cSTakashi Iwai static void print_codec_core_info(struct hdac_device *codec,
749d01ce99fSTakashi Iwai 				  struct snd_info_buffer *buffer)
7501da177e4SLinus Torvalds {
751812a2ccaSTakashi Iwai 	snd_iprintf(buffer, "Codec: ");
752812a2ccaSTakashi Iwai 	if (codec->vendor_name && codec->chip_name)
753812a2ccaSTakashi Iwai 		snd_iprintf(buffer, "%s %s\n",
754812a2ccaSTakashi Iwai 			    codec->vendor_name, codec->chip_name);
755812a2ccaSTakashi Iwai 	else
756812a2ccaSTakashi Iwai 		snd_iprintf(buffer, "Not Set\n");
7571da177e4SLinus Torvalds 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
75879c944adSJaroslav Kysela 	if (codec->afg)
75979c944adSJaroslav Kysela 		snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n",
76079c944adSJaroslav Kysela 			codec->afg_function_id, codec->afg_unsol);
76179c944adSJaroslav Kysela 	if (codec->mfg)
76279c944adSJaroslav Kysela 		snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n",
76379c944adSJaroslav Kysela 			codec->mfg_function_id, codec->mfg_unsol);
764234b4346SPascal de Bruijn 	snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
765234b4346SPascal de Bruijn 	snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
7661da177e4SLinus Torvalds 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
767e25c05f1SJonathan Phenix 
768e25c05f1SJonathan Phenix 	if (codec->mfg)
769e25c05f1SJonathan Phenix 		snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
770e25c05f1SJonathan Phenix 	else
771e25c05f1SJonathan Phenix 		snd_iprintf(buffer, "No Modem Function Group found\n");
7727639a06cSTakashi Iwai }
773e25c05f1SJonathan Phenix 
print_codec_info(struct snd_info_entry * entry,struct snd_info_buffer * buffer)7747639a06cSTakashi Iwai static void print_codec_info(struct snd_info_entry *entry,
7757639a06cSTakashi Iwai 			     struct snd_info_buffer *buffer)
7767639a06cSTakashi Iwai {
7777639a06cSTakashi Iwai 	struct hda_codec *codec = entry->private_data;
7787639a06cSTakashi Iwai 	hda_nid_t nid, fg;
7797639a06cSTakashi Iwai 	int i, nodes;
7807639a06cSTakashi Iwai 
7817639a06cSTakashi Iwai 	print_codec_core_info(&codec->core, buffer);
7827639a06cSTakashi Iwai 	fg = codec->core.afg;
7837639a06cSTakashi Iwai 	if (!fg)
784ec9e1c5cSTakashi Iwai 		return;
785cb53c626STakashi Iwai 	snd_hda_power_up(codec);
786b90d7760STakashi Iwai 	snd_iprintf(buffer, "Default PCM:\n");
7877639a06cSTakashi Iwai 	print_pcm_caps(buffer, codec, fg);
7881da177e4SLinus Torvalds 	snd_iprintf(buffer, "Default Amp-In caps: ");
7897639a06cSTakashi Iwai 	print_amp_caps(buffer, codec, fg, HDA_INPUT);
7901da177e4SLinus Torvalds 	snd_iprintf(buffer, "Default Amp-Out caps: ");
7917639a06cSTakashi Iwai 	print_amp_caps(buffer, codec, fg, HDA_OUTPUT);
7927639a06cSTakashi Iwai 	snd_iprintf(buffer, "State of AFG node 0x%02x:\n", fg);
7937639a06cSTakashi Iwai 	print_power_state(buffer, codec, fg);
7941da177e4SLinus Torvalds 
7957639a06cSTakashi Iwai 	nodes = snd_hda_get_sub_nodes(codec, fg, &nid);
7961da177e4SLinus Torvalds 	if (! nid || nodes < 0) {
7971da177e4SLinus Torvalds 		snd_iprintf(buffer, "Invalid AFG subtree\n");
798cb53c626STakashi Iwai 		snd_hda_power_down(codec);
7991da177e4SLinus Torvalds 		return;
8001da177e4SLinus Torvalds 	}
801797760abSAndrew Paprocki 
8027639a06cSTakashi Iwai 	print_gpio(buffer, codec, fg);
8032d34e1b3STakashi Iwai 	if (codec->proc_widget_hook)
8047639a06cSTakashi Iwai 		codec->proc_widget_hook(buffer, codec, fg);
805797760abSAndrew Paprocki 
8061da177e4SLinus Torvalds 	for (i = 0; i < nodes; i++, nid++) {
807d01ce99fSTakashi Iwai 		unsigned int wid_caps =
8089ba17b4dSTakashi Iwai 			param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
809a22d543aSTakashi Iwai 		unsigned int wid_type = get_wcaps_type(wid_caps);
8104eea3091STakashi Iwai 		hda_nid_t *conn = NULL;
811797760abSAndrew Paprocki 		int conn_len = 0;
8123e289f16STakashi Iwai 
8131da177e4SLinus Torvalds 		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
8141da177e4SLinus Torvalds 			    get_wid_type_name(wid_type), wid_caps);
815c4920606STakashi Iwai 		if (wid_caps & AC_WCAP_STEREO) {
816fd72d008SWu Fengguang 			unsigned int chans = get_wcaps_channels(wid_caps);
817c4920606STakashi Iwai 			if (chans == 2)
8181da177e4SLinus Torvalds 				snd_iprintf(buffer, " Stereo");
8191da177e4SLinus Torvalds 			else
820c4920606STakashi Iwai 				snd_iprintf(buffer, " %d-Channels", chans);
821c4920606STakashi Iwai 		} else
8221da177e4SLinus Torvalds 			snd_iprintf(buffer, " Mono");
8231da177e4SLinus Torvalds 		if (wid_caps & AC_WCAP_DIGITAL)
8241da177e4SLinus Torvalds 			snd_iprintf(buffer, " Digital");
8251da177e4SLinus Torvalds 		if (wid_caps & AC_WCAP_IN_AMP)
8261da177e4SLinus Torvalds 			snd_iprintf(buffer, " Amp-In");
8271da177e4SLinus Torvalds 		if (wid_caps & AC_WCAP_OUT_AMP)
8281da177e4SLinus Torvalds 			snd_iprintf(buffer, " Amp-Out");
829797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_STRIPE)
830797760abSAndrew Paprocki 			snd_iprintf(buffer, " Stripe");
831797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_LR_SWAP)
832797760abSAndrew Paprocki 			snd_iprintf(buffer, " R/L");
833c4920606STakashi Iwai 		if (wid_caps & AC_WCAP_CP_CAPS)
834c4920606STakashi Iwai 			snd_iprintf(buffer, " CP");
8351da177e4SLinus Torvalds 		snd_iprintf(buffer, "\n");
8361da177e4SLinus Torvalds 
8375b0cb1d8SJaroslav Kysela 		print_nid_array(buffer, codec, nid, &codec->mixers);
8385b0cb1d8SJaroslav Kysela 		print_nid_array(buffer, codec, nid, &codec->nids);
8393911a4c1SJaroslav Kysela 		print_nid_pcms(buffer, codec, nid);
8403911a4c1SJaroslav Kysela 
841e1716139STakashi Iwai 		/* volume knob is a special widget that always have connection
842e1716139STakashi Iwai 		 * list
843e1716139STakashi Iwai 		 */
844e1716139STakashi Iwai 		if (wid_type == AC_WID_VOL_KNB)
845e1716139STakashi Iwai 			wid_caps |= AC_WCAP_CONN_LIST;
846e1716139STakashi Iwai 
8474eea3091STakashi Iwai 		if (wid_caps & AC_WCAP_CONN_LIST) {
8484eea3091STakashi Iwai 			conn_len = snd_hda_get_num_raw_conns(codec, nid);
8494eea3091STakashi Iwai 			if (conn_len > 0) {
8506da2ec56SKees Cook 				conn = kmalloc_array(conn_len,
8516da2ec56SKees Cook 						     sizeof(hda_nid_t),
8524eea3091STakashi Iwai 						     GFP_KERNEL);
8534eea3091STakashi Iwai 				if (!conn)
8544eea3091STakashi Iwai 					return;
8554eea3091STakashi Iwai 				if (snd_hda_get_raw_connections(codec, nid, conn,
8564eea3091STakashi Iwai 								conn_len) < 0)
8574eea3091STakashi Iwai 					conn_len = 0;
8584eea3091STakashi Iwai 			}
8594eea3091STakashi Iwai 		}
8603e289f16STakashi Iwai 
8611da177e4SLinus Torvalds 		if (wid_caps & AC_WCAP_IN_AMP) {
8621da177e4SLinus Torvalds 			snd_iprintf(buffer, "  Amp-In caps: ");
8631da177e4SLinus Torvalds 			print_amp_caps(buffer, codec, nid, HDA_INPUT);
8641da177e4SLinus Torvalds 			snd_iprintf(buffer, "  Amp-In vals: ");
8654f32456eSMichael Karcher 			if (wid_type == AC_WID_PIN ||
8664f32456eSMichael Karcher 			    (codec->single_adc_amp &&
8674f32456eSMichael Karcher 			     wid_type == AC_WID_AUD_IN))
8681da177e4SLinus Torvalds 				print_amp_vals(buffer, codec, nid, HDA_INPUT,
869cc261738STakashi Iwai 					       wid_caps, 1);
8704f32456eSMichael Karcher 			else
8714f32456eSMichael Karcher 				print_amp_vals(buffer, codec, nid, HDA_INPUT,
872cc261738STakashi Iwai 					       wid_caps, conn_len);
8731da177e4SLinus Torvalds 		}
8741da177e4SLinus Torvalds 		if (wid_caps & AC_WCAP_OUT_AMP) {
8751da177e4SLinus Torvalds 			snd_iprintf(buffer, "  Amp-Out caps: ");
8761da177e4SLinus Torvalds 			print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
8771da177e4SLinus Torvalds 			snd_iprintf(buffer, "  Amp-Out vals: ");
8789421f954STakashi Iwai 			if (wid_type == AC_WID_PIN &&
8799421f954STakashi Iwai 			    codec->pin_amp_workaround)
8809421f954STakashi Iwai 				print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
881cc261738STakashi Iwai 					       wid_caps, conn_len);
8829421f954STakashi Iwai 			else
8831da177e4SLinus Torvalds 				print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
884cc261738STakashi Iwai 					       wid_caps, 1);
8851da177e4SLinus Torvalds 		}
8861da177e4SLinus Torvalds 
887e97a5167STakashi Iwai 		switch (wid_type) {
888797760abSAndrew Paprocki 		case AC_WID_PIN: {
889797760abSAndrew Paprocki 			int supports_vref;
890797760abSAndrew Paprocki 			print_pin_caps(buffer, codec, nid, &supports_vref);
891797760abSAndrew Paprocki 			print_pin_ctls(buffer, codec, nid, supports_vref);
892e97a5167STakashi Iwai 			break;
893797760abSAndrew Paprocki 		}
894e97a5167STakashi Iwai 		case AC_WID_VOL_KNB:
895797760abSAndrew Paprocki 			print_vol_knob(buffer, codec, nid);
896e97a5167STakashi Iwai 			break;
897e97a5167STakashi Iwai 		case AC_WID_AUD_OUT:
898e97a5167STakashi Iwai 		case AC_WID_AUD_IN:
899797760abSAndrew Paprocki 			print_audio_io(buffer, codec, nid, wid_type);
900797760abSAndrew Paprocki 			if (wid_caps & AC_WCAP_DIGITAL)
901797760abSAndrew Paprocki 				print_digital_conv(buffer, codec, nid);
902e97a5167STakashi Iwai 			if (wid_caps & AC_WCAP_FORMAT_OVRD) {
903b90d7760STakashi Iwai 				snd_iprintf(buffer, "  PCM:\n");
9041da177e4SLinus Torvalds 				print_pcm_caps(buffer, codec, nid);
9051da177e4SLinus Torvalds 			}
906e97a5167STakashi Iwai 			break;
907e97a5167STakashi Iwai 		}
9081da177e4SLinus Torvalds 
909797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_UNSOL_CAP)
910797760abSAndrew Paprocki 			print_unsol_cap(buffer, codec, nid);
911b7027cc2STakashi Iwai 
912797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_POWER)
913797760abSAndrew Paprocki 			print_power_state(buffer, codec, nid);
914797760abSAndrew Paprocki 
915797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_DELAY)
916797760abSAndrew Paprocki 			snd_iprintf(buffer, "  Delay: %d samples\n",
917797760abSAndrew Paprocki 				    (wid_caps & AC_WCAP_DELAY) >>
918797760abSAndrew Paprocki 				    AC_WCAP_DELAY_SHIFT);
919797760abSAndrew Paprocki 
9207a624ea5SMengdong Lin 		if (wid_type == AC_WID_PIN && codec->dp_mst)
9217a624ea5SMengdong Lin 			print_device_list(buffer, codec, nid);
9227a624ea5SMengdong Lin 
923797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_CONN_LIST)
924797760abSAndrew Paprocki 			print_conn_list(buffer, codec, nid, wid_type,
925797760abSAndrew Paprocki 					conn, conn_len);
926797760abSAndrew Paprocki 
927797760abSAndrew Paprocki 		if (wid_caps & AC_WCAP_PROC_WID)
928797760abSAndrew Paprocki 			print_proc_caps(buffer, codec, nid);
929797760abSAndrew Paprocki 
930daead538STakashi Iwai 		if (codec->proc_widget_hook)
931daead538STakashi Iwai 			codec->proc_widget_hook(buffer, codec, nid);
9324eea3091STakashi Iwai 
9334eea3091STakashi Iwai 		kfree(conn);
934e1716139STakashi Iwai 	}
935cb53c626STakashi Iwai 	snd_hda_power_down(codec);
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds 
9381da177e4SLinus Torvalds /*
9391da177e4SLinus Torvalds  * create a proc read
9401da177e4SLinus Torvalds  */
snd_hda_codec_proc_new(struct hda_codec * codec)9411da177e4SLinus Torvalds int snd_hda_codec_proc_new(struct hda_codec *codec)
9421da177e4SLinus Torvalds {
9431da177e4SLinus Torvalds 	char name[32];
9441da177e4SLinus Torvalds 
9457639a06cSTakashi Iwai 	snprintf(name, sizeof(name), "codec#%d", codec->core.addr);
94647f2769bSTakashi Iwai 	return snd_card_ro_proc_new(codec->card, name, codec, print_codec_info);
9471da177e4SLinus Torvalds }
9481da177e4SLinus Torvalds 
949