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, mute=%x\n",
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, AC_VERB_GET_AMP_GAIN_MUTE,
80 AC_AMP_GET_LEFT | dir | i);
81 snd_iprintf(buffer, "0x%02x ", val);
83 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
84 AC_AMP_GET_RIGHT | dir | i);
85 snd_iprintf(buffer, "0x%02x]", val);
87 snd_iprintf(buffer, "\n");
90 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
92 static unsigned int rates[] = {
93 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
94 96000, 176400, 192000, 384000
98 pcm &= AC_SUPPCM_RATES;
99 snd_iprintf(buffer, " rates [0x%x]:", pcm);
100 for (i = 0; i < ARRAY_SIZE(rates); i++)
102 snd_iprintf(buffer, " %d", rates[i]);
103 snd_iprintf(buffer, "\n");
106 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
108 static unsigned int bits[] = { 8, 16, 20, 24, 32 };
111 pcm = (pcm >> 16) & 0xff;
112 snd_iprintf(buffer, " bits [0x%x]:", pcm);
113 for (i = 0; i < ARRAY_SIZE(bits); i++)
115 snd_iprintf(buffer, " %d", bits[i]);
116 snd_iprintf(buffer, "\n");
119 static void print_pcm_formats(struct snd_info_buffer *buffer,
120 unsigned int streams)
122 snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf);
123 if (streams & AC_SUPFMT_PCM)
124 snd_iprintf(buffer, " PCM");
125 if (streams & AC_SUPFMT_FLOAT32)
126 snd_iprintf(buffer, " FLOAT");
127 if (streams & AC_SUPFMT_AC3)
128 snd_iprintf(buffer, " AC3");
129 snd_iprintf(buffer, "\n");
132 static void print_pcm_caps(struct snd_info_buffer *buffer,
133 struct hda_codec *codec, hda_nid_t nid)
135 unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
136 unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
137 if (pcm == -1 || stream == -1) {
138 snd_iprintf(buffer, "N/A\n");
141 print_pcm_rates(buffer, pcm);
142 print_pcm_bits(buffer, pcm);
143 print_pcm_formats(buffer, stream);
146 static const char *get_jack_location(u32 cfg)
148 static char *bases[7] = {
149 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
151 static unsigned char specials_idx[] = {
156 static char *specials[] = {
157 "Rear Panel", "Drive Bar",
158 "Riser", "HDMI", "ATAPI",
159 "Mobile-In", "Mobile-Out"
162 cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
163 if ((cfg & 0x0f) < 7)
164 return bases[cfg & 0x0f];
165 for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
166 if (cfg == specials_idx[i])
172 static const char *get_jack_connection(u32 cfg)
174 static char *names[16] = {
175 "Unknown", "1/8", "1/4", "ATAPI",
176 "RCA", "Optical","Digital", "Analog",
177 "DIN", "XLR", "RJ11", "Comb",
178 NULL, NULL, NULL, "Other"
180 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
187 static const char *get_jack_color(u32 cfg)
189 static char *names[16] = {
190 "Unknown", "Black", "Grey", "Blue",
191 "Green", "Red", "Orange", "Yellow",
192 "Purple", "Pink", NULL, NULL,
193 NULL, NULL, "White", "Other",
195 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
202 static void print_pin_caps(struct snd_info_buffer *buffer,
203 struct hda_codec *codec, hda_nid_t nid)
205 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
206 static char *jack_types[16] = {
207 "Line Out", "Speaker", "HP Out", "CD",
208 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
209 "Line In", "Aux", "Mic", "Telephony",
210 "SPDIF In", "Digitial In", "Reserved", "Other"
212 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
215 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
216 snd_iprintf(buffer, " Pincap 0x08%x:", caps);
217 if (caps & AC_PINCAP_IN)
218 snd_iprintf(buffer, " IN");
219 if (caps & AC_PINCAP_OUT)
220 snd_iprintf(buffer, " OUT");
221 if (caps & AC_PINCAP_HP_DRV)
222 snd_iprintf(buffer, " HP");
223 if (caps & AC_PINCAP_EAPD)
224 snd_iprintf(buffer, " EAPD");
225 if (caps & AC_PINCAP_PRES_DETECT)
226 snd_iprintf(buffer, " Detect");
227 snd_iprintf(buffer, "\n");
228 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
229 snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
230 jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
231 jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
232 jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
233 get_jack_location(caps));
234 snd_iprintf(buffer, " Conn = %s, Color = %s\n",
235 get_jack_connection(caps),
236 get_jack_color(caps));
240 static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
242 struct hda_codec *codec = entry->private_data;
247 snd_hda_get_codec_name(codec, buf, sizeof(buf));
248 snd_iprintf(buffer, "Codec: %s\n", buf);
249 snd_iprintf(buffer, "Address: %d\n", codec->addr);
250 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
251 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
252 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
255 snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
257 snd_iprintf(buffer, "No Modem Function Group found\n");
261 snd_iprintf(buffer, "Default PCM:\n");
262 print_pcm_caps(buffer, codec, codec->afg);
263 snd_iprintf(buffer, "Default Amp-In caps: ");
264 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
265 snd_iprintf(buffer, "Default Amp-Out caps: ");
266 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
268 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
269 if (! nid || nodes < 0) {
270 snd_iprintf(buffer, "Invalid AFG subtree\n");
273 for (i = 0; i < nodes; i++, nid++) {
274 unsigned int wid_caps = snd_hda_param_read(codec, nid,
275 AC_PAR_AUDIO_WIDGET_CAP);
276 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
278 hda_nid_t conn[HDA_MAX_CONNECTIONS];
280 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
281 get_wid_type_name(wid_type), wid_caps);
282 if (wid_caps & AC_WCAP_STEREO)
283 snd_iprintf(buffer, " Stereo");
285 snd_iprintf(buffer, " Mono");
286 if (wid_caps & AC_WCAP_DIGITAL)
287 snd_iprintf(buffer, " Digital");
288 if (wid_caps & AC_WCAP_IN_AMP)
289 snd_iprintf(buffer, " Amp-In");
290 if (wid_caps & AC_WCAP_OUT_AMP)
291 snd_iprintf(buffer, " Amp-Out");
292 snd_iprintf(buffer, "\n");
294 if (wid_caps & AC_WCAP_CONN_LIST)
295 conn_len = snd_hda_get_connections(codec, nid, conn,
296 HDA_MAX_CONNECTIONS);
298 if (wid_caps & AC_WCAP_IN_AMP) {
299 snd_iprintf(buffer, " Amp-In caps: ");
300 print_amp_caps(buffer, codec, nid, HDA_INPUT);
301 snd_iprintf(buffer, " Amp-In vals: ");
302 print_amp_vals(buffer, codec, nid, HDA_INPUT,
303 wid_caps & AC_WCAP_STEREO, conn_len);
305 if (wid_caps & AC_WCAP_OUT_AMP) {
306 snd_iprintf(buffer, " Amp-Out caps: ");
307 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
308 snd_iprintf(buffer, " Amp-Out vals: ");
309 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
310 wid_caps & AC_WCAP_STEREO, 1);
313 if (wid_type == AC_WID_PIN) {
314 unsigned int pinctls;
315 print_pin_caps(buffer, codec, nid);
316 pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
317 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
318 if (pinctls & AC_PINCTL_IN_EN)
319 snd_iprintf(buffer, " IN");
320 if (pinctls & AC_PINCTL_OUT_EN)
321 snd_iprintf(buffer, " OUT");
322 if (pinctls & AC_PINCTL_HP_EN)
323 snd_iprintf(buffer, " HP");
324 snd_iprintf(buffer, "\n");
327 if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
328 (wid_caps & AC_WCAP_FORMAT_OVRD)) {
329 snd_iprintf(buffer, " PCM:\n");
330 print_pcm_caps(buffer, codec, nid);
333 if (wid_caps & AC_WCAP_POWER)
334 snd_iprintf(buffer, " Power: 0x%x\n",
335 snd_hda_codec_read(codec, nid, 0,
336 AC_VERB_GET_POWER_STATE, 0));
338 if (wid_caps & AC_WCAP_CONN_LIST) {
340 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
341 curr = snd_hda_codec_read(codec, nid, 0,
342 AC_VERB_GET_CONNECT_SEL, 0);
343 snd_iprintf(buffer, " Connection: %d\n", conn_len);
344 snd_iprintf(buffer, " ");
345 for (c = 0; c < conn_len; c++) {
346 snd_iprintf(buffer, " 0x%02x", conn[c]);
348 snd_iprintf(buffer, "*");
350 snd_iprintf(buffer, "\n");
358 int snd_hda_codec_proc_new(struct hda_codec *codec)
361 struct snd_info_entry *entry;
364 snprintf(name, sizeof(name), "codec#%d", codec->addr);
365 err = snd_card_proc_new(codec->bus->card, name, &entry);
369 snd_info_set_text_ops(entry, codec, print_codec_info);