| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Universal Interface for Intel High Definition Audio Codec | 
 | 3 |  *  | 
 | 4 |  * Generic proc interface | 
 | 5 |  * | 
 | 6 |  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | 
 | 7 |  * | 
 | 8 |  * | 
 | 9 |  *  This driver is free software; you can redistribute it and/or modify | 
 | 10 |  *  it under the terms of the GNU General Public License as published by | 
 | 11 |  *  the Free Software Foundation; either version 2 of the License, or | 
 | 12 |  *  (at your option) any later version. | 
 | 13 |  * | 
 | 14 |  *  This driver is distributed in the hope that it will be useful, | 
 | 15 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 16 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 17 |  *  GNU General Public License for more details. | 
 | 18 |  * | 
 | 19 |  *  You should have received a copy of the GNU General Public License | 
 | 20 |  *  along with this program; if not, write to the Free Software | 
 | 21 |  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA | 
 | 22 |  */ | 
 | 23 |  | 
 | 24 | #include <sound/driver.h> | 
 | 25 | #include <linux/init.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | #include <sound/core.h> | 
 | 27 | #include "hda_codec.h" | 
| Adrian Bunk | 1861204 | 2005-11-23 13:14:50 +0100 | [diff] [blame] | 28 | #include "hda_local.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 |  | 
 | 30 | static const char *get_wid_type_name(unsigned int wid_value) | 
 | 31 | { | 
 | 32 | 	static char *names[16] = { | 
 | 33 | 		[AC_WID_AUD_OUT] = "Audio Output", | 
 | 34 | 		[AC_WID_AUD_IN] = "Audio Input", | 
 | 35 | 		[AC_WID_AUD_MIX] = "Audio Mixer", | 
 | 36 | 		[AC_WID_AUD_SEL] = "Audio Selector", | 
 | 37 | 		[AC_WID_PIN] = "Pin Complex", | 
 | 38 | 		[AC_WID_POWER] = "Power Widget", | 
 | 39 | 		[AC_WID_VOL_KNB] = "Volume Knob Widget", | 
 | 40 | 		[AC_WID_BEEP] = "Beep Generator Widget", | 
 | 41 | 		[AC_WID_VENDOR] = "Vendor Defined Widget", | 
 | 42 | 	}; | 
 | 43 | 	wid_value &= 0xf; | 
 | 44 | 	if (names[wid_value]) | 
 | 45 | 		return names[wid_value]; | 
 | 46 | 	else | 
| Takashi Iwai | 3bc8952 | 2006-10-17 20:41:38 +0200 | [diff] [blame] | 47 | 		return "UNKNOWN Widget"; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 | } | 
 | 49 |  | 
