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 <linux/init.h>
25 #include <sound/core.h>
26 #include "hda_codec.h"
27 #include "hda_local.h"
29 static const char *get_wid_type_name(unsigned int wid_value)
31 static char *names[16] = {
32 [AC_WID_AUD_OUT] = "Audio Output",
33 [AC_WID_AUD_IN] = "Audio Input",
34 [AC_WID_AUD_MIX] = "Audio Mixer",
35 [AC_WID_AUD_SEL] = "Audio Selector",
36 [AC_WID_PIN] = "Pin Complex",
37 [AC_WID_POWER] = "Power Widget",
38 [AC_WID_VOL_KNB] = "Volume Knob Widget",
39 [AC_WID_BEEP] = "Beep Generator Widget",
40 [AC_WID_VENDOR] = "Vendor Defined Widget",
44 return names[wid_value];
46 return "UNKNOWN Widget";
49 static void print_amp_caps(struct snd_info_buffer *buffer,
50 struct hda_codec *codec, hda_nid_t nid, int dir)
53 caps = snd_hda_param_read(codec, nid,
55 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
56 if (caps == -1 || caps == 0) {
57 snd_iprintf(buffer, "N/A\n");
60 snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, "
62 caps & AC_AMPCAP_OFFSET,
63 (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
64 (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
65 (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
68 static void print_amp_vals(struct snd_info_buffer *buffer,
69 struct hda_codec *codec, hda_nid_t nid,
70 int dir, int stereo, int indices)
75 dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
76 for (i = 0; i < indices; i++) {
77 snd_iprintf(buffer, " [");
79 val = snd_hda_codec_read(codec, nid, 0,
80 AC_VERB_GET_AMP_GAIN_MUTE,
81 AC_AMP_GET_LEFT | dir | i);
82 snd_iprintf(buffer, "0x%02x ", val);
84 val = snd_hda_codec_read(codec, nid, 0,
85 AC_VERB_GET_AMP_GAIN_MUTE,
86 AC_AMP_GET_RIGHT | dir | i);
87 snd_iprintf(buffer, "0x%02x]", val);
89 snd_iprintf(buffer, "\n");
92 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
94 static unsigned int rates[] = {
95 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
96 96000, 176400, 192000, 384000
100 pcm &= AC_SUPPCM_RATES;
101 snd_iprintf(buffer, " rates [0x%x]:", pcm);
102 for (i = 0; i < ARRAY_SIZE(rates); i++)
104 snd_iprintf(buffer, " %d", rates[i]);
105 snd_iprintf(buffer, "\n");
108 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
110 static unsigned int bits[] = { 8, 16, 20, 24, 32 };
113 pcm = (pcm >> 16) & 0xff;
114 snd_iprintf(buffer, " bits [0x%x]:", pcm);
115 for (i = 0; i < ARRAY_SIZE(bits); i++)
117 snd_iprintf(buffer, " %d", bits[i]);
118 snd_iprintf(buffer, "\n");
121 static void print_pcm_formats(struct snd_info_buffer *buffer,
122 unsigned int streams)
124 snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf);
125 if (streams & AC_SUPFMT_PCM)
126 snd_iprintf(buffer, " PCM");
127 if (streams & AC_SUPFMT_FLOAT32)
128 snd_iprintf(buffer, " FLOAT");
129 if (streams & AC_SUPFMT_AC3)
130 snd_iprintf(buffer, " AC3");
131 snd_iprintf(buffer, "\n");
134 static void print_pcm_caps(struct snd_info_buffer *buffer,
135 struct hda_codec *codec, hda_nid_t nid)
137 unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
138 unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
139 if (pcm == -1 || stream == -1) {
140 snd_iprintf(buffer, "N/A\n");
143 print_pcm_rates(buffer, pcm);
144 print_pcm_bits(buffer, pcm);
145 print_pcm_formats(buffer, stream);
148 static const char *get_jack_location(u32 cfg)
150 static char *bases[7] = {
151 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
153 static unsigned char specials_idx[] = {
158 static char *specials[] = {
159 "Rear Panel", "Drive Bar",
160 "Riser", "HDMI", "ATAPI",
161 "Mobile-In", "Mobile-Out"
164 cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
165 if ((cfg & 0x0f) < 7)
166 return bases[cfg & 0x0f];
167 for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
168 if (cfg == specials_idx[i])
174 static const char *get_jack_connection(u32 cfg)
176 static char *names[16] = {
177 "Unknown", "1/8", "1/4", "ATAPI",
178 "RCA", "Optical","Digital", "Analog",
179 "DIN", "XLR", "RJ11", "Comb",
180 NULL, NULL, NULL, "Other"
182 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
189 static const char *get_jack_color(u32 cfg)
191 static char *names[16] = {
192 "Unknown", "Black", "Grey", "Blue",
193 "Green", "Red", "Orange", "Yellow",
194 "Purple", "Pink", NULL, NULL,
195 NULL, NULL, "White", "Other",
197 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
204 static void print_pin_caps(struct snd_info_buffer *buffer,
205 struct hda_codec *codec, hda_nid_t nid)
207 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
208 static char *jack_types[16] = {
209 "Line Out", "Speaker", "HP Out", "CD",
210 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
211 "Line In", "Aux", "Mic", "Telephony",
212 "SPDIF In", "Digitial In", "Reserved", "Other"
214 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
215 unsigned int caps, val;
217 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
218 snd_iprintf(buffer, " Pincap 0x08%x:", caps);
219 if (caps & AC_PINCAP_IN)
220 snd_iprintf(buffer, " IN");
221 if (caps & AC_PINCAP_OUT)
222 snd_iprintf(buffer, " OUT");
223 if (caps & AC_PINCAP_HP_DRV)
224 snd_iprintf(buffer, " HP");
225 if (caps & AC_PINCAP_EAPD)
226 snd_iprintf(buffer, " EAPD");
227 if (caps & AC_PINCAP_PRES_DETECT)
228 snd_iprintf(buffer, " Detect");
229 snd_iprintf(buffer, "\n");
230 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
231 snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
232 jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
233 jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
234 jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
235 get_jack_location(caps));
236 snd_iprintf(buffer, " Conn = %s, Color = %s\n",
237 get_jack_connection(caps),
238 get_jack_color(caps));
239 if (caps & AC_PINCAP_EAPD) {
240 val = snd_hda_codec_read(codec, nid, 0,
241 AC_VERB_GET_EAPD_BTLENABLE, 0);
242 snd_iprintf(buffer, " EAPD: 0x%x\n", val);
247 static void print_codec_info(struct snd_info_entry *entry,
248 struct snd_info_buffer *buffer)
250 struct hda_codec *codec = entry->private_data;
255 snd_hda_get_codec_name(codec, buf, sizeof(buf));
256 snd_iprintf(buffer, "Codec: %s\n", buf);
257 snd_iprintf(buffer, "Address: %d\n", codec->addr);
258 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
259 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
260 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
263 snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
265 snd_iprintf(buffer, "No Modem Function Group found\n");
269 snd_hda_power_up(codec);
270 snd_iprintf(buffer, "Default PCM:\n");
271 print_pcm_caps(buffer, codec, codec->afg);
272 snd_iprintf(buffer, "Default Amp-In caps: ");
273 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
274 snd_iprintf(buffer, "Default Amp-Out caps: ");
275 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
277 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
278 if (! nid || nodes < 0) {
279 snd_iprintf(buffer, "Invalid AFG subtree\n");
280 snd_hda_power_down(codec);
283 for (i = 0; i < nodes; i++, nid++) {
284 unsigned int wid_caps =
285 snd_hda_param_read(codec, nid,
286 AC_PAR_AUDIO_WIDGET_CAP);
287 unsigned int wid_type =
288 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
290 hda_nid_t conn[HDA_MAX_CONNECTIONS];
291 unsigned int pinctls;
293 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
294 get_wid_type_name(wid_type), wid_caps);
295 if (wid_caps & AC_WCAP_STEREO)
296 snd_iprintf(buffer, " Stereo");
298 snd_iprintf(buffer, " Mono");
299 if (wid_caps & AC_WCAP_DIGITAL)
300 snd_iprintf(buffer, " Digital");
301 if (wid_caps & AC_WCAP_IN_AMP)
302 snd_iprintf(buffer, " Amp-In");
303 if (wid_caps & AC_WCAP_OUT_AMP)
304 snd_iprintf(buffer, " Amp-Out");
305 snd_iprintf(buffer, "\n");
307 /* volume knob is a special widget that always have connection
310 if (wid_type == AC_WID_VOL_KNB)
311 wid_caps |= AC_WCAP_CONN_LIST;
313 if (wid_caps & AC_WCAP_CONN_LIST)
314 conn_len = snd_hda_get_connections(codec, nid, conn,
315 HDA_MAX_CONNECTIONS);
317 if (wid_caps & AC_WCAP_IN_AMP) {
318 snd_iprintf(buffer, " Amp-In caps: ");
319 print_amp_caps(buffer, codec, nid, HDA_INPUT);
320 snd_iprintf(buffer, " Amp-In vals: ");
321 print_amp_vals(buffer, codec, nid, HDA_INPUT,
322 wid_caps & AC_WCAP_STEREO, conn_len);
324 if (wid_caps & AC_WCAP_OUT_AMP) {
325 snd_iprintf(buffer, " Amp-Out caps: ");
326 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
327 snd_iprintf(buffer, " Amp-Out vals: ");
328 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
329 wid_caps & AC_WCAP_STEREO, 1);
334 print_pin_caps(buffer, codec, nid);
335 pinctls = snd_hda_codec_read(codec, nid, 0,
336 AC_VERB_GET_PIN_WIDGET_CONTROL,
338 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
339 if (pinctls & AC_PINCTL_IN_EN)
340 snd_iprintf(buffer, " IN");
341 if (pinctls & AC_PINCTL_OUT_EN)
342 snd_iprintf(buffer, " OUT");
343 if (pinctls & AC_PINCTL_HP_EN)
344 snd_iprintf(buffer, " HP");
345 snd_iprintf(buffer, "\n");
348 pinctls = snd_hda_param_read(codec, nid,
350 snd_iprintf(buffer, " Volume-Knob: delta=%d, "
352 (pinctls >> 7) & 1, pinctls & 0x7f);
353 pinctls = snd_hda_codec_read(codec, nid, 0,
354 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
355 snd_iprintf(buffer, "direct=%d, val=%d\n",
356 (pinctls >> 7) & 1, pinctls & 0x7f);
360 if (wid_caps & AC_WCAP_FORMAT_OVRD) {
361 snd_iprintf(buffer, " PCM:\n");
362 print_pcm_caps(buffer, codec, nid);
367 if (wid_caps & AC_WCAP_POWER)
368 snd_iprintf(buffer, " Power: 0x%x\n",
369 snd_hda_codec_read(codec, nid, 0,
370 AC_VERB_GET_POWER_STATE,
373 if (wid_caps & AC_WCAP_CONN_LIST) {
375 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
376 curr = snd_hda_codec_read(codec, nid, 0,
377 AC_VERB_GET_CONNECT_SEL, 0);
378 snd_iprintf(buffer, " Connection: %d\n", conn_len);
380 snd_iprintf(buffer, " ");
381 for (c = 0; c < conn_len; c++) {
382 snd_iprintf(buffer, " 0x%02x", conn[c]);
384 snd_iprintf(buffer, "*");
386 snd_iprintf(buffer, "\n");
390 snd_hda_power_down(codec);
396 int snd_hda_codec_proc_new(struct hda_codec *codec)
399 struct snd_info_entry *entry;
402 snprintf(name, sizeof(name), "codec#%d", codec->addr);
403 err = snd_card_proc_new(codec->bus->card, name, &entry);
407 snd_info_set_text_ops(entry, codec, print_codec_info);