[ALSA] hda_proc - Add a number of new settings to proc codec output

This patch adds additional output to the /proc codec#X info.
The following pieces of information are added to the output:
-  Balanced, L/R swap, trigger, impedance sense pin capabilities
-  Vref pin capabilities
-  Current Vref pin widget control setting
-  Default configuration association, sequence, and misc bit test
-  EAPD/BTL bits conveying balanced mode, EAPD, and L/R swap
-  Power state modified to show state name as well as setting vs actual value
-  GPIO parameter output on Audio Function Group, including enumeration of IO
   pins which are indicated present (Any I and O pins are not output at this
   time)
-  Stripe and L/R swap widget capabilities
-  All digital converter bits: enable, validity, validity config, preemphasis,
   copyright, non-audio, professional, generation level, and content category
-  Converter stream and channel values for in/out widgets
-  SDI select value for in widgets
-  Unsolicited response widget capability tag and enabled bit
-  Delay widget capability value
-  Processing widget capability benign bit and number of coefficients
-  Realtek Define Registers: processing coefficient, coefficient index
[Also, fixed space/tab issues and make codes a bit more readable
  -- Takashi]

Signed-off-by: Andrew Paprocki <andrew@ishiboo.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 719e46f..eb4a2ae 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -84,7 +84,9 @@
 #define AC_VERB_GET_GPIO_DATA			0x0f15
 #define AC_VERB_GET_GPIO_MASK			0x0f16
 #define AC_VERB_GET_GPIO_DIRECTION		0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK		0x0f18
 #define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK	0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK		0x0f1a
 #define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
 /* f20: AFG/MFG */
 #define AC_VERB_GET_SUBSYSTEM_ID		0x0f20
@@ -112,7 +114,9 @@
 #define AC_VERB_SET_GPIO_DATA			0x715
 #define AC_VERB_SET_GPIO_MASK			0x716
 #define AC_VERB_SET_GPIO_DIRECTION		0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK		0x718
 #define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK	0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK		0x71a
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0	0x71c
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
@@ -185,6 +189,27 @@
 #define AC_SUPFMT_FLOAT32		(1<<1)
 #define AC_SUPFMT_AC3			(1<<2)
 
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT		(0xff<<0)
+#define AC_GPIO_O_COUNT			(0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT		8
+#define AC_GPIO_I_COUNT			(0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT		16
+#define AC_GPIO_UNSOLICITED		(1<<30)
+#define AC_GPIO_WAKE			(1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL			(0xf<<0)
+#define AC_CONV_STREAM			(0xf<<4)
+#define AC_CONV_STREAM_SHIFT		4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT			(0xf<<0)
+
+/* Unsolicited response */
+#define AC_UNSOL_TAG			(0x3f<<0)
+#define AC_UNSOL_ENABLED		(1<<7)
+
 /* Pin widget capabilies */
 #define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
 #define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
@@ -230,6 +255,9 @@
 #define AC_PWRST_D3SUP			(1<<3)
 
 /* Power state values */
+#define AC_PWRST_SETTING		(0xf<<0)
+#define AC_PWRST_ACTUAL			(0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT		4
 #define AC_PWRST_D0			0x00
 #define AC_PWRST_D1			0x01
 #define AC_PWRST_D2			0x02
@@ -238,6 +266,7 @@
 /* Processing capabilies */
 #define AC_PCAP_BENIGN			(1<<0)
 #define AC_PCAP_NUM_COEF		(0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT		8
 
 /* Volume knobs capabilities */
 #define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
@@ -274,6 +303,9 @@
 #define AC_DIG1_PROFESSIONAL		(1<<6)
 #define AC_DIG1_LEVEL			(1<<7)
 
+/* DIGITAL2 bits */
+#define AC_DIG2_CC			(0x7f<<0)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_VREFEN		(0x7<<0)
 #define AC_PINCTL_VREF_HIZ		0	/* Hi-Z */
