RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / sound / pci / hda / hda_proc.c
blobe313e685f1617bd664fbd1cf167dab6a7954cb16
1 /*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
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",
43 wid_value &= 0xf;
44 if (names[wid_value])
45 return names[wid_value];
46 else
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)
53 unsigned int caps;
54 caps = snd_hda_param_read(codec, nid,
55 dir == HDA_OUTPUT ?
56 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
57 if (caps == -1 || caps == 0) {
58 snd_iprintf(buffer, "N/A\n");
59 return;
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)
72 unsigned int val;
73 int i;
75 dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
76 for (i = 0; i < indices; i++) {
77 snd_iprintf(buffer, " [");
78 if (stereo) {
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
96 int i;
98 pcm &= AC_SUPPCM_RATES;
99 snd_iprintf(buffer, " rates [0x%x]:", pcm);
100 for (i = 0; i < ARRAY_SIZE(rates); i++)
101 if (pcm & (1 << 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 };
109 int i;
111 pcm = (pcm >> 16) & 0xff;
112 snd_iprintf(buffer, " bits [0x%x]:", pcm);
113 for (i = 0; i < ARRAY_SIZE(bits); i++)
114 if (pcm & (1 << 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");
139 return;
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[] = {
152 0x07, 0x08,
153 0x17, 0x18, 0x19,
154 0x37, 0x38
156 static char *specials[] = {
157 "Rear Panel", "Drive Bar",
158 "Riser", "HDMI", "ATAPI",
159 "Mobile-In", "Mobile-Out"
161 int i;
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])
167 return specials[i];
169 return "UNKNOWN";
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;
181 if (names[cfg])
182 return names[cfg];
183 else
184 return "UNKNOWN";
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;
196 if (names[cfg])
197 return names[cfg];
198 else
199 return "UNKNOWN";
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" };
213 unsigned int caps;
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;
243 char buf[32];
244 hda_nid_t nid;
245 int i, nodes;
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);
253 if (! codec->afg)
254 return;
255 snd_iprintf(buffer, "Default PCM:\n");
256 print_pcm_caps(buffer, codec, codec->afg);
257 snd_iprintf(buffer, "Default Amp-In caps: ");
258 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
259 snd_iprintf(buffer, "Default Amp-Out caps: ");
260 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
262 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
263 if (! nid || nodes < 0) {
264 snd_iprintf(buffer, "Invalid AFG subtree\n");
265 return;
267 for (i = 0; i < nodes; i++, nid++) {
268 unsigned int wid_caps = snd_hda_param_read(codec, nid,
269 AC_PAR_AUDIO_WIDGET_CAP);
270 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
271 int conn_len = 0;
272 hda_nid_t conn[HDA_MAX_CONNECTIONS];
274 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
275 get_wid_type_name(wid_type), wid_caps);
276 if (wid_caps & AC_WCAP_STEREO)
277 snd_iprintf(buffer, " Stereo");
278 else
279 snd_iprintf(buffer, " Mono");
280 if (wid_caps & AC_WCAP_DIGITAL)
281 snd_iprintf(buffer, " Digital");
282 if (wid_caps & AC_WCAP_IN_AMP)
283 snd_iprintf(buffer, " Amp-In");
284 if (wid_caps & AC_WCAP_OUT_AMP)
285 snd_iprintf(buffer, " Amp-Out");
286 snd_iprintf(buffer, "\n");
288 if (wid_caps & AC_WCAP_CONN_LIST)
289 conn_len = snd_hda_get_connections(codec, nid, conn,
290 HDA_MAX_CONNECTIONS);
292 if (wid_caps & AC_WCAP_IN_AMP) {
293 snd_iprintf(buffer, " Amp-In caps: ");
294 print_amp_caps(buffer, codec, nid, HDA_INPUT);
295 snd_iprintf(buffer, " Amp-In vals: ");
296 print_amp_vals(buffer, codec, nid, HDA_INPUT,
297 wid_caps & AC_WCAP_STEREO, conn_len);
299 if (wid_caps & AC_WCAP_OUT_AMP) {
300 snd_iprintf(buffer, " Amp-Out caps: ");
301 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
302 snd_iprintf(buffer, " Amp-Out vals: ");
303 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
304 wid_caps & AC_WCAP_STEREO, 1);
307 if (wid_type == AC_WID_PIN) {
308 unsigned int pinctls;
309 print_pin_caps(buffer, codec, nid);
310 pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
311 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
312 if (pinctls & AC_PINCTL_IN_EN)
313 snd_iprintf(buffer, " IN");
314 if (pinctls & AC_PINCTL_OUT_EN)
315 snd_iprintf(buffer, " OUT");
316 if (pinctls & AC_PINCTL_HP_EN)
317 snd_iprintf(buffer, " HP");
318 snd_iprintf(buffer, "\n");
321 if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
322 (wid_caps & AC_WCAP_FORMAT_OVRD)) {
323 snd_iprintf(buffer, " PCM:\n");
324 print_pcm_caps(buffer, codec, nid);
327 if (wid_caps & AC_WCAP_POWER)
328 snd_iprintf(buffer, " Power: 0x%x\n",
329 snd_hda_codec_read(codec, nid, 0,
330 AC_VERB_GET_POWER_STATE, 0));
332 if (wid_caps & AC_WCAP_CONN_LIST) {
333 int c, curr = -1;
334 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
335 curr = snd_hda_codec_read(codec, nid, 0,
336 AC_VERB_GET_CONNECT_SEL, 0);
337 snd_iprintf(buffer, " Connection: %d\n", conn_len);
338 snd_iprintf(buffer, " ");
339 for (c = 0; c < conn_len; c++) {
340 snd_iprintf(buffer, " 0x%02x", conn[c]);
341 if (c == curr)
342 snd_iprintf(buffer, "*");
344 snd_iprintf(buffer, "\n");
350 * create a proc read
352 int snd_hda_codec_proc_new(struct hda_codec *codec)
354 char name[32];
355 struct snd_info_entry *entry;
356 int err;
358 snprintf(name, sizeof(name), "codec#%d", codec->addr);
359 err = snd_card_proc_new(codec->bus->card, name, &entry);
360 if (err < 0)
361 return err;
363 snd_info_set_text_ops(entry, codec, print_codec_info);
364 return 0;