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"
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 "UNKOWN Widget";
50 static void print_amp_caps(snd_info_buffer_t *buffer,
51 struct hda_codec *codec, hda_nid_t nid, int dir)
54 if (dir == HDA_OUTPUT)
55 caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
57 caps = snd_hda_param_read(codec, nid, 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(snd_info_buffer_t *buffer,
70 struct hda_codec *codec, hda_nid_t nid,
75 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
77 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
79 snd_iprintf(buffer, "0x%02x ", val);
81 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
83 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
85 snd_iprintf(buffer, "0x%02x\n", val);
88 static void print_pcm_caps(snd_info_buffer_t *buffer,
89 struct hda_codec *codec, hda_nid_t nid)
91 unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
92 unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
93 if (pcm == -1 || stream == -1) {
94 snd_iprintf(buffer, "N/A\n");
97 snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n",
98 pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf);
101 static const char *get_jack_location(u32 cfg)
103 static char *bases[7] = {
104 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
106 static unsigned char specials_idx[] = {
111 static char *specials[] = {
112 "Rear Panel", "Drive Bar",
113 "Riser", "HDMI", "ATAPI",
114 "Mobile-In", "Mobile-Out"
117 cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
118 if ((cfg & 0x0f) < 7)
119 return bases[cfg & 0x0f];
120 for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
121 if (cfg == specials_idx[i])
127 static const char *get_jack_connection(u32 cfg)
129 static char *names[16] = {
130 "Unknown", "1/8", "1/4", "ATAPI",
131 "RCA", "Optical","Digital", "Analog",
132 "DIN", "XLR", "RJ11", "Comb",
133 NULL, NULL, NULL, "Other"
135 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
142 static const char *get_jack_color(u32 cfg)
144 static char *names[16] = {
145 "Unknown", "Black", "Grey", "Blue",
146 "Green", "Red", "Orange", "Yellow",
147 "Purple", "Pink", NULL, NULL,
148 NULL, NULL, "White", "Other",
150 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
157 static void print_pin_caps(snd_info_buffer_t *buffer,
158 struct hda_codec *codec, hda_nid_t nid)
160 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
161 static char *jack_types[16] = {
162 "Line Out", "Speaker", "HP Out", "CD",
163 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
164 "Line In", "Aux", "Mic", "Telephony",
165 "SPDIF In", "Digitial In", "Reserved", "Other"
167 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
170 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
171 snd_iprintf(buffer, " Pincap 0x08%x:", caps);
172 if (caps & AC_PINCAP_IN)
173 snd_iprintf(buffer, " IN");
174 if (caps & AC_PINCAP_OUT)
175 snd_iprintf(buffer, " OUT");
176 if (caps & AC_PINCAP_HP_DRV)
177 snd_iprintf(buffer, " HP");
178 snd_iprintf(buffer, "\n");
179 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
180 snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
181 jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
182 jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
183 jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
184 get_jack_location(caps));
185 snd_iprintf(buffer, " Conn = %s, Color = %s\n",
186 get_jack_connection(caps),
187 get_jack_color(caps));
191 static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
193 struct hda_codec *codec = entry->private_data;
198 snd_hda_get_codec_name(codec, buf, sizeof(buf));
199 snd_iprintf(buffer, "Codec: %s\n", buf);
200 snd_iprintf(buffer, "Address: %d\n", codec->addr);
201 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
202 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
203 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
204 snd_iprintf(buffer, "Default PCM: ");
205 print_pcm_caps(buffer, codec, codec->afg);
206 snd_iprintf(buffer, "Default Amp-In caps: ");
207 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
208 snd_iprintf(buffer, "Default Amp-Out caps: ");
209 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
211 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
212 if (! nid || nodes < 0) {
213 snd_iprintf(buffer, "Invalid AFG subtree\n");
216 for (i = 0; i < nodes; i++, nid++) {
217 unsigned int wid_caps = snd_hda_param_read(codec, nid,
218 AC_PAR_AUDIO_WIDGET_CAP);
219 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
220 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
221 get_wid_type_name(wid_type), wid_caps);
222 if (wid_caps & AC_WCAP_STEREO)
223 snd_iprintf(buffer, " Stereo");
225 snd_iprintf(buffer, " Mono");
226 if (wid_caps & AC_WCAP_DIGITAL)
227 snd_iprintf(buffer, " Digital");
228 if (wid_caps & AC_WCAP_IN_AMP)
229 snd_iprintf(buffer, " Amp-In");
230 if (wid_caps & AC_WCAP_OUT_AMP)
231 snd_iprintf(buffer, " Amp-Out");
232 snd_iprintf(buffer, "\n");
234 if (wid_caps & AC_WCAP_IN_AMP) {
235 snd_iprintf(buffer, " Amp-In caps: ");
236 print_amp_caps(buffer, codec, nid, HDA_INPUT);
237 snd_iprintf(buffer, " Amp-In vals: ");
238 print_amp_vals(buffer, codec, nid, HDA_INPUT,
239 wid_caps & AC_WCAP_STEREO);
241 if (wid_caps & AC_WCAP_OUT_AMP) {
242 snd_iprintf(buffer, " Amp-Out caps: ");
243 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
244 snd_iprintf(buffer, " Amp-Out vals: ");
245 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
246 wid_caps & AC_WCAP_STEREO);
249 if (wid_type == AC_WID_PIN) {
250 unsigned int pinctls;
251 print_pin_caps(buffer, codec, nid);
252 pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
253 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
254 if (pinctls & AC_PINCTL_IN_EN)
255 snd_iprintf(buffer, " IN");
256 if (pinctls & AC_PINCTL_OUT_EN)
257 snd_iprintf(buffer, " OUT");
258 if (pinctls & AC_PINCTL_HP_EN)
259 snd_iprintf(buffer, " HP");
260 snd_iprintf(buffer, "\n");
263 if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
264 (wid_caps & AC_WCAP_FORMAT_OVRD)) {
265 snd_iprintf(buffer, " PCM: ");
266 print_pcm_caps(buffer, codec, nid);
269 if (wid_caps & AC_WCAP_CONN_LIST) {
270 hda_nid_t conn[HDA_MAX_CONNECTIONS];
271 int c, conn_len, curr = -1;
272 conn_len = snd_hda_get_connections(codec, nid, conn,
273 HDA_MAX_CONNECTIONS);
274 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
275 curr = snd_hda_codec_read(codec, nid, 0,
276 AC_VERB_GET_CONNECT_SEL, 0);
277 snd_iprintf(buffer, " Connection: %d\n", conn_len);
278 snd_iprintf(buffer, " ");
279 for (c = 0; c < conn_len; c++) {
280 snd_iprintf(buffer, " 0x%02x", conn[c]);
282 snd_iprintf(buffer, "*");
284 snd_iprintf(buffer, "\n");
292 int snd_hda_codec_proc_new(struct hda_codec *codec)
295 snd_info_entry_t *entry;
298 snprintf(name, sizeof(name), "codec#%d", codec->addr);
299 err = snd_card_proc_new(codec->bus->card, name, &entry);
303 snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);