@@ -288,12 +320,22 @@
 /* Unsolicited response - 8bit */
 #define AC_USRSP_EN			(1<<7)
 
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK	(0x7fffffff)
+#define AC_PINSENSE_PRESENCE		(1<<31)
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED		(1<<0)
+#define AC_EAPDBTL_EAPD			(1<<1)
+#define AC_EAPDBTL_LR_SWAP		(1<<2)
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE		(0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
 #define AC_DEFCFG_ASSOC_SHIFT		4
 #define AC_DEFCFG_MISC			(0xf<<8)
 #define AC_DEFCFG_MISC_SHIFT		8
+#define AC_DEFCFG_MISC_NO_PRESENCE	(1<<0)
 #define AC_DEFCFG_COLOR			(0xf<<12)
 #define AC_DEFCFG_COLOR_SHIFT		12
 #define AC_DEFCFG_CONN_TYPE		(0xf<<16)
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 4b8d644..35a630d 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -202,7 +202,8 @@
 }
 
 static void print_pin_caps(struct snd_info_buffer *buffer,
-			   struct hda_codec *codec, hda_nid_t nid)
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int *supports_vref)
 {
 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
 	static char *jack_types[16] = {
@@ -226,7 +227,45 @@
 		snd_iprintf(buffer, " EAPD");
 	if (caps & AC_PINCAP_PRES_DETECT)
 		snd_iprintf(buffer, " Detect");
+	if (caps & AC_PINCAP_BALANCE)
+		snd_iprintf(buffer, " Balanced");
+	if (caps & AC_PINCAP_LR_SWAP)
+		snd_iprintf(buffer, " R/L");
+	if (caps & AC_PINCAP_TRIG_REQ)
+		snd_iprintf(buffer, " Trigger");
+	if (caps & AC_PINCAP_IMP_SENSE)
+		snd_iprintf(buffer, " ImpSense");
 	snd_iprintf(buffer, "\n");
+	if (caps & AC_PINCAP_VREF) {
+		unsigned int vref =
+			(caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+		snd_iprintf(buffer, "    Vref caps:");
+		if (vref & AC_PINCAP_VREF_HIZ)
+			snd_iprintf(buffer, " HIZ");
+		if (vref & AC_PINCAP_VREF_50)
+			snd_iprintf(buffer, " 50");
+		if (vref & AC_PINCAP_VREF_GRD)
+			snd_iprintf(buffer, " GRD");
+		if (vref & AC_PINCAP_VREF_80)
+			snd_iprintf(buffer, " 80");
+		if (vref & AC_PINCAP_VREF_100)
+			snd_iprintf(buffer, " 100");
+		snd_iprintf(buffer, "\n");
+		*supports_vref = 1;
+	} else
+		*supports_vref = 0;
+	if (caps & AC_PINCAP_EAPD) {
+		val = snd_hda_codec_read(codec, nid, 0,
+					 AC_VERB_GET_EAPD_BTLENABLE, 0);
+		snd_iprintf(buffer, "  EAPD 0x%x:", val);
+		if (val & AC_EAPDBTL_BALANCED)
+			snd_iprintf(buffer, " BALANCED");
+		if (val & AC_EAPDBTL_EAPD)
+			snd_iprintf(buffer, " EAPD");
+		if (val & AC_EAPDBTL_LR_SWAP)
+			snd_iprintf(buffer, " R/L");
+		snd_iprintf(buffer, "\n");
+	}
 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
@@ -236,13 +275,233 @@
 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
 		    get_jack_connection(caps),
 		    get_jack_color(caps));
-	if (caps & AC_PINCAP_EAPD) {
-		val = snd_hda_codec_read(codec, nid, 0,
-					 AC_VERB_GET_EAPD_BTLENABLE, 0);
-		snd_iprintf(buffer, "  EAPD: 0x%x\n", val);
+	/* Default association and sequence values refer to default grouping
+	 * of pin complexes and their sequence within the group. This is used
+	 * for priority and resource allocation.
+	 */
+	snd_iprintf(buffer, "    DefAssociation = 0x%x, Sequence = 0x%x\n",
+		    (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
+		    caps & AC_DEFCFG_SEQUENCE);
+	if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
+	    AC_DEFCFG_MISC_NO_PRESENCE) {
+		/* Miscellaneous bit indicates external hardware does not
+		 * support presence detection even if the pin complex
+		 * indicates it is supported.
+		 */
+		snd_iprintf(buffer, "    Misc = NO_PRESENCE\n");
 	}
 }
 
+static void print_pin_ctls(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int supports_vref)
+{
+	unsigned int pinctls;
+
+	pinctls = snd_hda_codec_read(codec, nid, 0,
+				     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
+	if (pinctls & AC_PINCTL_IN_EN)
+		snd_iprintf(buffer, " IN");
+	if (pinctls & AC_PINCTL_OUT_EN)
+		snd_iprintf(buffer, " OUT");
+	if (pinctls & AC_PINCTL_HP_EN)
+		snd_iprintf(buffer, " HP");
+	if (supports_vref) {
+		int vref = pinctls & AC_PINCTL_VREFEN;
+		switch (vref) {
+		case AC_PINCTL_VREF_HIZ:
+			snd_iprintf(buffer, " VREF_HIZ");
+			break;
+		case AC_PINCTL_VREF_50:
+			snd_iprintf(buffer, " VREF_50");
+			break;
+		case AC_PINCTL_VREF_GRD:
+			snd_iprintf(buffer, " VREF_GRD");
+			break;
+		case AC_PINCTL_VREF_80:
+			snd_iprintf(buffer, " VREF_80");
+			break;
+		case AC_PINCTL_VREF_100:
+			snd_iprintf(buffer, " VREF_100");
+			break;
+		}
+	}
+	snd_iprintf(buffer, "\n");
+}
+
+static void print_vol_knob(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int cap = snd_hda_param_read(codec, nid,
+					      AC_PAR_VOL_KNB_CAP);
+	snd_iprintf(buffer, "  Volume-Knob: delta=%d, steps=%d, ",
+		    (cap >> 7) & 1, cap & 0x7f);
+	cap = snd_hda_codec_read(codec, nid, 0,
+				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+	snd_iprintf(buffer, "direct=%d, val=%d\n",
+		    (cap >> 7) & 1, cap & 0x7f);
+}
+
+static void print_audio_io(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   unsigned int wid_type)
+{
+	int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+	snd_iprintf(buffer,
+		    "  Converter: stream=%d, channel=%d\n",
+		    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
+		    conv & AC_CONV_CHANNEL);
+
+	if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
+		int sdi = snd_hda_codec_read(codec, nid, 0,
+					     AC_VERB_GET_SDI_SELECT, 0);
+		snd_iprintf(buffer, "  SDI-Select: %d\n",
+			    sdi & AC_SDI_SELECT);
+	}
+}
+
+static void print_digital_conv(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
+						AC_VERB_GET_DIGI_CONVERT_1, 0);
+	unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
+						AC_VERB_GET_DIGI_CONVERT_2, 0);
+	snd_iprintf(buffer, "  Digital:");
+	if (digi1 & AC_DIG1_ENABLE)
+		snd_iprintf(buffer, " Enabled");
+	if (digi1 & AC_DIG1_V)
+		snd_iprintf(buffer, " Validity");
+	if (digi1 & AC_DIG1_VCFG)
+		snd_iprintf(buffer, " ValidityCfg");
+	if (digi1 & AC_DIG1_EMPHASIS)
+		snd_iprintf(buffer, " Preemphasis");
+	if (digi1 & AC_DIG1_COPYRIGHT)
+		snd_iprintf(buffer, " Copyright");
+	if (digi1 & AC_DIG1_NONAUDIO)
+		snd_iprintf(buffer, " Non-Audio");
+	if (digi1 & AC_DIG1_PROFESSIONAL)
+		snd_iprintf(buffer, " Pro");
+	if (digi1 & AC_DIG1_LEVEL)
+		snd_iprintf(buffer, " GenLevel");
+	snd_iprintf(buffer, "\n");
+	snd_iprintf(buffer, "  Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
+}
+
+static const char *get_pwr_state(u32 state)
+{
+	static const char *buf[4] = {
+		"D0", "D1", "D2", "D3"
+	};
+	if (state < 4)
+		return buf[state];
+	return "UNKNOWN";
+}
+
+static void print_power_state(struct snd_info_buffer *buffer,
+			      struct hda_codec *codec, hda_nid_t nid)
+{
+	int pwr = snd_hda_codec_read(codec, nid, 0,
+				     AC_VERB_GET_POWER_STATE, 0);
+	snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
+		    get_pwr_state(pwr & AC_PWRST_SETTING),
+		    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
+				  AC_PWRST_ACTUAL_SHIFT));
+}
+
+static void print_unsol_cap(struct snd_info_buffer *buffer,
+			      struct hda_codec *codec, hda_nid_t nid)
+{
+	int unsol = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
+	snd_iprintf(buffer,
+		    "  Unsolicited: tag=%02x, enabled=%d\n",
+		    unsol & AC_UNSOL_TAG,
+		    (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
+}
+
+static void print_proc_caps(struct snd_info_buffer *buffer,
+			    struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int proc_caps = snd_hda_param_read(codec, nid,
+						    AC_PAR_PROC_CAP);
+	snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
+		    proc_caps & AC_PCAP_BENIGN,
+		    (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
+}
+
+static void 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)
+{
+	int c, curr = -1;
+
+	if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+		curr = snd_hda_codec_read(codec, nid, 0,
+					  AC_VERB_GET_CONNECT_SEL, 0);
+	snd_iprintf(buffer, "  Connection: %d\n", conn_len);
+	if (conn_len > 0) {
+		snd_iprintf(buffer, "    ");
+		for (c = 0; c < conn_len; c++) {
+			snd_iprintf(buffer, " 0x%02x", conn[c]);
+			if (c == curr)
+				snd_iprintf(buffer, "*");
+		}
+		snd_iprintf(buffer, "\n");
+	}
+}
+
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	int coeff = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_PROC_COEF, 0);
+	snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
+	coeff = snd_hda_codec_read(codec, nid, 0,
+				   AC_VERB_GET_COEF_INDEX, 0);
+	snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
+}
+
+static void print_gpio(struct snd_info_buffer *buffer,
+		       struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int gpio =
+		snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+	unsigned int enable, direction, wake, unsol, sticky, data;
+	int i, max;
+	snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
+		    "unsolicited=%d, wake=%d\n",
+		    gpio & AC_GPIO_IO_COUNT,
+		    (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
+		    (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
+		    (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
+		    (gpio & AC_GPIO_WAKE) ? 1 : 0);
+	max = gpio & AC_GPIO_IO_COUNT;
+	enable = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_MASK, 0);
+	direction = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_GPIO_DIRECTION, 0);
+	wake = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_GPIO_WAKE_MASK, 0);
+	unsol  = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
+	sticky = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_STICKY_MASK, 0);
+	data = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_GPIO_DATA, 0);
+	for (i = 0; i < max; ++i)
+		snd_iprintf(buffer,
+			    "  IO[%d]: enable=%d, dir=%d, wake=%d, "
+			    "sticky=%d, data=%d\n", i,
+			    (enable & (1<<i)) ? 1 : 0,
+			    (direction & (1<<i)) ? 1 : 0,
+			    (wake & (1<<i)) ? 1 : 0,
+			    (sticky & (1<<i)) ? 1 : 0,
+			    (data & (1<<i)) ? 1 : 0);
+	/* FIXME: add GPO and GPI pin information */
+}
 
 static void print_codec_info(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
@@ -280,15 +539,17 @@
 		snd_hda_power_down(codec);
 		return;
 	}
