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_types
[16] = {
161 "Line Out", "Speaker", "HP Out", "CD",
162 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
163 "Line In", "Aux", "Mic", "Telephony",
164 "SPDIF In", "Digitial In", "Reserved", "Other"
166 static char *jack_locations
[4] = { "Ext", "Int", "Sep", "Oth" };
169 caps
= snd_hda_param_read(codec
, nid
, AC_PAR_PIN_CAP
);
170 snd_iprintf(buffer
, " Pincap 0x08%x:", caps
);
171 if (caps
& AC_PINCAP_IN
)
172 snd_iprintf(buffer
, " IN");
173 if (caps
& AC_PINCAP_OUT
)
174 snd_iprintf(buffer
, " OUT");
175 if (caps
& AC_PINCAP_HP_DRV
)
176 snd_iprintf(buffer
, " HP");
177 snd_iprintf(buffer
, "\n");
178 caps
= snd_hda_codec_read(codec
, nid
, 0, AC_VERB_GET_CONFIG_DEFAULT
, 0);
179 snd_iprintf(buffer
, " Pin Default 0x%08x: %s at %s %s\n", caps
,
180 jack_types
[(caps
& AC_DEFCFG_DEVICE
) >> AC_DEFCFG_DEVICE_SHIFT
],
181 jack_locations
[(caps
>> (AC_DEFCFG_LOCATION_SHIFT
+ 4)) & 3],
182 get_jack_location(caps
));
183 snd_iprintf(buffer
, " Conn = %s, Color = %s\n",
184 get_jack_connection(caps
),
185 get_jack_color(caps
));
189 static void print_codec_info(snd_info_entry_t
*entry
, snd_info_buffer_t
*buffer
)
191 struct hda_codec
*codec
= entry
->private_data
;
196 snd_hda_get_codec_name(codec
, buf
, sizeof(buf
));
197 snd_iprintf(buffer
, "Codec: %s\n", buf
);
198 snd_iprintf(buffer
, "Address: %d\n", codec
->addr
);
199 snd_iprintf(buffer
, "Vendor Id: 0x%x\n", codec
->vendor_id
);
200 snd_iprintf(buffer
, "Subsystem Id: 0x%x\n", codec
->subsystem_id
);
201 snd_iprintf(buffer
, "Revision Id: 0x%x\n", codec
->revision_id
);
202 snd_iprintf(buffer
, "Default PCM: ");
203 print_pcm_caps(buffer
, codec
, codec
->afg
);
204 snd_iprintf(buffer
, "Default Amp-In caps: ");
205 print_amp_caps(buffer
, codec
, codec
->afg
, HDA_INPUT
);
206 snd_iprintf(buffer
, "Default Amp-Out caps: ");
207 print_amp_caps(buffer
, codec
, codec
->afg
, HDA_OUTPUT
);
209 nodes
= snd_hda_get_sub_nodes(codec
, codec
->afg
, &nid
);
210 if (! nid
|| nodes
< 0) {
211 snd_iprintf(buffer
, "Invalid AFG subtree\n");
214 for (i
= 0; i
< nodes
; i
++, nid
++) {
215 unsigned int wid_caps
= snd_hda_param_read(codec
, nid
,
216 AC_PAR_AUDIO_WIDGET_CAP
);
217 unsigned int wid_type
= (wid_caps
& AC_WCAP_TYPE
) >> AC_WCAP_TYPE_SHIFT
;
218 snd_iprintf(buffer
, "Node 0x%02x [%s] wcaps 0x%x:", nid
,
219 get_wid_type_name(wid_type
), wid_caps
);
220 if (wid_caps
& AC_WCAP_STEREO
)
221 snd_iprintf(buffer
, " Stereo");
223 snd_iprintf(buffer
, " Mono");
224 if (wid_caps
& AC_WCAP_DIGITAL
)
225 snd_iprintf(buffer
, " Digital");
226 if (wid_caps
& AC_WCAP_IN_AMP
)
227 snd_iprintf(buffer
, " Amp-In");
228 if (wid_caps
& AC_WCAP_OUT_AMP
)
229 snd_iprintf(buffer
, " Amp-Out");
230 snd_iprintf(buffer
, "\n");
232 if (wid_caps
& AC_WCAP_IN_AMP
) {
233 snd_iprintf(buffer
, " Amp-In caps: ");
234 print_amp_caps(buffer
, codec
, nid
, HDA_INPUT
);
235 snd_iprintf(buffer
, " Amp-In vals: ");
236 print_amp_vals(buffer
, codec
, nid
, HDA_INPUT
,
237 wid_caps
& AC_WCAP_STEREO
);
239 if (wid_caps
& AC_WCAP_OUT_AMP
) {
240 snd_iprintf(buffer
, " Amp-Out caps: ");
241 print_amp_caps(buffer
, codec
, nid
, HDA_OUTPUT
);
242 snd_iprintf(buffer
, " Amp-Out vals: ");
243 print_amp_vals(buffer
, codec
, nid
, HDA_OUTPUT
,
244 wid_caps
& AC_WCAP_STEREO
);
247 if (wid_type
== AC_WID_PIN
) {
248 unsigned int pinctls
;
249 print_pin_caps(buffer
, codec
, nid
);
250 pinctls
= snd_hda_codec_read(codec
, nid
, 0, AC_VERB_GET_PIN_WIDGET_CONTROL
, 0);
251 snd_iprintf(buffer
, " Pin-ctls: 0x%02x:", pinctls
);
252 if (pinctls
& AC_PINCTL_IN_EN
)
253 snd_iprintf(buffer
, " IN");
254 if (pinctls
& AC_PINCTL_OUT_EN
)
255 snd_iprintf(buffer
, " OUT");
256 if (pinctls
& AC_PINCTL_HP_EN
)
257 snd_iprintf(buffer
, " HP");
258 snd_iprintf(buffer
, "\n");
261 if ((wid_type
== AC_WID_AUD_OUT
|| wid_type
== AC_WID_AUD_IN
) &&
262 (wid_caps
& AC_WCAP_FORMAT_OVRD
)) {
263 snd_iprintf(buffer
, " PCM: ");
264 print_pcm_caps(buffer
, codec
, nid
);
267 if (wid_caps
& AC_WCAP_CONN_LIST
) {
268 hda_nid_t conn
[HDA_MAX_CONNECTIONS
];
270 conn_len
= snd_hda_get_connections(codec
, nid
, conn
,
271 HDA_MAX_CONNECTIONS
);
272 snd_iprintf(buffer
, " Connection: %d\n", conn_len
);
273 snd_iprintf(buffer
, " ");
274 for (c
= 0; c
< conn_len
; c
++)
275 snd_iprintf(buffer
, " 0x%02x", conn
[c
]);
276 snd_iprintf(buffer
, "\n");
284 int snd_hda_codec_proc_new(struct hda_codec
*codec
)
287 snd_info_entry_t
*entry
;
290 snprintf(name
, sizeof(name
), "codec#%d", codec
->addr
);
291 err
= snd_card_proc_new(codec
->bus
->card
, name
, &entry
);
295 snd_info_set_text_ops(entry
, codec
, 32 * 1024, print_codec_info
);