| Takashi Iwai | c8b6bf9b | 2005-11-17 14:57:47 +0100 | [diff] [blame] | 50 | static void print_amp_caps(struct snd_info_buffer *buffer, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | 			   struct hda_codec *codec, hda_nid_t nid, int dir) | 
 | 52 | { | 
 | 53 | 	unsigned int caps; | 
| Jaroslav Kysela | 7f0e2f8 | 2006-07-05 17:39:14 +0200 | [diff] [blame] | 54 | 	caps = snd_hda_param_read(codec, nid, | 
 | 55 | 				  dir == HDA_OUTPUT ? | 
 | 56 | 				    AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 57 | 	if (caps == -1 || caps == 0) { | 
 | 58 | 		snd_iprintf(buffer, "N/A\n"); | 
 | 59 | 		return; | 
 | 60 | 	} | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 61 | 	snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, " | 
 | 62 | 		    "mute=%x\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | 		    caps & AC_AMPCAP_OFFSET, | 
 | 64 | 		    (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, | 
 | 65 | 		    (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, | 
 | 66 | 		    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); | 
 | 67 | } | 
 | 68 |  | 
| Takashi Iwai | c8b6bf9b | 2005-11-17 14:57:47 +0100 | [diff] [blame] | 69 | static void print_amp_vals(struct snd_info_buffer *buffer, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | 			   struct hda_codec *codec, hda_nid_t nid, | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 71 | 			   int dir, int stereo, int indices) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | { | 
 | 73 | 	unsigned int val; | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 74 | 	int i; | 
 | 75 |  | 
| Jaroslav Kysela | 7f0e2f8 | 2006-07-05 17:39:14 +0200 | [diff] [blame] | 76 | 	dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 77 | 	for (i = 0; i < indices; i++) { | 
 | 78 | 		snd_iprintf(buffer, " ["); | 
 | 79 | 		if (stereo) { | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 80 | 			val = snd_hda_codec_read(codec, nid, 0, | 
 | 81 | 						 AC_VERB_GET_AMP_GAIN_MUTE, | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 82 | 						 AC_AMP_GET_LEFT | dir | i); | 
 | 83 | 			snd_iprintf(buffer, "0x%02x ", val); | 
 | 84 | 		} | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 85 | 		val = snd_hda_codec_read(codec, nid, 0, | 
 | 86 | 					 AC_VERB_GET_AMP_GAIN_MUTE, | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 87 | 					 AC_AMP_GET_RIGHT | dir | i); | 
 | 88 | 		snd_iprintf(buffer, "0x%02x]", val); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 | 	} | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 90 | 	snd_iprintf(buffer, "\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | } | 
 | 92 |  | 
| Takashi Iwai | b90d776 | 2006-11-07 16:10:06 +0100 | [diff] [blame] | 93 | static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) | 
 | 94 | { | 
 | 95 | 	static unsigned int rates[] = { | 
 | 96 | 		8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, | 
 | 97 | 		96000, 176400, 192000, 384000 | 
 | 98 | 	}; | 
 | 99 | 	int i; | 
 | 100 |  | 
 | 101 | 	pcm &= AC_SUPPCM_RATES; | 
 | 102 | 	snd_iprintf(buffer, "    rates [0x%x]:", pcm); | 
 | 103 | 	for (i = 0; i < ARRAY_SIZE(rates); i++)  | 
 | 104 | 		if (pcm & (1 << i)) | 
 | 105 | 			snd_iprintf(buffer, " %d", rates[i]); | 
 | 106 | 	snd_iprintf(buffer, "\n"); | 
 | 107 | } | 
 | 108 |  | 
 | 109 | static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) | 
 | 110 | { | 
 | 111 | 	static unsigned int bits[] = { 8, 16, 20, 24, 32 }; | 
 | 112 | 	int i; | 
 | 113 |  | 
 | 114 | 	pcm = (pcm >> 16) & 0xff; | 
 | 115 | 	snd_iprintf(buffer, "    bits [0x%x]:", pcm); | 
 | 116 | 	for (i = 0; i < ARRAY_SIZE(bits); i++) | 
 | 117 | 		if (pcm & (1 << i)) | 
 | 118 | 			snd_iprintf(buffer, " %d", bits[i]); | 
 | 119 | 	snd_iprintf(buffer, "\n"); | 
 | 120 | } | 
 | 121 |  | 
 | 122 | static void print_pcm_formats(struct snd_info_buffer *buffer, | 
 | 123 | 			      unsigned int streams) | 
 | 124 | { | 
 | 125 | 	snd_iprintf(buffer, "    formats [0x%x]:", streams & 0xf); | 
 | 126 | 	if (streams & AC_SUPFMT_PCM) | 
 | 127 | 		snd_iprintf(buffer, " PCM"); | 
 | 128 | 	if (streams & AC_SUPFMT_FLOAT32) | 
 | 129 | 		snd_iprintf(buffer, " FLOAT"); | 
 | 130 | 	if (streams & AC_SUPFMT_AC3) | 
 | 131 | 		snd_iprintf(buffer, " AC3"); | 
 | 132 | 	snd_iprintf(buffer, "\n"); | 
 | 133 | } | 
 | 134 |  | 
| Takashi Iwai | c8b6bf9b | 2005-11-17 14:57:47 +0100 | [diff] [blame] | 135 | static void print_pcm_caps(struct snd_info_buffer *buffer, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 136 | 			   struct hda_codec *codec, hda_nid_t nid) | 
 | 137 | { | 
 | 138 | 	unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM); | 
 | 139 | 	unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 
 | 140 | 	if (pcm == -1 || stream == -1) { | 
 | 141 | 		snd_iprintf(buffer, "N/A\n"); | 
 | 142 | 		return; | 
 | 143 | 	} | 
| Takashi Iwai | b90d776 | 2006-11-07 16:10:06 +0100 | [diff] [blame] | 144 | 	print_pcm_rates(buffer, pcm); | 
 | 145 | 	print_pcm_bits(buffer, pcm); | 
 | 146 | 	print_pcm_formats(buffer, stream); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | } | 
 | 148 |  | 
 | 149 | static const char *get_jack_location(u32 cfg) | 
 | 150 | { | 
 | 151 | 	static char *bases[7] = { | 
 | 152 | 		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", | 
 | 153 | 	}; | 
 | 154 | 	static unsigned char specials_idx[] = { | 
 | 155 | 		0x07, 0x08, | 
 | 156 | 		0x17, 0x18, 0x19, | 
 | 157 | 		0x37, 0x38 | 
 | 158 | 	}; | 
 | 159 | 	static char *specials[] = { | 
 | 160 | 		"Rear Panel", "Drive Bar", | 
 | 161 | 		"Riser", "HDMI", "ATAPI", | 
 | 162 | 		"Mobile-In", "Mobile-Out" | 
 | 163 | 	}; | 
 | 164 | 	int i; | 
 | 165 | 	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; | 
 | 166 | 	if ((cfg & 0x0f) < 7) | 
 | 167 | 		return bases[cfg & 0x0f]; | 
 | 168 | 	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { | 
 | 169 | 		if (cfg == specials_idx[i]) | 
 | 170 | 			return specials[i]; | 
 | 171 | 	} | 
 | 172 | 	return "UNKNOWN"; | 
 | 173 | } | 
 | 174 |  | 
 | 175 | static const char *get_jack_connection(u32 cfg) | 
 | 176 | { | 
 | 177 | 	static char *names[16] = { | 
 | 178 | 		"Unknown", "1/8", "1/4", "ATAPI", | 
 | 179 | 		"RCA", "Optical","Digital", "Analog", | 
 | 180 | 		"DIN", "XLR", "RJ11", "Comb", | 
 | 181 | 		NULL, NULL, NULL, "Other" | 
 | 182 | 	}; | 
 | 183 | 	cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT; | 
 | 184 | 	if (names[cfg]) | 
 | 185 | 		return names[cfg]; | 
 | 186 | 	else | 
 | 187 | 		return "UNKNOWN"; | 
 | 188 | } | 
 | 189 |  | 
 | 190 | static const char *get_jack_color(u32 cfg) | 
 | 191 | { | 
 | 192 | 	static char *names[16] = { | 
 | 193 | 		"Unknown", "Black", "Grey", "Blue", | 
 | 194 | 		"Green", "Red", "Orange", "Yellow", | 
 | 195 | 		"Purple", "Pink", NULL, NULL, | 
 | 196 | 		NULL, NULL, "White", "Other", | 
 | 197 | 	}; | 
 | 198 | 	cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT; | 
 | 199 | 	if (names[cfg]) | 
 | 200 | 		return names[cfg]; | 
 | 201 | 	else | 
 | 202 | 		return "UNKNOWN"; | 
 | 203 | } | 
 | 204 |  | 
| Takashi Iwai | c8b6bf9b | 2005-11-17 14:57:47 +0100 | [diff] [blame] | 205 | static void print_pin_caps(struct snd_info_buffer *buffer, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | 			   struct hda_codec *codec, hda_nid_t nid) | 
 | 207 | { | 
| Takashi Iwai | b0c95f5 | 2005-04-20 13:44:08 +0200 | [diff] [blame] | 208 | 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 209 | 	static char *jack_types[16] = { | 
 | 210 | 		"Line Out", "Speaker", "HP Out", "CD", | 
 | 211 | 		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", | 
 | 212 | 		"Line In", "Aux", "Mic", "Telephony", | 
 | 213 | 		"SPDIF In", "Digitial In", "Reserved", "Other" | 
 | 214 | 	}; | 
 | 215 | 	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | 
 | 216 | 	unsigned int caps; | 
 | 217 |  | 
 | 218 | 	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 
 | 219 | 	snd_iprintf(buffer, "  Pincap 0x08%x:", caps); | 
 | 220 | 	if (caps & AC_PINCAP_IN) | 
 | 221 | 		snd_iprintf(buffer, " IN"); | 
 | 222 | 	if (caps & AC_PINCAP_OUT) | 
 | 223 | 		snd_iprintf(buffer, " OUT"); | 
 | 224 | 	if (caps & AC_PINCAP_HP_DRV) | 
 | 225 | 		snd_iprintf(buffer, " HP"); | 
| Takashi Iwai | 5885492 | 2006-06-21 19:19:25 +0200 | [diff] [blame] | 226 | 	if (caps & AC_PINCAP_EAPD) | 
 | 227 | 		snd_iprintf(buffer, " EAPD"); | 
 | 228 | 	if (caps & AC_PINCAP_PRES_DETECT) | 
 | 229 | 		snd_iprintf(buffer, " Detect"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 230 | 	snd_iprintf(buffer, "\n"); | 
 | 231 | 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 
| Takashi Iwai | b0c95f5 | 2005-04-20 13:44:08 +0200 | [diff] [blame] | 232 | 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps, | 
 | 233 | 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 234 | 		    jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], | 
 | 235 | 		    jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], | 
 | 236 | 		    get_jack_location(caps)); | 
 | 237 | 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n", | 
 | 238 | 		    get_jack_connection(caps), | 
 | 239 | 		    get_jack_color(caps)); | 
 | 240 | } | 
 | 241 |  | 
 | 242 |  | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 243 | static void print_codec_info(struct snd_info_entry *entry, | 
 | 244 | 			     struct snd_info_buffer *buffer) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 245 | { | 
 | 246 | 	struct hda_codec *codec = entry->private_data; | 
 | 247 | 	char buf[32]; | 
 | 248 | 	hda_nid_t nid; | 
 | 249 | 	int i, nodes; | 
 | 250 |  | 
 | 251 | 	snd_hda_get_codec_name(codec, buf, sizeof(buf)); | 
 | 252 | 	snd_iprintf(buffer, "Codec: %s\n", buf); | 
 | 253 | 	snd_iprintf(buffer, "Address: %d\n", codec->addr); | 
 | 254 | 	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); | 
 | 255 | 	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); | 
 | 256 | 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); | 