+
+	print_gpio(buffer, codec, codec->afg);
+
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int wid_caps =
 			snd_hda_param_read(codec, nid,
 					   AC_PAR_AUDIO_WIDGET_CAP);
 		unsigned int wid_type =
 			(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-		int conn_len = 0; 
 		hda_nid_t conn[HDA_MAX_CONNECTIONS];
-		unsigned int pinctls;
+		int conn_len = 0;
 
 		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
 			    get_wid_type_name(wid_type), wid_caps);
@@ -302,6 +563,10 @@
 			snd_iprintf(buffer, " Amp-In");
 		if (wid_caps & AC_WCAP_OUT_AMP)
 			snd_iprintf(buffer, " Amp-Out");
+		if (wid_caps & AC_WCAP_STRIPE)
+			snd_iprintf(buffer, " Stripe");
+		if (wid_caps & AC_WCAP_LR_SWAP)
+			snd_iprintf(buffer, " R/L");
 		snd_iprintf(buffer, "\n");
 
 		/* volume knob is a special widget that always have connection
@@ -330,33 +595,20 @@
 		}
 
 		switch (wid_type) {
-		case AC_WID_PIN:
-			print_pin_caps(buffer, codec, nid);
-			pinctls = snd_hda_codec_read(codec, nid, 0,
-					     AC_VERB_GET_PIN_WIDGET_CONTROL,
-						     0);
-			snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
-			if (pinctls & AC_PINCTL_IN_EN)
-				snd_iprintf(buffer, " IN");
-			if (pinctls & AC_PINCTL_OUT_EN)
-				snd_iprintf(buffer, " OUT");
-			if (pinctls & AC_PINCTL_HP_EN)
-				snd_iprintf(buffer, " HP");
-			snd_iprintf(buffer, "\n");
+		case AC_WID_PIN: {
+			int supports_vref;
+			print_pin_caps(buffer, codec, nid, &supports_vref);
+			print_pin_ctls(buffer, codec, nid, supports_vref);
 			break;
+		}
 		case AC_WID_VOL_KNB:
-			pinctls = snd_hda_param_read(codec, nid,
-						     AC_PAR_VOL_KNB_CAP);
-			snd_iprintf(buffer, "  Volume-Knob: delta=%d, "
-				    "steps=%d, ",
-				    (pinctls >> 7) & 1, pinctls & 0x7f);
-			pinctls = snd_hda_codec_read(codec, nid, 0,
-					AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
-			snd_iprintf(buffer, "direct=%d, val=%d\n",
-				    (pinctls >> 7) & 1, pinctls & 0x7f);
+			print_vol_knob(buffer, codec, nid);
 			break;
 		case AC_WID_AUD_OUT:
 		case AC_WID_AUD_IN:
+			print_audio_io(buffer, codec, nid, wid_type);
+			if (wid_caps & AC_WCAP_DIGITAL)
+				print_digital_conv(buffer, codec, nid);
 			if (wid_caps & AC_WCAP_FORMAT_OVRD) {
 				snd_iprintf(buffer, "  PCM:\n");
 				print_pcm_caps(buffer, codec, nid);
@@ -364,28 +616,27 @@
 			break;
 		}
 
-		if (wid_caps & AC_WCAP_POWER)
-			snd_iprintf(buffer, "  Power: 0x%x\n",
-				    snd_hda_codec_read(codec, nid, 0,
-						       AC_VERB_GET_POWER_STATE,
-						       0));
+		if (wid_caps & AC_WCAP_UNSOL_CAP)
+			print_unsol_cap(buffer, codec, nid);
 
-		if (wid_caps & AC_WCAP_CONN_LIST) {
-			int c, curr = -1;
-			if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
-				curr = snd_hda_codec_read(codec, nid, 0,
-					AC_VERB_GET_CONNECT_SEL, 0);
-			snd_iprintf(buffer, "  Connection: %d\n", conn_len);
-			if (conn_len > 0) {
-				snd_iprintf(buffer, "    ");
-				for (c = 0; c < conn_len; c++) {
-					snd_iprintf(buffer, " 0x%02x", conn[c]);
-					if (c == curr)
-						snd_iprintf(buffer, "*");
-				}
-				snd_iprintf(buffer, "\n");
-			}
-		}
+		if (wid_caps & AC_WCAP_POWER)
+			print_power_state(buffer, codec, nid);
+
+		if (wid_caps & AC_WCAP_DELAY)
+			snd_iprintf(buffer, "  Delay: %d samples\n",
+				    (wid_caps & AC_WCAP_DELAY) >>
+				    AC_WCAP_DELAY_SHIFT);
+
+		if (wid_caps & AC_WCAP_CONN_LIST)
+			print_conn_list(buffer, codec, nid, wid_type,
+					conn, conn_len);
+
+		if (wid_caps & AC_WCAP_PROC_WID)
+			print_proc_caps(buffer, codec, nid);
+
+		/* NID 0x20 == Realtek Define Registers */
+		if (codec->vendor_id == 0x10ec && nid == 0x20)
+			print_realtek_coef(buffer, codec, nid);
 	}
 	snd_hda_power_down(codec);
 }