[ALSA] sound/: possible cleanups
[linux-2.6/kvm.git] / sound / pci / hda / hda_proc.c
blobca514a6a58751781e809c10a010eaf74ef8fea26
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 <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",
44 wid_value &= 0xf;
45 if (names[wid_value])
46 return names[wid_value];
47 else
48 return "UNKOWN Widget";
51 static void print_amp_caps(struct snd_info_buffer *buffer,
52 struct hda_codec *codec, hda_nid_t nid, int dir)
54 unsigned int caps;
55 if (dir == HDA_OUTPUT)
56 caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
57 else
58 caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP);
59 if (caps == -1 || caps == 0) {
60 snd_iprintf(buffer, "N/A\n");
61 return;
63 snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n",
64 caps & AC_AMPCAP_OFFSET,
65 (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
66 (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
67 (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
70 static void print_amp_vals(struct snd_info_buffer *buffer,
71 struct hda_codec *codec, hda_nid_t nid,
72 int dir, int stereo, int indices)
74 unsigned int val;
75 int i;
77 if (dir == HDA_OUTPUT)
78 dir = AC_AMP_GET_OUTPUT;
79 else
80 dir = AC_AMP_GET_INPUT;
81 for (i = 0; i < indices; i++) {
82 snd_iprintf(buffer, " [");
83 if (stereo) {
84 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
85 AC_AMP_GET_LEFT | dir | i);
86 snd_iprintf(buffer, "0x%02x ", val);
88 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
89 AC_AMP_GET_RIGHT | dir | i);
90 snd_iprintf(buffer, "0x%02x]", val);
92 snd_iprintf(buffer, "\n");
95 static void print_pcm_caps(struct snd_info_buffer *buffer,
96 struct hda_codec *codec, hda_nid_t nid)
98 unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
99 unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
100 if (pcm == -1 || stream == -1) {
101 snd_iprintf(buffer, "N/A\n");
102 return;
104 snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n",
105 pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf);
108 static const char *get_jack_location(u32 cfg)
110 static char *bases[7] = {
111 "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
113 static unsigned char specials_idx[] = {
114 0x07, 0x08,
115 0x17, 0x18, 0x19,
116 0x37, 0x38
118 static char *specials[] = {
119 "Rear Panel", "Drive Bar",
120 "Riser", "HDMI", "ATAPI",
121 "Mobile-In", "Mobile-Out"
123 int i;
124 cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
125 if ((cfg & 0x0f) < 7)
126 return bases[cfg & 0x0f];
127 for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
128 if (cfg == specials_idx[i])
129 return specials[i];
131 return "UNKNOWN";
134 static const char *get_jack_connection(u32 cfg)
136 static char *names[16] = {
137 "Unknown", "1/8", "1/4", "ATAPI",
138 "RCA", "Optical","Digital", "Analog",
139 "DIN", "XLR", "RJ11", "Comb",
140 NULL, NULL, NULL, "Other"
142 cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
143 if (names[cfg])
144 return names[cfg];
145 else
146 return "UNKNOWN";
149 static const char *get_jack_color(u32 cfg)
151 static char *names[16] = {
152 "Unknown", "Black", "Grey", "Blue",
153 "Green", "Red", "Orange", "Yellow",
154 "Purple", "Pink", NULL, NULL,
155 NULL, NULL, "White", "Other",
157 cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
158 if (names[cfg])
159 return names[cfg];
160 else
161 return "UNKNOWN";
164 static void print_pin_caps(struct snd_info_buffer *buffer,
165 struct hda_codec *codec, hda_nid_t nid)
167 static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
168 static char *jack_types[16] = {
169 "Line Out", "Speaker", "HP Out", "CD",
170 "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
171 "Line In", "Aux", "Mic", "Telephony",
172 "SPDIF In", "Digitial In", "Reserved", "Other"
174 static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
175 unsigned int caps;
177 caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
178 snd_iprintf(buffer, " Pincap 0x08%x:", caps);
179 if (caps & AC_PINCAP_IN)
180 snd_iprintf(buffer, " IN");
181 if (caps & AC_PINCAP_OUT)
182 snd_iprintf(buffer, " OUT");
183 if (caps & AC_PINCAP_HP_DRV)
184 snd_iprintf(buffer, " HP");
185 snd_iprintf(buffer, "\n");
186 caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
187 snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
188 jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
189 jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
190 jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
191 get_jack_location(caps));
192 snd_iprintf(buffer, " Conn = %s, Color = %s\n",
193 get_jack_connection(caps),
194 get_jack_color(caps));
198 static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
200 struct hda_codec *codec = entry->private_data;
201 char buf[32];
202 hda_nid_t nid;
203 int i, nodes;
205 snd_hda_get_codec_name(codec, buf, sizeof(buf));
206 snd_iprintf(buffer, "Codec: %s\n", buf);
207 snd_iprintf(buffer, "Address: %d\n", codec->addr);
208 snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
209 snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
210 snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
211 if (! codec->afg)
212 return;
213 snd_iprintf(buffer, "Default PCM: ");
214 print_pcm_caps(buffer, codec, codec->afg);
215 snd_iprintf(buffer, "Default Amp-In caps: ");
216 print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
217 snd_iprintf(buffer, "Default Amp-Out caps: ");
218 print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
220 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
221 if (! nid || nodes < 0) {
222 snd_iprintf(buffer, "Invalid AFG subtree\n");
223 return;
225 for (i = 0; i < nodes; i++, nid++) {
226 unsigned int wid_caps = snd_hda_param_read(codec, nid,
227 AC_PAR_AUDIO_WIDGET_CAP);
228 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
229 int conn_len = 0;
230 hda_nid_t conn[HDA_MAX_CONNECTIONS];
232 snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
233 get_wid_type_name(wid_type), wid_caps);
234 if (wid_caps & AC_WCAP_STEREO)
235 snd_iprintf(buffer, " Stereo");
236 else
237 snd_iprintf(buffer, " Mono");
238 if (wid_caps & AC_WCAP_DIGITAL)
239 snd_iprintf(buffer, " Digital");
240 if (wid_caps & AC_WCAP_IN_AMP)
241 snd_iprintf(buffer, " Amp-In");
242 if (wid_caps & AC_WCAP_OUT_AMP)
243 snd_iprintf(buffer, " Amp-Out");
244 snd_iprintf(buffer, "\n");
246 if (wid_caps & AC_WCAP_CONN_LIST)
247 conn_len = snd_hda_get_connections(codec, nid, conn,
248 HDA_MAX_CONNECTIONS);
250 if (wid_caps & AC_WCAP_IN_AMP) {
251 snd_iprintf(buffer, " Amp-In caps: ");
252 print_amp_caps(buffer, codec, nid, HDA_INPUT);
253 snd_iprintf(buffer, " Amp-In vals: ");
254 print_amp_vals(buffer, codec, nid, HDA_INPUT,
255 wid_caps & AC_WCAP_STEREO, conn_len);
257 if (wid_caps & AC_WCAP_OUT_AMP) {
258 snd_iprintf(buffer, " Amp-Out caps: ");
259 print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
260 snd_iprintf(buffer, " Amp-Out vals: ");
261 print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
262 wid_caps & AC_WCAP_STEREO, 1);
265 if (wid_type == AC_WID_PIN) {
266 unsigned int pinctls;
267 print_pin_caps(buffer, codec, nid);
268 pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
269 snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
270 if (pinctls & AC_PINCTL_IN_EN)
271 snd_iprintf(buffer, " IN");
272 if (pinctls & AC_PINCTL_OUT_EN)
273 snd_iprintf(buffer, " OUT");
274 if (pinctls & AC_PINCTL_HP_EN)
275 snd_iprintf(buffer, " HP");
276 snd_iprintf(buffer, "\n");
279 if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
280 (wid_caps & AC_WCAP_FORMAT_OVRD)) {
281 snd_iprintf(buffer, " PCM: ");
282 print_pcm_caps(buffer, codec, nid);
285 if (wid_caps & AC_WCAP_POWER)
286 snd_iprintf(buffer, " Power: 0x%x\n",
287 snd_hda_codec_read(codec, nid, 0,
288 AC_VERB_GET_POWER_STATE, 0));
290 if (wid_caps & AC_WCAP_CONN_LIST) {
291 int c, curr = -1;
292 if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
293 curr = snd_hda_codec_read(codec, nid, 0,
294 AC_VERB_GET_CONNECT_SEL, 0);
295 snd_iprintf(buffer, " Connection: %d\n", conn_len);
296 snd_iprintf(buffer, " ");
297 for (c = 0; c < conn_len; c++) {
298 snd_iprintf(buffer, " 0x%02x", conn[c]);
299 if (c == curr)
300 snd_iprintf(buffer, "*");
302 snd_iprintf(buffer, "\n");
308 * create a proc read
310 int snd_hda_codec_proc_new(struct hda_codec *codec)
312 char name[32];
313 struct snd_info_entry *entry;
314 int err;
316 snprintf(name, sizeof(name), "codec#%d", codec->addr);
317 err = snd_card_proc_new(codec->bus->card, name, &entry);
318 if (err < 0)
319 return err;
321 snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);
322 return 0;