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 <linux/pci.h>
27 #include <sound/core.h>
28 #include "hda_codec.h"
29 #include "hda_local.h"
31 static const char *get_wid_type_name(unsigned int wid_value)
33 static char *names[16] = {
34 [AC_WID_AUD_OUT] = "Audio Output",
35 [AC_WID_AUD_IN] = "Audio Input",
36 [AC_WID_AUD_MIX] = "Audio Mixer",
37 [AC_WID_AUD_SEL] = "Audio Selector",
38 [AC_WID_PIN] = "Pin Complex",
39 [AC_WID_POWER] = "Power Widget",
40 [AC_WID_VOL_KNB] = "Volume Knob Widget",
41 [AC_WID_BEEP] = "Beep Generator Widget",
42 [AC_WID_VENDOR] = "Vendor Defined Widget",
46 return names[wid_value];
48 return "UNKNOWN Widget";
51 static void print_amp_caps(struct snd_info_buffer *buffer,
52 struct hda_codec *codec, hda_nid_t nid, int dir)
55 caps = snd_hda_param_read(codec, nid,
57 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
58 if (caps == -1 || caps == 0) {
59 snd_iprintf(buffer, "N/A\n");
62 snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n",
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, 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, AC_VERB_GET_AMP_GAIN_MUTE,
85 AC_AMP_GET_RIGHT | dir | i);
86 snd_iprintf(buffer, "0x%02x]", val);
88 snd_iprintf(buffer, "\n");
91 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
93 static unsigned int rates[] = {
94 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
95 96000, 176400, 192000, 384000
99 pcm &= AC_SUPPCM_RATES;
100 snd_iprintf(buffer, " rates [0x%x]:", pcm);
101 for (i = 0; i < ARRAY_SIZE(rates); i++)
103 snd_iprintf(buffer, " %d", rates[i]);
104 snd_iprintf(buffer, "\n");
107 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
109 static unsigned int bits[] = { 8, 16, 20, 24, 32 };
112 pcm = (pcm >> 16) & 0xff;
113 snd_iprintf(buffer, " bits [0x%x]:", pcm);
114 for (i = 0; i < ARRAY_SIZE(bits); i++)
116 snd_iprintf(buffer, " %d", bits[i]);
117 snd_iprintf(buffer, "\n");
120 static void print_pcm_formats(struct snd_info_buffer *buffer,
121 unsigned int streams)
123 snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf);
124 if (streams & AC_SUPFMT_PCM)
125 snd_iprintf(buffer, " PCM");
126 if (streams & AC_SUPFMT_FLOAT32)
127 snd_iprintf(buffer, " FLOAT");
128 if (streams & AC_SUPFMT_AC3)
129 snd_iprintf(buffer, " AC3");
130 snd_iprintf(buffer, "\n");
133 static void print_pcm_caps(struct snd_info_buffer *buffer,
134 struct hda_codec *codec, hda_nid_t nid)
136 unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
137 unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
138 if (pcm == -1 || stream == -1) {
139 snd_iprintf(buffer, "N/A\n");
142 print_pcm_rates(buffer, pcm);
143 print_pcm_bits(buffer, pcm);
144 print_pcm_formats(buffer, stream);
147 static const char *get_jack_location(u32 cfg)
149 static char *bases[7] = {
150 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
152 static unsigned char specials_idx[] = {
157 static char *specials[] = {
158 "Rear Panel", "Drive Bar",
159 "Riser", "HDMI", "ATAPI",
160 "Mobile-In", "Mobile-Out"
163 cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
164 if ((cfg & 0x0f) < 7)
165 return bases[cfg & 0x0f];
166 for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
167 if (cfg == specials_idx[i])
173 static const char *get_jack_connection(u32 cfg)
175 static char *names[16] = {
176 "Unknown", "1/8", "1/4", "ATAPI",
177 "RCA", "Optical","Digital", "Analog",
178 "DIN", "XLR", "RJ11", "Comb",
179 NULL, NULL, NULL, "Other"
181 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
188 static const char *get_jack_color(u32 cfg)
190 static char *names[16] = {
191 "Unknown", "Black", "Grey", "Blue",
192 "Green", "Red", "Orange", "Yellow",
193 "Purple", "Pink", NULL, NULL,
194 NULL, NULL, "White", "Other",
196 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
203 static void print_pin_caps(struct snd_info_buffer *buffer,
204 struct hda_codec *codec, hda_nid_t nid)
206 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
207 static char *jack_types[16] = {
208 "Line Out", "Speaker", "HP Out", "CD",
209 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
210 "Line In", "Aux", "Mic", "Telephony",
211 "SPDIF In", "Digitial In", "Reserved", "Other"
213 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
216 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
217 snd_iprintf(buffer, " Pincap 0x08%x:", caps);
218 if (caps & AC_PINCAP_IN)
219 snd_iprintf(buffer, " IN");
220 if (caps & AC_PINCAP_OUT)
221 snd_iprintf(buffer, " OUT");
222 if (caps & AC_PINCAP_HP_DRV)
223 snd_iprintf(buffer, " HP");
224 if (caps & AC_PINCAP_EAPD)
225 snd_iprintf(buffer, " EAPD");
226 if (caps & AC_PINCAP_PRES_DETECT)
227 snd_iprintf(buffer, " Detect");
228 snd_iprintf(buffer, "\n");
229 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
230 snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
231 jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
232 jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
233 jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
234 get_jack_location(caps));
235 snd_iprintf(buffer, " Conn = %s, Color = %s\n",
236 get_jack_connection(caps),
237 get_jack_color(caps));
241 static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
243 struct hda_codec *codec = entry->private_data;
248 snd_hda_get_codec_name(codec, buf, sizeof(buf));
249 snd_iprintf(buffer, "Codec: %s\n", buf);
250 snd_iprintf(buffer, "Address: %d\n", codec->addr);
251 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
252 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
253 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
256 snd_iprintf(buffer, "Default PCM:\n");
257 print_pcm_caps(buffer, codec, codec->afg);
258 snd_iprintf(buffer, "Default Amp-In caps: ");
259 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
260 snd_iprintf(buffer, "Default Amp-Out caps: ");
261 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
263 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
264 if (! nid || nodes < 0) {
265 snd_iprintf(buffer, "Invalid AFG subtree\n");
268 for (i = 0; i < nodes; i++, nid++) {
269 unsigned int wid_caps = snd_hda_param_read(codec, nid,
270 AC_PAR_AUDIO_WIDGET_CAP);
271 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
273 hda_nid_t conn[HDA_MAX_CONNECTIONS];
275 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
276 get_wid_type_name(wid_type), wid_caps);
277 if (wid_caps & AC_WCAP_STEREO)
278 snd_iprintf(buffer, " Stereo");
280 snd_iprintf(buffer, " Mono");
281 if (wid_caps & AC_WCAP_DIGITAL)
282 snd_iprintf(buffer, " Digital");
283 if (wid_caps & AC_WCAP_IN_AMP)
284 snd_iprintf(buffer, " Amp-In");
285 if (wid_caps & AC_WCAP_OUT_AMP)
286 snd_iprintf(buffer, " Amp-Out");
287 snd_iprintf(buffer, "\n");
289 if (wid_caps & AC_WCAP_CONN_LIST)
290 conn_len = snd_hda_get_connections(codec, nid, conn,
291 HDA_MAX_CONNECTIONS);
293 if (wid_caps & AC_WCAP_IN_AMP) {
294 snd_iprintf(buffer, " Amp-In caps: ");
295 print_amp_caps(buffer, codec, nid, HDA_INPUT);
296 snd_iprintf(buffer, " Amp-In vals: ");
297 print_amp_vals(buffer, codec, nid, HDA_INPUT,
298 wid_caps & AC_WCAP_STEREO, conn_len);
300 if (wid_caps & AC_WCAP_OUT_AMP) {
301 snd_iprintf(buffer, " Amp-Out caps: ");
302 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
303 snd_iprintf(buffer, " Amp-Out vals: ");
304 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
305 wid_caps & AC_WCAP_STEREO, 1);
308 if (wid_type == AC_WID_PIN) {
309 unsigned int pinctls;
310 print_pin_caps(buffer, codec, nid);
311 pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
312 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
313 if (pinctls & AC_PINCTL_IN_EN)
314 snd_iprintf(buffer, " IN");
315 if (pinctls & AC_PINCTL_OUT_EN)
316 snd_iprintf(buffer, " OUT");
317 if (pinctls & AC_PINCTL_HP_EN)
318 snd_iprintf(buffer, " HP");
319 snd_iprintf(buffer, "\n");
322 if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
323 (wid_caps & AC_WCAP_FORMAT_OVRD)) {
324 snd_iprintf(buffer, " PCM:\n");
325 print_pcm_caps(buffer, codec, nid);
328 if (wid_caps & AC_WCAP_POWER)
329 snd_iprintf(buffer, " Power: 0x%x\n",
330 snd_hda_codec_read(codec, nid, 0,
331 AC_VERB_GET_POWER_STATE, 0));
333 if (wid_caps & AC_WCAP_CONN_LIST) {
335 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
336 curr = snd_hda_codec_read(codec, nid, 0,
337 AC_VERB_GET_CONNECT_SEL, 0);
338 snd_iprintf(buffer, " Connection: %d\n", conn_len);
339 snd_iprintf(buffer, " ");
340 for (c = 0; c < conn_len; c++) {
341 snd_iprintf(buffer, " 0x%02x", conn[c]);
343 snd_iprintf(buffer, "*");
345 snd_iprintf(buffer, "\n");
353 int snd_hda_codec_proc_new(struct hda_codec *codec)
356 struct snd_info_entry *entry;
359 snprintf(name, sizeof(name), "codec#%d", codec->addr);
360 err = snd_card_proc_new(codec->bus->card, name, &entry);
364 snd_info_set_text_ops(entry, codec, print_codec_info);