2 * Universal Interface for Intel High Definition Audio Codec
4 * Generic proc interface
6 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
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.
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.
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
24 #include <sound/driver.h>
25 #include <linux/init.h>
26 #include <sound/core.h>
27 #include "hda_codec.h"
28 #include "hda_local.h"
30 static const char *get_wid_type_name(unsigned int wid_value)
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",
45 return names[wid_value];
47 return "UNKNOWN Widget";
50 static void print_amp_caps(struct snd_info_buffer *buffer,
51 struct hda_codec *codec, hda_nid_t nid, int dir)
54 caps = snd_hda_param_read(codec, nid,
56 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
57 if (caps == -1 || caps == 0) {
58 snd_iprintf(buffer, "N/A\n");
61 snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, "
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);
69 static void print_amp_vals(struct snd_info_buffer *buffer,
70 struct hda_codec *codec, hda_nid_t nid,
71 int dir, int stereo, int indices)
76 dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
77 for (i = 0; i < indices; i++) {
78 snd_iprintf(buffer, " [");
80 val = snd_hda_codec_read(codec, nid, 0,
81 AC_VERB_GET_AMP_GAIN_MUTE,
82 AC_AMP_GET_LEFT | dir | i);
83 snd_iprintf(buffer, "0x%02x ", val);
85 val = snd_hda_codec_read(codec, nid, 0,
86 AC_VERB_GET_AMP_GAIN_MUTE,
87 AC_AMP_GET_RIGHT | dir | i);
88 snd_iprintf(buffer, "0x%02x]", val);
90 snd_iprintf(buffer, "\n");
93 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
95 static unsigned int rates[] = {
96 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
97 96000, 176400, 192000, 384000
101 pcm &= AC_SUPPCM_RATES;
102 snd_iprintf(buffer, " rates [0x%x]:", pcm);
103 for (i = 0; i < ARRAY_SIZE(rates); i++)
105 snd_iprintf(buffer, " %d", rates[i]);
106 snd_iprintf(buffer, "\n");
109 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
111 static unsigned int bits[] = { 8, 16, 20, 24, 32 };
114 pcm = (pcm >> 16) & 0xff;
115 snd_iprintf(buffer, " bits [0x%x]:", pcm);
116 for (i = 0; i < ARRAY_SIZE(bits); i++)
118 snd_iprintf(buffer, " %d", bits[i]);
119 snd_iprintf(buffer, "\n");
122 static void print_pcm_formats(struct snd_info_buffer *buffer,
123 unsigned int streams)
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");
135 static void print_pcm_caps(struct snd_info_buffer *buffer,
136 struct hda_codec *codec, hda_nid_t nid)
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");
144 print_pcm_rates(buffer, pcm);
145 print_pcm_bits(buffer, pcm);
146 print_pcm_formats(buffer, stream);
149 static const char *get_jack_location(u32 cfg)
151 static char *bases[7] = {
152 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
154 static unsigned char specials_idx[] = {
159 static char *specials[] = {
160 "Rear Panel", "Drive Bar",
161 "Riser", "HDMI", "ATAPI",
162 "Mobile-In", "Mobile-Out"
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])
175 static const char *get_jack_connection(u32 cfg)
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"
183 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
190 static const char *get_jack_color(u32 cfg)
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",
198 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
205 static void print_pin_caps(struct snd_info_buffer *buffer,
206 struct hda_codec *codec, hda_nid_t nid)
208 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
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"
215 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
216 unsigned int caps, val;
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");
226 if (caps & AC_PINCAP_EAPD)
227 snd_iprintf(buffer, " EAPD");
228 if (caps & AC_PINCAP_PRES_DETECT)
229 snd_iprintf(buffer, " Detect");
230 snd_iprintf(buffer, "\n");
231 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
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],
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 if (caps & AC_PINCAP_EAPD) {
241 val = snd_hda_codec_read(codec, nid, 0,
242 AC_VERB_GET_EAPD_BTLENABLE, 0);
243 snd_iprintf(buffer, " EAPD: 0x%x\n", val);
248 static void print_codec_info(struct snd_info_entry *entry,
249 struct snd_info_buffer *buffer)
251 struct hda_codec *codec = entry->private_data;
256 snd_hda_get_codec_name(codec, buf, sizeof(buf));
257 snd_iprintf(buffer, "Codec: %s\n", buf);
258 snd_iprintf(buffer, "Address: %d\n", codec->addr);
259 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
260 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
261 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
264 snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
266 snd_iprintf(buffer, "No Modem Function Group found\n");
270 snd_hda_power_up(codec);
271 snd_iprintf(buffer, "Default PCM:\n");
272 print_pcm_caps(buffer, codec, codec->afg);
273 snd_iprintf(buffer, "Default Amp-In caps: ");
274 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
275 snd_iprintf(buffer, "Default Amp-Out caps: ");
276 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
278 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
279 if (! nid || nodes < 0) {
280 snd_iprintf(buffer, "Invalid AFG subtree\n");
281 snd_hda_power_down(codec);
284 for (i = 0; i < nodes; i++, nid++) {
285 unsigned int wid_caps =
286 snd_hda_param_read(codec, nid,
287 AC_PAR_AUDIO_WIDGET_CAP);
288 unsigned int wid_type =
289 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
291 hda_nid_t conn[HDA_MAX_CONNECTIONS];
292 unsigned int pinctls;
294 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
295 get_wid_type_name(wid_type), wid_caps);
296 if (wid_caps & AC_WCAP_STEREO)
297 snd_iprintf(buffer, " Stereo");
299 snd_iprintf(buffer, " Mono");
300 if (wid_caps & AC_WCAP_DIGITAL)
301 snd_iprintf(buffer, " Digital");
302 if (wid_caps & AC_WCAP_IN_AMP)
303 snd_iprintf(buffer, " Amp-In");
304 if (wid_caps & AC_WCAP_OUT_AMP)
305 snd_iprintf(buffer, " Amp-Out");
306 snd_iprintf(buffer, "\n");
308 /* volume knob is a special widget that always have connection
311 if (wid_type == AC_WID_VOL_KNB)
312 wid_caps |= AC_WCAP_CONN_LIST;
314 if (wid_caps & AC_WCAP_CONN_LIST)
315 conn_len = snd_hda_get_connections(codec, nid, conn,
316 HDA_MAX_CONNECTIONS);
318 if (wid_caps & AC_WCAP_IN_AMP) {
319 snd_iprintf(buffer, " Amp-In caps: ");
320 print_amp_caps(buffer, codec, nid, HDA_INPUT);
321 snd_iprintf(buffer, " Amp-In vals: ");
322 print_amp_vals(buffer, codec, nid, HDA_INPUT,
323 wid_caps & AC_WCAP_STEREO, conn_len);
325 if (wid_caps & AC_WCAP_OUT_AMP) {
326 snd_iprintf(buffer, " Amp-Out caps: ");
327 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
328 snd_iprintf(buffer, " Amp-Out vals: ");
329 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
330 wid_caps & AC_WCAP_STEREO, 1);
335 print_pin_caps(buffer, codec, nid);
336 pinctls = snd_hda_codec_read(codec, nid, 0,
337 AC_VERB_GET_PIN_WIDGET_CONTROL,
339 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
340 if (pinctls & AC_PINCTL_IN_EN)
341 snd_iprintf(buffer, " IN");
342 if (pinctls & AC_PINCTL_OUT_EN)
343 snd_iprintf(buffer, " OUT");
344 if (pinctls & AC_PINCTL_HP_EN)
345 snd_iprintf(buffer, " HP");
346 snd_iprintf(buffer, "\n");
349 pinctls = snd_hda_param_read(codec, nid,
351 snd_iprintf(buffer, " Volume-Knob: delta=%d, "
353 (pinctls >> 7) & 1, pinctls & 0x7f);
354 pinctls = snd_hda_codec_read(codec, nid, 0,
355 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
356 snd_iprintf(buffer, "direct=%d, val=%d\n",
357 (pinctls >> 7) & 1, pinctls & 0x7f);
361 if (wid_caps & AC_WCAP_FORMAT_OVRD) {
362 snd_iprintf(buffer, " PCM:\n");
363 print_pcm_caps(buffer, codec, nid);
368 if (wid_caps & AC_WCAP_POWER)
369 snd_iprintf(buffer, " Power: 0x%x\n",
370 snd_hda_codec_read(codec, nid, 0,
371 AC_VERB_GET_POWER_STATE,
374 if (wid_caps & AC_WCAP_CONN_LIST) {
376 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
377 curr = snd_hda_codec_read(codec, nid, 0,
378 AC_VERB_GET_CONNECT_SEL, 0);
379 snd_iprintf(buffer, " Connection: %d\n", conn_len);
381 snd_iprintf(buffer, " ");
382 for (c = 0; c < conn_len; c++) {
383 snd_iprintf(buffer, " 0x%02x", conn[c]);
385 snd_iprintf(buffer, "*");
387 snd_iprintf(buffer, "\n");
391 snd_hda_power_down(codec);
397 int snd_hda_codec_proc_new(struct hda_codec *codec)
400 struct snd_info_entry *entry;
403 snprintf(name, sizeof(name), "codec#%d", codec->addr);
404 err = snd_card_proc_new(codec->bus->card, name, &entry);
408 snd_info_set_text_ops(entry, codec, print_codec_info);