| Jonathan Phenix | e25c05f | 2007-06-19 18:31:28 +0200 | [diff] [blame] | 257 |  | 
 | 258 | 	if (codec->mfg) | 
 | 259 | 		snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg); | 
 | 260 | 	else | 
 | 261 | 		snd_iprintf(buffer, "No Modem Function Group found\n"); | 
 | 262 |  | 
| Takashi Iwai | ec9e1c5 | 2005-09-07 13:29:22 +0200 | [diff] [blame] | 263 | 	if (! codec->afg) | 
 | 264 | 		return; | 
| Takashi Iwai | cb53c62 | 2007-08-10 17:21:45 +0200 | [diff] [blame] | 265 | 	snd_hda_power_up(codec); | 
| Takashi Iwai | b90d776 | 2006-11-07 16:10:06 +0100 | [diff] [blame] | 266 | 	snd_iprintf(buffer, "Default PCM:\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 267 | 	print_pcm_caps(buffer, codec, codec->afg); | 
 | 268 | 	snd_iprintf(buffer, "Default Amp-In caps: "); | 
 | 269 | 	print_amp_caps(buffer, codec, codec->afg, HDA_INPUT); | 
 | 270 | 	snd_iprintf(buffer, "Default Amp-Out caps: "); | 
 | 271 | 	print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT); | 
 | 272 |  | 
 | 273 | 	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | 
 | 274 | 	if (! nid || nodes < 0) { | 
 | 275 | 		snd_iprintf(buffer, "Invalid AFG subtree\n"); | 
| Takashi Iwai | cb53c62 | 2007-08-10 17:21:45 +0200 | [diff] [blame] | 276 | 		snd_hda_power_down(codec); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 277 | 		return; | 
 | 278 | 	} | 
 | 279 | 	for (i = 0; i < nodes; i++, nid++) { | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 280 | 		unsigned int wid_caps = | 
 | 281 | 			snd_hda_param_read(codec, nid, | 
 | 282 | 					   AC_PAR_AUDIO_WIDGET_CAP); | 
 | 283 | 		unsigned int wid_type = | 
 | 284 | 			(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 285 | 		int conn_len = 0;  | 
 | 286 | 		hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 
 | 287 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 | 		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, | 
 | 289 | 			    get_wid_type_name(wid_type), wid_caps); | 
 | 290 | 		if (wid_caps & AC_WCAP_STEREO) | 
 | 291 | 			snd_iprintf(buffer, " Stereo"); | 
 | 292 | 		else | 
 | 293 | 			snd_iprintf(buffer, " Mono"); | 
 | 294 | 		if (wid_caps & AC_WCAP_DIGITAL) | 
 | 295 | 			snd_iprintf(buffer, " Digital"); | 
 | 296 | 		if (wid_caps & AC_WCAP_IN_AMP) | 
 | 297 | 			snd_iprintf(buffer, " Amp-In"); | 
 | 298 | 		if (wid_caps & AC_WCAP_OUT_AMP) | 
 | 299 | 			snd_iprintf(buffer, " Amp-Out"); | 
 | 300 | 		snd_iprintf(buffer, "\n"); | 
 | 301 |  | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 302 | 		if (wid_caps & AC_WCAP_CONN_LIST) | 
 | 303 | 			conn_len = snd_hda_get_connections(codec, nid, conn, | 
 | 304 | 							   HDA_MAX_CONNECTIONS); | 
 | 305 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 306 | 		if (wid_caps & AC_WCAP_IN_AMP) { | 
 | 307 | 			snd_iprintf(buffer, "  Amp-In caps: "); | 
 | 308 | 			print_amp_caps(buffer, codec, nid, HDA_INPUT); | 
 | 309 | 			snd_iprintf(buffer, "  Amp-In vals: "); | 
 | 310 | 			print_amp_vals(buffer, codec, nid, HDA_INPUT, | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 311 | 				       wid_caps & AC_WCAP_STEREO, conn_len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 312 | 		} | 
 | 313 | 		if (wid_caps & AC_WCAP_OUT_AMP) { | 
 | 314 | 			snd_iprintf(buffer, "  Amp-Out caps: "); | 
 | 315 | 			print_amp_caps(buffer, codec, nid, HDA_OUTPUT); | 
 | 316 | 			snd_iprintf(buffer, "  Amp-Out vals: "); | 
 | 317 | 			print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 318 | 				       wid_caps & AC_WCAP_STEREO, 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 | 		} | 
 | 320 |  | 
 | 321 | 		if (wid_type == AC_WID_PIN) { | 
 | 322 | 			unsigned int pinctls; | 
 | 323 | 			print_pin_caps(buffer, codec, nid); | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 324 | 			pinctls = snd_hda_codec_read(codec, nid, 0, | 
 | 325 | 					     AC_VERB_GET_PIN_WIDGET_CONTROL, | 
 | 326 | 						     0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 327 | 			snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls); | 
 | 328 | 			if (pinctls & AC_PINCTL_IN_EN) | 
 | 329 | 				snd_iprintf(buffer, " IN"); | 
 | 330 | 			if (pinctls & AC_PINCTL_OUT_EN) | 
 | 331 | 				snd_iprintf(buffer, " OUT"); | 
 | 332 | 			if (pinctls & AC_PINCTL_HP_EN) | 
 | 333 | 				snd_iprintf(buffer, " HP"); | 
 | 334 | 			snd_iprintf(buffer, "\n"); | 
 | 335 | 		} | 
 | 336 |  | 
 | 337 | 		if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) && | 
 | 338 | 		    (wid_caps & AC_WCAP_FORMAT_OVRD)) { | 
| Takashi Iwai | b90d776 | 2006-11-07 16:10:06 +0100 | [diff] [blame] | 339 | 			snd_iprintf(buffer, "  PCM:\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 340 | 			print_pcm_caps(buffer, codec, nid); | 
 | 341 | 		} | 
 | 342 |  | 
| Takashi Iwai | b7027cc | 2005-11-02 18:13:41 +0100 | [diff] [blame] | 343 | 		if (wid_caps & AC_WCAP_POWER) | 
 | 344 | 			snd_iprintf(buffer, "  Power: 0x%x\n", | 
 | 345 | 				    snd_hda_codec_read(codec, nid, 0, | 
| Takashi Iwai | d01ce99 | 2007-07-27 16:52:19 +0200 | [diff] [blame] | 346 | 						       AC_VERB_GET_POWER_STATE, | 
 | 347 | 						       0)); | 
| Takashi Iwai | b7027cc | 2005-11-02 18:13:41 +0100 | [diff] [blame] | 348 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | 		if (wid_caps & AC_WCAP_CONN_LIST) { | 
| Takashi Iwai | 3e289f1 | 2005-06-10 19:45:09 +0200 | [diff] [blame] | 350 | 			int c, curr = -1; | 
| ChenLi Tien | c301098 | 2005-03-24 12:02:54 +0100 | [diff] [blame] | 351 | 			if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | 
 | 352 | 				curr = snd_hda_codec_read(codec, nid, 0, | 
 | 353 | 					AC_VERB_GET_CONNECT_SEL, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 354 | 			snd_iprintf(buffer, "  Connection: %d\n", conn_len); | 
 | 355 | 			snd_iprintf(buffer, "    "); | 
| ChenLi Tien | c301098 | 2005-03-24 12:02:54 +0100 | [diff] [blame] | 356 | 			for (c = 0; c < conn_len; c++) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 357 | 				snd_iprintf(buffer, " 0x%02x", conn[c]); | 
| ChenLi Tien | c301098 | 2005-03-24 12:02:54 +0100 | [diff] [blame] | 358 | 				if (c == curr) | 
 | 359 | 					snd_iprintf(buffer, "*"); | 
 | 360 | 			} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 | 			snd_iprintf(buffer, "\n"); | 
 | 362 | 		} | 
 | 363 | 	} | 
| Takashi Iwai | cb53c62 | 2007-08-10 17:21:45 +0200 | [diff] [blame] | 364 | 	snd_hda_power_down(codec); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 | } | 
 | 366 |  | 
 | 367 | /* | 
 | 368 |  * create a proc read | 
 | 369 |  */ | 
 | 370 | int snd_hda_codec_proc_new(struct hda_codec *codec) | 
 | 371 | { | 
 | 372 | 	char name[32]; | 
| Takashi Iwai | c8b6bf9b | 2005-11-17 14:57:47 +0100 | [diff] [blame] | 373 | 	struct snd_info_entry *entry; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 | 	int err; | 
 | 375 |  | 
 | 376 | 	snprintf(name, sizeof(name), "codec#%d", codec->addr); | 
 | 377 | 	err = snd_card_proc_new(codec->bus->card, name, &entry); | 
 | 378 | 	if (err < 0) | 
 | 379 | 		return err; | 
 | 380 |  | 
| Takashi Iwai | bf85020 | 2006-04-28 15:13:41 +0200 | [diff] [blame] | 381 | 	snd_info_set_text_ops(entry, codec, print_codec_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 382 | 	return 0; | 
 | 383 | } | 
 | 384 |  |