Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Universal Interface for Intel High Definition Audio Codec
4 : : *
5 : : * Generic proc interface
6 : : *
7 : : * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
8 : : */
9 : :
10 : : #include <linux/init.h>
11 : : #include <linux/slab.h>
12 : : #include <sound/core.h>
13 : : #include <linux/module.h>
14 : : #include <sound/hda_codec.h>
15 : : #include "hda_local.h"
16 : :
17 : : static int dump_coef = -1;
18 : : module_param(dump_coef, int, 0644);
19 : : MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
20 : :
21 : : /* always use noncached version */
22 : : #define param_read(codec, nid, parm) \
23 : : snd_hdac_read_parm_uncached(&(codec)->core, nid, parm)
24 : :
25 : 0 : static const char *get_wid_type_name(unsigned int wid_value)
26 : : {
27 : 0 : static const char * const names[16] = {
28 : : [AC_WID_AUD_OUT] = "Audio Output",
29 : : [AC_WID_AUD_IN] = "Audio Input",
30 : : [AC_WID_AUD_MIX] = "Audio Mixer",
31 : : [AC_WID_AUD_SEL] = "Audio Selector",
32 : : [AC_WID_PIN] = "Pin Complex",
33 : : [AC_WID_POWER] = "Power Widget",
34 : : [AC_WID_VOL_KNB] = "Volume Knob Widget",
35 : : [AC_WID_BEEP] = "Beep Generator Widget",
36 : : [AC_WID_VENDOR] = "Vendor Defined Widget",
37 : : };
38 : 0 : if (wid_value == -1)
39 : : return "UNKNOWN Widget";
40 : 0 : wid_value &= 0xf;
41 [ # # ]: 0 : if (names[wid_value])
42 : : return names[wid_value];
43 : : else
44 : 0 : return "UNKNOWN Widget";
45 : : }
46 : :
47 : 0 : static void print_nid_array(struct snd_info_buffer *buffer,
48 : : struct hda_codec *codec, hda_nid_t nid,
49 : : struct snd_array *array)
50 : : {
51 : 0 : int i;
52 : 0 : struct hda_nid_item *items = array->list, *item;
53 : 0 : struct snd_kcontrol *kctl;
54 [ # # ]: 0 : for (i = 0; i < array->used; i++) {
55 : 0 : item = &items[i];
56 [ # # ]: 0 : if (item->nid == nid) {
57 : 0 : kctl = item->kctl;
58 : 0 : snd_iprintf(buffer,
59 : : " Control: name=\"%s\", index=%i, device=%i\n",
60 : : kctl->id.name, kctl->id.index + item->index,
61 : : kctl->id.device);
62 [ # # ]: 0 : if (item->flags & HDA_NID_ITEM_AMP)
63 [ # # ]: 0 : snd_iprintf(buffer,
64 : : " ControlAmp: chs=%lu, dir=%s, "
65 : : "idx=%lu, ofs=%lu\n",
66 : : get_amp_channels(kctl),
67 : : get_amp_direction(kctl) ? "Out" : "In",
68 : : get_amp_index(kctl),
69 : : get_amp_offset(kctl));
70 : : }
71 : : }
72 : 0 : }
73 : :
74 : 0 : static void print_nid_pcms(struct snd_info_buffer *buffer,
75 : : struct hda_codec *codec, hda_nid_t nid)
76 : : {
77 : 0 : int type;
78 : 0 : struct hda_pcm *cpcm;
79 : :
80 [ # # ]: 0 : list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
81 [ # # ]: 0 : for (type = 0; type < 2; type++) {
82 [ # # # # ]: 0 : if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
83 : 0 : continue;
84 : 0 : snd_iprintf(buffer, " Device: name=\"%s\", "
85 : : "type=\"%s\", device=%i\n",
86 : : cpcm->name,
87 : : snd_hda_pcm_type_name[cpcm->pcm_type],
88 : : cpcm->pcm->device);
89 : : }
90 : : }
91 : 0 : }
92 : :
93 : 0 : static void print_amp_caps(struct snd_info_buffer *buffer,
94 : : struct hda_codec *codec, hda_nid_t nid, int dir)
95 : : {
96 : 0 : unsigned int caps;
97 [ # # ]: 0 : caps = param_read(codec, nid, dir == HDA_OUTPUT ?
98 : : AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
99 [ # # ]: 0 : if (caps == -1 || caps == 0) {
100 : 0 : snd_iprintf(buffer, "N/A\n");
101 : 0 : return;
102 : : }
103 : 0 : snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, "
104 : : "mute=%x\n",
105 : : caps & AC_AMPCAP_OFFSET,
106 : : (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
107 : : (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
108 : : (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
109 : : }
110 : :
111 : : /* is this a stereo widget or a stereo-to-mono mix? */
112 : 0 : static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid,
113 : : int dir, unsigned int wcaps, int indices)
114 : : {
115 : 0 : hda_nid_t conn;
116 : :
117 [ # # ]: 0 : if (wcaps & AC_WCAP_STEREO)
118 : : return true;
119 : : /* check for a stereo-to-mono mix; it must be:
120 : : * only a single connection, only for input, and only a mixer widget
121 : : */
122 [ # # # # ]: 0 : if (indices != 1 || dir != HDA_INPUT ||
123 : : get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
124 : : return false;
125 : :
126 [ # # ]: 0 : if (snd_hda_get_raw_connections(codec, nid, &conn, 1) < 0)
127 : : return false;
128 : : /* the connection source is a stereo? */
129 : 0 : wcaps = snd_hda_param_read(codec, conn, AC_PAR_AUDIO_WIDGET_CAP);
130 : 0 : return !!(wcaps & AC_WCAP_STEREO);
131 : : }
132 : :
133 : 0 : static void print_amp_vals(struct snd_info_buffer *buffer,
134 : : struct hda_codec *codec, hda_nid_t nid,
135 : : int dir, unsigned int wcaps, int indices)
136 : : {
137 : 0 : unsigned int val;
138 : 0 : bool stereo;
139 : 0 : int i;
140 : :
141 : 0 : stereo = is_stereo_amps(codec, nid, dir, wcaps, indices);
142 : :
143 [ # # ]: 0 : dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
144 [ # # ]: 0 : for (i = 0; i < indices; i++) {
145 : 0 : snd_iprintf(buffer, " [");
146 : 0 : val = snd_hda_codec_read(codec, nid, 0,
147 : : AC_VERB_GET_AMP_GAIN_MUTE,
148 : 0 : AC_AMP_GET_LEFT | dir | i);
149 : 0 : snd_iprintf(buffer, "0x%02x", val);
150 [ # # ]: 0 : if (stereo) {
151 : 0 : val = snd_hda_codec_read(codec, nid, 0,
152 : : AC_VERB_GET_AMP_GAIN_MUTE,
153 : : AC_AMP_GET_RIGHT | dir | i);
154 : 0 : snd_iprintf(buffer, " 0x%02x", val);
155 : : }
156 : 0 : snd_iprintf(buffer, "]");
157 : : }
158 : 0 : snd_iprintf(buffer, "\n");
159 : 0 : }
160 : :
161 : : static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
162 : : {
163 : : static const unsigned int rates[] = {
164 : : 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
165 : : 96000, 176400, 192000, 384000
166 : : };
167 : : int i;
168 : :
169 : : pcm &= AC_SUPPCM_RATES;
170 : : snd_iprintf(buffer, " rates [0x%x]:", pcm);
171 : : for (i = 0; i < ARRAY_SIZE(rates); i++)
172 : : if (pcm & (1 << i))
173 : : snd_iprintf(buffer, " %d", rates[i]);
174 : : snd_iprintf(buffer, "\n");
175 : : }
176 : :
177 : : static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
178 : : {
179 : : char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
180 : :
181 : : snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff);
182 : : snd_print_pcm_bits(pcm, buf, sizeof(buf));
183 : : snd_iprintf(buffer, "%s\n", buf);
184 : : }
185 : :
186 : : static void print_pcm_formats(struct snd_info_buffer *buffer,
187 : : unsigned int streams)
188 : : {
189 : : snd_iprintf(buffer, " formats [0x%x]:", streams & 0xf);
190 : : if (streams & AC_SUPFMT_PCM)
191 : : snd_iprintf(buffer, " PCM");
192 : : if (streams & AC_SUPFMT_FLOAT32)
193 : : snd_iprintf(buffer, " FLOAT");
194 : : if (streams & AC_SUPFMT_AC3)
195 : : snd_iprintf(buffer, " AC3");
196 : : snd_iprintf(buffer, "\n");
197 : : }
198 : :
199 : 0 : static void print_pcm_caps(struct snd_info_buffer *buffer,
200 : : struct hda_codec *codec, hda_nid_t nid)
201 : : {
202 : 0 : unsigned int pcm = param_read(codec, nid, AC_PAR_PCM);
203 : 0 : unsigned int stream = param_read(codec, nid, AC_PAR_STREAM);
204 [ # # ]: 0 : if (pcm == -1 || stream == -1) {
205 : 0 : snd_iprintf(buffer, "N/A\n");
206 : 0 : return;
207 : : }
208 : 0 : print_pcm_rates(buffer, pcm);
209 : 0 : print_pcm_bits(buffer, pcm);
210 : 0 : print_pcm_formats(buffer, stream);
211 : : }
212 : :
213 : 0 : static const char *get_jack_connection(u32 cfg)
214 : : {
215 : 0 : static const char * const names[16] = {
216 : : "Unknown", "1/8", "1/4", "ATAPI",
217 : : "RCA", "Optical","Digital", "Analog",
218 : : "DIN", "XLR", "RJ11", "Comb",
219 : : NULL, NULL, NULL, "Other"
220 : : };
221 : 0 : cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
222 [ # # ]: 0 : if (names[cfg])
223 : : return names[cfg];
224 : : else
225 : 0 : return "UNKNOWN";
226 : : }
227 : :
228 : 0 : static const char *get_jack_color(u32 cfg)
229 : : {
230 : 0 : static const char * const names[16] = {
231 : : "Unknown", "Black", "Grey", "Blue",
232 : : "Green", "Red", "Orange", "Yellow",
233 : : "Purple", "Pink", NULL, NULL,
234 : : NULL, NULL, "White", "Other",
235 : : };
236 : 0 : cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
237 : 0 : if (names[cfg])
238 : : return names[cfg];
239 : : else
240 : 0 : return "UNKNOWN";
241 : : }
242 : :
243 : : /*
244 : : * Parse the pin default config value and returns the string of the
245 : : * jack location, e.g. "Rear", "Front", etc.
246 : : */
247 : 0 : static const char *get_jack_location(u32 cfg)
248 : : {
249 : 0 : static const char * const bases[7] = {
250 : : "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
251 : : };
252 : 0 : static const unsigned char specials_idx[] = {
253 : : 0x07, 0x08,
254 : : 0x17, 0x18, 0x19,
255 : : 0x37, 0x38
256 : : };
257 : 0 : static const char * const specials[] = {
258 : : "Rear Panel", "Drive Bar",
259 : : "Riser", "HDMI", "ATAPI",
260 : : "Mobile-In", "Mobile-Out"
261 : : };
262 : 0 : int i;
263 : :
264 : 0 : cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
265 : 0 : if ((cfg & 0x0f) < 7)
266 : 0 : return bases[cfg & 0x0f];
267 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
268 [ # # ]: 0 : if (cfg == specials_idx[i])
269 : 0 : return specials[i];
270 : : }
271 : : return "UNKNOWN";
272 : : }
273 : :
274 : : /*
275 : : * Parse the pin default config value and returns the string of the
276 : : * jack connectivity, i.e. external or internal connection.
277 : : */
278 : 0 : static const char *get_jack_connectivity(u32 cfg)
279 : : {
280 : 0 : static const char * const jack_locations[4] = {
281 : : "Ext", "Int", "Sep", "Oth"
282 : : };
283 : :
284 : 0 : return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
285 : : }
286 : :
287 : : /*
288 : : * Parse the pin default config value and returns the string of the
289 : : * jack type, i.e. the purpose of the jack, such as Line-Out or CD.
290 : : */
291 : 0 : static const char *get_jack_type(u32 cfg)
292 : : {
293 : 0 : static const char * const jack_types[16] = {
294 : : "Line Out", "Speaker", "HP Out", "CD",
295 : : "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
296 : : "Line In", "Aux", "Mic", "Telephony",
297 : : "SPDIF In", "Digital In", "Reserved", "Other"
298 : : };
299 : :
300 : 0 : return jack_types[(cfg & AC_DEFCFG_DEVICE)
301 : 0 : >> AC_DEFCFG_DEVICE_SHIFT];
302 : : }
303 : :
304 : 0 : static void print_pin_caps(struct snd_info_buffer *buffer,
305 : : struct hda_codec *codec, hda_nid_t nid,
306 : : int *supports_vref)
307 : : {
308 : 0 : static const char * const jack_conns[4] = {
309 : : "Jack", "N/A", "Fixed", "Both"
310 : : };
311 : 0 : unsigned int caps, val;
312 : :
313 : 0 : caps = param_read(codec, nid, AC_PAR_PIN_CAP);
314 : 0 : snd_iprintf(buffer, " Pincap 0x%08x:", caps);
315 [ # # ]: 0 : if (caps & AC_PINCAP_IN)
316 : 0 : snd_iprintf(buffer, " IN");
317 [ # # ]: 0 : if (caps & AC_PINCAP_OUT)
318 : 0 : snd_iprintf(buffer, " OUT");
319 [ # # ]: 0 : if (caps & AC_PINCAP_HP_DRV)
320 : 0 : snd_iprintf(buffer, " HP");
321 [ # # ]: 0 : if (caps & AC_PINCAP_EAPD)
322 : 0 : snd_iprintf(buffer, " EAPD");
323 [ # # ]: 0 : if (caps & AC_PINCAP_PRES_DETECT)
324 : 0 : snd_iprintf(buffer, " Detect");
325 [ # # ]: 0 : if (caps & AC_PINCAP_BALANCE)
326 : 0 : snd_iprintf(buffer, " Balanced");
327 [ # # ]: 0 : if (caps & AC_PINCAP_HDMI) {
328 : : /* Realtek uses this bit as a different meaning */
329 [ # # ]: 0 : if ((codec->core.vendor_id >> 16) == 0x10ec)
330 : 0 : snd_iprintf(buffer, " R/L");
331 : : else {
332 [ # # ]: 0 : if (caps & AC_PINCAP_HBR)
333 : 0 : snd_iprintf(buffer, " HBR");
334 : 0 : snd_iprintf(buffer, " HDMI");
335 : : }
336 : : }
337 [ # # ]: 0 : if (caps & AC_PINCAP_DP)
338 : 0 : snd_iprintf(buffer, " DP");
339 [ # # ]: 0 : if (caps & AC_PINCAP_TRIG_REQ)
340 : 0 : snd_iprintf(buffer, " Trigger");
341 [ # # ]: 0 : if (caps & AC_PINCAP_IMP_SENSE)
342 : 0 : snd_iprintf(buffer, " ImpSense");
343 : 0 : snd_iprintf(buffer, "\n");
344 [ # # ]: 0 : if (caps & AC_PINCAP_VREF) {
345 : 0 : unsigned int vref =
346 : 0 : (caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
347 : 0 : snd_iprintf(buffer, " Vref caps:");
348 [ # # ]: 0 : if (vref & AC_PINCAP_VREF_HIZ)
349 : 0 : snd_iprintf(buffer, " HIZ");
350 [ # # ]: 0 : if (vref & AC_PINCAP_VREF_50)
351 : 0 : snd_iprintf(buffer, " 50");
352 [ # # ]: 0 : if (vref & AC_PINCAP_VREF_GRD)
353 : 0 : snd_iprintf(buffer, " GRD");
354 [ # # ]: 0 : if (vref & AC_PINCAP_VREF_80)
355 : 0 : snd_iprintf(buffer, " 80");
356 [ # # ]: 0 : if (vref & AC_PINCAP_VREF_100)
357 : 0 : snd_iprintf(buffer, " 100");
358 : 0 : snd_iprintf(buffer, "\n");
359 : 0 : *supports_vref = 1;
360 : : } else
361 : 0 : *supports_vref = 0;
362 [ # # ]: 0 : if (caps & AC_PINCAP_EAPD) {
363 : 0 : val = snd_hda_codec_read(codec, nid, 0,
364 : : AC_VERB_GET_EAPD_BTLENABLE, 0);
365 : 0 : snd_iprintf(buffer, " EAPD 0x%x:", val);
366 [ # # ]: 0 : if (val & AC_EAPDBTL_BALANCED)
367 : 0 : snd_iprintf(buffer, " BALANCED");
368 [ # # ]: 0 : if (val & AC_EAPDBTL_EAPD)
369 : 0 : snd_iprintf(buffer, " EAPD");
370 [ # # ]: 0 : if (val & AC_EAPDBTL_LR_SWAP)
371 : 0 : snd_iprintf(buffer, " R/L");
372 : 0 : snd_iprintf(buffer, "\n");
373 : : }
374 : 0 : caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
375 [ # # ]: 0 : snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
376 : : jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
377 : : get_jack_type(caps),
378 : : get_jack_connectivity(caps),
379 : : get_jack_location(caps));
380 [ # # ]: 0 : snd_iprintf(buffer, " Conn = %s, Color = %s\n",
381 : : get_jack_connection(caps),
382 : : get_jack_color(caps));
383 : : /* Default association and sequence values refer to default grouping
384 : : * of pin complexes and their sequence within the group. This is used
385 : : * for priority and resource allocation.
386 : : */
387 : 0 : snd_iprintf(buffer, " DefAssociation = 0x%x, Sequence = 0x%x\n",
388 : : (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
389 : : caps & AC_DEFCFG_SEQUENCE);
390 [ # # ]: 0 : if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
391 : : AC_DEFCFG_MISC_NO_PRESENCE) {
392 : : /* Miscellaneous bit indicates external hardware does not
393 : : * support presence detection even if the pin complex
394 : : * indicates it is supported.
395 : : */
396 : 0 : snd_iprintf(buffer, " Misc = NO_PRESENCE\n");
397 : : }
398 : 0 : }
399 : :
400 : 0 : static void print_pin_ctls(struct snd_info_buffer *buffer,
401 : : struct hda_codec *codec, hda_nid_t nid,
402 : : int supports_vref)
403 : : {
404 : 0 : unsigned int pinctls;
405 : :
406 : 0 : pinctls = snd_hda_codec_read(codec, nid, 0,
407 : : AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
408 : 0 : snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
409 [ # # ]: 0 : if (pinctls & AC_PINCTL_IN_EN)
410 : 0 : snd_iprintf(buffer, " IN");
411 [ # # ]: 0 : if (pinctls & AC_PINCTL_OUT_EN)
412 : 0 : snd_iprintf(buffer, " OUT");
413 [ # # ]: 0 : if (pinctls & AC_PINCTL_HP_EN)
414 : 0 : snd_iprintf(buffer, " HP");
415 [ # # ]: 0 : if (supports_vref) {
416 : 0 : int vref = pinctls & AC_PINCTL_VREFEN;
417 [ # # # # : 0 : switch (vref) {
# # ]
418 : 0 : case AC_PINCTL_VREF_HIZ:
419 : 0 : snd_iprintf(buffer, " VREF_HIZ");
420 : 0 : break;
421 : 0 : case AC_PINCTL_VREF_50:
422 : 0 : snd_iprintf(buffer, " VREF_50");
423 : 0 : break;
424 : 0 : case AC_PINCTL_VREF_GRD:
425 : 0 : snd_iprintf(buffer, " VREF_GRD");
426 : 0 : break;
427 : 0 : case AC_PINCTL_VREF_80:
428 : 0 : snd_iprintf(buffer, " VREF_80");
429 : 0 : break;
430 : 0 : case AC_PINCTL_VREF_100:
431 : 0 : snd_iprintf(buffer, " VREF_100");
432 : 0 : break;
433 : : }
434 : 0 : }
435 : 0 : snd_iprintf(buffer, "\n");
436 : 0 : }
437 : :
438 : 0 : static void print_vol_knob(struct snd_info_buffer *buffer,
439 : : struct hda_codec *codec, hda_nid_t nid)
440 : : {
441 : 0 : unsigned int cap = param_read(codec, nid, AC_PAR_VOL_KNB_CAP);
442 : 0 : snd_iprintf(buffer, " Volume-Knob: delta=%d, steps=%d, ",
443 : : (cap >> 7) & 1, cap & 0x7f);
444 : 0 : cap = snd_hda_codec_read(codec, nid, 0,
445 : : AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
446 : 0 : snd_iprintf(buffer, "direct=%d, val=%d\n",
447 : : (cap >> 7) & 1, cap & 0x7f);
448 : 0 : }
449 : :
450 : 0 : static void print_audio_io(struct snd_info_buffer *buffer,
451 : : struct hda_codec *codec, hda_nid_t nid,
452 : : unsigned int wid_type)
453 : : {
454 : 0 : int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
455 : 0 : snd_iprintf(buffer,
456 : : " Converter: stream=%d, channel=%d\n",
457 : : (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
458 : : conv & AC_CONV_CHANNEL);
459 : :
460 [ # # # # ]: 0 : if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
461 : 0 : int sdi = snd_hda_codec_read(codec, nid, 0,
462 : : AC_VERB_GET_SDI_SELECT, 0);
463 : 0 : snd_iprintf(buffer, " SDI-Select: %d\n",
464 : : sdi & AC_SDI_SELECT);
465 : : }
466 : 0 : }
467 : :
468 : 0 : static void print_digital_conv(struct snd_info_buffer *buffer,
469 : : struct hda_codec *codec, hda_nid_t nid)
470 : : {
471 : 0 : unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
472 : : AC_VERB_GET_DIGI_CONVERT_1, 0);
473 : 0 : unsigned char digi2 = digi1 >> 8;
474 : 0 : unsigned char digi3 = digi1 >> 16;
475 : :
476 : 0 : snd_iprintf(buffer, " Digital:");
477 [ # # ]: 0 : if (digi1 & AC_DIG1_ENABLE)
478 : 0 : snd_iprintf(buffer, " Enabled");
479 [ # # ]: 0 : if (digi1 & AC_DIG1_V)
480 : 0 : snd_iprintf(buffer, " Validity");
481 [ # # ]: 0 : if (digi1 & AC_DIG1_VCFG)
482 : 0 : snd_iprintf(buffer, " ValidityCfg");
483 [ # # ]: 0 : if (digi1 & AC_DIG1_EMPHASIS)
484 : 0 : snd_iprintf(buffer, " Preemphasis");
485 [ # # ]: 0 : if (digi1 & AC_DIG1_COPYRIGHT)
486 : 0 : snd_iprintf(buffer, " Non-Copyright");
487 [ # # ]: 0 : if (digi1 & AC_DIG1_NONAUDIO)
488 : 0 : snd_iprintf(buffer, " Non-Audio");
489 [ # # ]: 0 : if (digi1 & AC_DIG1_PROFESSIONAL)
490 : 0 : snd_iprintf(buffer, " Pro");
491 [ # # ]: 0 : if (digi1 & AC_DIG1_LEVEL)
492 : 0 : snd_iprintf(buffer, " GenLevel");
493 [ # # ]: 0 : if (digi3 & AC_DIG3_KAE)
494 : 0 : snd_iprintf(buffer, " KAE");
495 : 0 : snd_iprintf(buffer, "\n");
496 : 0 : snd_iprintf(buffer, " Digital category: 0x%x\n",
497 : : digi2 & AC_DIG2_CC);
498 : 0 : snd_iprintf(buffer, " IEC Coding Type: 0x%x\n",
499 : : digi3 & AC_DIG3_ICT);
500 : 0 : }
501 : :
502 : 0 : static const char *get_pwr_state(u32 state)
503 : : {
504 : 0 : static const char * const buf[] = {
505 : : "D0", "D1", "D2", "D3", "D3cold"
506 : : };
507 : 0 : if (state < ARRAY_SIZE(buf))
508 : 0 : return buf[state];
509 : : return "UNKNOWN";
510 : : }
511 : :
512 : 0 : static void print_power_state(struct snd_info_buffer *buffer,
513 : : struct hda_codec *codec, hda_nid_t nid)
514 : : {
515 : 0 : static const char * const names[] = {
516 : : [ilog2(AC_PWRST_D0SUP)] = "D0",
517 : : [ilog2(AC_PWRST_D1SUP)] = "D1",
518 : : [ilog2(AC_PWRST_D2SUP)] = "D2",
519 : : [ilog2(AC_PWRST_D3SUP)] = "D3",
520 : : [ilog2(AC_PWRST_D3COLDSUP)] = "D3cold",
521 : : [ilog2(AC_PWRST_S3D3COLDSUP)] = "S3D3cold",
522 : : [ilog2(AC_PWRST_CLKSTOP)] = "CLKSTOP",
523 : : [ilog2(AC_PWRST_EPSS)] = "EPSS",
524 : : };
525 : :
526 : 0 : int sup = param_read(codec, nid, AC_PAR_POWER_STATE);
527 : 0 : int pwr = snd_hda_codec_read(codec, nid, 0,
528 : : AC_VERB_GET_POWER_STATE, 0);
529 [ # # ]: 0 : if (sup != -1) {
530 : 0 : int i;
531 : :
532 : 0 : snd_iprintf(buffer, " Power states: ");
533 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(names); i++) {
534 [ # # ]: 0 : if (sup & (1U << i))
535 : 0 : snd_iprintf(buffer, " %s", names[i]);
536 : : }
537 : 0 : snd_iprintf(buffer, "\n");
538 : : }
539 : :
540 [ # # # # ]: 0 : snd_iprintf(buffer, " Power: setting=%s, actual=%s",
541 : : get_pwr_state(pwr & AC_PWRST_SETTING),
542 : : get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
543 : : AC_PWRST_ACTUAL_SHIFT));
544 [ # # ]: 0 : if (pwr & AC_PWRST_ERROR)
545 : 0 : snd_iprintf(buffer, ", Error");
546 [ # # ]: 0 : if (pwr & AC_PWRST_CLK_STOP_OK)
547 : 0 : snd_iprintf(buffer, ", Clock-stop-OK");
548 [ # # ]: 0 : if (pwr & AC_PWRST_SETTING_RESET)
549 : 0 : snd_iprintf(buffer, ", Setting-reset");
550 : 0 : snd_iprintf(buffer, "\n");
551 : 0 : }
552 : :
553 : 0 : static void print_unsol_cap(struct snd_info_buffer *buffer,
554 : : struct hda_codec *codec, hda_nid_t nid)
555 : : {
556 : 0 : int unsol = snd_hda_codec_read(codec, nid, 0,
557 : : AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
558 : 0 : snd_iprintf(buffer,
559 : : " Unsolicited: tag=%02x, enabled=%d\n",
560 : : unsol & AC_UNSOL_TAG,
561 : : (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
562 : 0 : }
563 : :
564 : 0 : static inline bool can_dump_coef(struct hda_codec *codec)
565 : : {
566 : 0 : switch (dump_coef) {
567 : : case 0: return false;
568 : : case 1: return true;
569 : 0 : default: return codec->dump_coef;
570 : : }
571 : : }
572 : :
573 : 0 : static void print_proc_caps(struct snd_info_buffer *buffer,
574 : : struct hda_codec *codec, hda_nid_t nid)
575 : : {
576 : 0 : unsigned int i, ncoeff, oldindex;
577 : 0 : unsigned int proc_caps = param_read(codec, nid, AC_PAR_PROC_CAP);
578 : 0 : ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
579 : 0 : snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n",
580 : : proc_caps & AC_PCAP_BENIGN, ncoeff);
581 : :
582 [ # # # # : 0 : if (!can_dump_coef(codec))
# ]
583 : : return;
584 : :
585 : : /* Note: This is racy - another process could run in parallel and change
586 : : the coef index too. */
587 : 0 : oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0);
588 [ # # ]: 0 : for (i = 0; i < ncoeff; i++) {
589 : 0 : unsigned int val;
590 : 0 : snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i);
591 : 0 : val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF,
592 : : 0);
593 : 0 : snd_iprintf(buffer, " Coeff 0x%02x: 0x%04x\n", i, val);
594 : : }
595 : 0 : snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex);
596 : : }
597 : :
598 : 0 : static void print_conn_list(struct snd_info_buffer *buffer,
599 : : struct hda_codec *codec, hda_nid_t nid,
600 : : unsigned int wid_type, hda_nid_t *conn,
601 : : int conn_len)
602 : : {
603 : 0 : int c, curr = -1;
604 : 0 : const hda_nid_t *list;
605 : 0 : int cache_len;
606 : :
607 : 0 : if (conn_len > 1 &&
608 [ # # ]: 0 : wid_type != AC_WID_AUD_MIX &&
609 [ # # ]: 0 : wid_type != AC_WID_VOL_KNB &&
610 : : wid_type != AC_WID_POWER)
611 : 0 : curr = snd_hda_codec_read(codec, nid, 0,
612 : : AC_VERB_GET_CONNECT_SEL, 0);
613 : 0 : snd_iprintf(buffer, " Connection: %d\n", conn_len);
614 [ # # ]: 0 : if (conn_len > 0) {
615 : 0 : snd_iprintf(buffer, " ");
616 [ # # ]: 0 : for (c = 0; c < conn_len; c++) {
617 : 0 : snd_iprintf(buffer, " 0x%02x", conn[c]);
618 [ # # ]: 0 : if (c == curr)
619 : 0 : snd_iprintf(buffer, "*");
620 : : }
621 : 0 : snd_iprintf(buffer, "\n");
622 : : }
623 : :
624 : : /* Get Cache connections info */
625 : 0 : cache_len = snd_hda_get_conn_list(codec, nid, &list);
626 [ # # # # ]: 0 : if (cache_len >= 0 && (cache_len != conn_len ||
627 [ # # ]: 0 : memcmp(list, conn, conn_len) != 0)) {
628 : 0 : snd_iprintf(buffer, " In-driver Connection: %d\n", cache_len);
629 [ # # ]: 0 : if (cache_len > 0) {
630 : 0 : snd_iprintf(buffer, " ");
631 [ # # ]: 0 : for (c = 0; c < cache_len; c++)
632 : 0 : snd_iprintf(buffer, " 0x%02x", list[c]);
633 : 0 : snd_iprintf(buffer, "\n");
634 : : }
635 : : }
636 : 0 : }
637 : :
638 : 0 : static void print_gpio(struct snd_info_buffer *buffer,
639 : : struct hda_codec *codec, hda_nid_t nid)
640 : : {
641 : 0 : unsigned int gpio =
642 : 0 : param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
643 : 0 : unsigned int enable, direction, wake, unsol, sticky, data;
644 : 0 : int i, max;
645 : 0 : snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
646 : : "unsolicited=%d, wake=%d\n",
647 : : gpio & AC_GPIO_IO_COUNT,
648 : : (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
649 : : (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
650 : : (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
651 : : (gpio & AC_GPIO_WAKE) ? 1 : 0);
652 : 0 : max = gpio & AC_GPIO_IO_COUNT;
653 [ # # ]: 0 : if (!max || max > 8)
654 : : return;
655 : 0 : enable = snd_hda_codec_read(codec, nid, 0,
656 : : AC_VERB_GET_GPIO_MASK, 0);
657 : 0 : direction = snd_hda_codec_read(codec, nid, 0,
658 : : AC_VERB_GET_GPIO_DIRECTION, 0);
659 : 0 : wake = snd_hda_codec_read(codec, nid, 0,
660 : : AC_VERB_GET_GPIO_WAKE_MASK, 0);
661 : 0 : unsol = snd_hda_codec_read(codec, nid, 0,
662 : : AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
663 : 0 : sticky = snd_hda_codec_read(codec, nid, 0,
664 : : AC_VERB_GET_GPIO_STICKY_MASK, 0);
665 : 0 : data = snd_hda_codec_read(codec, nid, 0,
666 : : AC_VERB_GET_GPIO_DATA, 0);
667 [ # # ]: 0 : for (i = 0; i < max; ++i)
668 : 0 : snd_iprintf(buffer,
669 : : " IO[%d]: enable=%d, dir=%d, wake=%d, "
670 : : "sticky=%d, data=%d, unsol=%d\n", i,
671 : : (enable & (1<<i)) ? 1 : 0,
672 : : (direction & (1<<i)) ? 1 : 0,
673 : : (wake & (1<<i)) ? 1 : 0,
674 : : (sticky & (1<<i)) ? 1 : 0,
675 : : (data & (1<<i)) ? 1 : 0,
676 : : (unsol & (1<<i)) ? 1 : 0);
677 : : /* FIXME: add GPO and GPI pin information */
678 : 0 : print_nid_array(buffer, codec, nid, &codec->mixers);
679 : 0 : print_nid_array(buffer, codec, nid, &codec->nids);
680 : : }
681 : :
682 : 0 : static void print_device_list(struct snd_info_buffer *buffer,
683 : : struct hda_codec *codec, hda_nid_t nid)
684 : : {
685 : 0 : int i, curr = -1;
686 : 0 : u8 dev_list[AC_MAX_DEV_LIST_LEN];
687 : 0 : int devlist_len;
688 : :
689 : 0 : devlist_len = snd_hda_get_devices(codec, nid, dev_list,
690 : : AC_MAX_DEV_LIST_LEN);
691 : 0 : snd_iprintf(buffer, " Devices: %d\n", devlist_len);
692 [ # # ]: 0 : if (devlist_len <= 0)
693 : 0 : return;
694 : :
695 : 0 : curr = snd_hda_codec_read(codec, nid, 0,
696 : : AC_VERB_GET_DEVICE_SEL, 0);
697 : :
698 [ # # ]: 0 : for (i = 0; i < devlist_len; i++) {
699 [ # # ]: 0 : if (i == curr)
700 : 0 : snd_iprintf(buffer, " *");
701 : : else
702 : 0 : snd_iprintf(buffer, " ");
703 : :
704 : 0 : snd_iprintf(buffer,
705 : : "Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i,
706 : : !!(dev_list[i] & AC_DE_PD),
707 : : !!(dev_list[i] & AC_DE_ELDV),
708 : : !!(dev_list[i] & AC_DE_IA));
709 : : }
710 : : }
711 : :
712 : : static void print_codec_core_info(struct hdac_device *codec,
713 : : struct snd_info_buffer *buffer)
714 : : {
715 : : snd_iprintf(buffer, "Codec: ");
716 : : if (codec->vendor_name && codec->chip_name)
717 : : snd_iprintf(buffer, "%s %s\n",
718 : : codec->vendor_name, codec->chip_name);
719 : : else
720 : : snd_iprintf(buffer, "Not Set\n");
721 : : snd_iprintf(buffer, "Address: %d\n", codec->addr);
722 : : if (codec->afg)
723 : : snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n",
724 : : codec->afg_function_id, codec->afg_unsol);
725 : : if (codec->mfg)
726 : : snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n",
727 : : codec->mfg_function_id, codec->mfg_unsol);
728 : : snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
729 : : snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
730 : : snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
731 : :
732 : : if (codec->mfg)
733 : : snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
734 : : else
735 : : snd_iprintf(buffer, "No Modem Function Group found\n");
736 : : }
737 : :
738 : 0 : static void print_codec_info(struct snd_info_entry *entry,
739 : : struct snd_info_buffer *buffer)
740 : : {
741 : 0 : struct hda_codec *codec = entry->private_data;
742 : 0 : hda_nid_t nid, fg;
743 : 0 : int i, nodes;
744 : :
745 : 0 : print_codec_core_info(&codec->core, buffer);
746 : 0 : fg = codec->core.afg;
747 [ # # ]: 0 : if (!fg)
748 : 0 : return;
749 : 0 : snd_hda_power_up(codec);
750 : 0 : snd_iprintf(buffer, "Default PCM:\n");
751 : 0 : print_pcm_caps(buffer, codec, fg);
752 : 0 : snd_iprintf(buffer, "Default Amp-In caps: ");
753 : 0 : print_amp_caps(buffer, codec, fg, HDA_INPUT);
754 : 0 : snd_iprintf(buffer, "Default Amp-Out caps: ");
755 : 0 : print_amp_caps(buffer, codec, fg, HDA_OUTPUT);
756 : 0 : snd_iprintf(buffer, "State of AFG node 0x%02x:\n", fg);
757 : 0 : print_power_state(buffer, codec, fg);
758 : :
759 : 0 : nodes = snd_hda_get_sub_nodes(codec, fg, &nid);
760 [ # # # # ]: 0 : if (! nid || nodes < 0) {
761 : 0 : snd_iprintf(buffer, "Invalid AFG subtree\n");
762 : 0 : snd_hda_power_down(codec);
763 : 0 : return;
764 : : }
765 : :
766 : 0 : print_gpio(buffer, codec, fg);
767 [ # # ]: 0 : if (codec->proc_widget_hook)
768 : 0 : codec->proc_widget_hook(buffer, codec, fg);
769 : :
770 [ # # ]: 0 : for (i = 0; i < nodes; i++, nid++) {
771 : 0 : unsigned int wid_caps =
772 : 0 : param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
773 [ # # ]: 0 : unsigned int wid_type = get_wcaps_type(wid_caps);
774 : 0 : hda_nid_t *conn = NULL;
775 : 0 : int conn_len = 0;
776 : :
777 [ # # ]: 0 : snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
778 : : get_wid_type_name(wid_type), wid_caps);
779 [ # # ]: 0 : if (wid_caps & AC_WCAP_STEREO) {
780 [ # # ]: 0 : unsigned int chans = get_wcaps_channels(wid_caps);
781 [ # # ]: 0 : if (chans == 2)
782 : 0 : snd_iprintf(buffer, " Stereo");
783 : : else
784 : 0 : snd_iprintf(buffer, " %d-Channels", chans);
785 : : } else
786 : 0 : snd_iprintf(buffer, " Mono");
787 [ # # ]: 0 : if (wid_caps & AC_WCAP_DIGITAL)
788 : 0 : snd_iprintf(buffer, " Digital");
789 [ # # ]: 0 : if (wid_caps & AC_WCAP_IN_AMP)
790 : 0 : snd_iprintf(buffer, " Amp-In");
791 [ # # ]: 0 : if (wid_caps & AC_WCAP_OUT_AMP)
792 : 0 : snd_iprintf(buffer, " Amp-Out");
793 [ # # ]: 0 : if (wid_caps & AC_WCAP_STRIPE)
794 : 0 : snd_iprintf(buffer, " Stripe");
795 [ # # ]: 0 : if (wid_caps & AC_WCAP_LR_SWAP)
796 : 0 : snd_iprintf(buffer, " R/L");
797 [ # # ]: 0 : if (wid_caps & AC_WCAP_CP_CAPS)
798 : 0 : snd_iprintf(buffer, " CP");
799 : 0 : snd_iprintf(buffer, "\n");
800 : :
801 : 0 : print_nid_array(buffer, codec, nid, &codec->mixers);
802 : 0 : print_nid_array(buffer, codec, nid, &codec->nids);
803 : 0 : print_nid_pcms(buffer, codec, nid);
804 : :
805 : : /* volume knob is a special widget that always have connection
806 : : * list
807 : : */
808 [ # # ]: 0 : if (wid_type == AC_WID_VOL_KNB)
809 : 0 : wid_caps |= AC_WCAP_CONN_LIST;
810 : :
811 [ # # ]: 0 : if (wid_caps & AC_WCAP_CONN_LIST) {
812 : 0 : conn_len = snd_hda_get_num_raw_conns(codec, nid);
813 [ # # ]: 0 : if (conn_len > 0) {
814 : 0 : conn = kmalloc_array(conn_len,
815 : : sizeof(hda_nid_t),
816 : : GFP_KERNEL);
817 [ # # ]: 0 : if (!conn)
818 : : return;
819 [ # # ]: 0 : if (snd_hda_get_raw_connections(codec, nid, conn,
820 : : conn_len) < 0)
821 : 0 : conn_len = 0;
822 : : }
823 : : }
824 : :
825 [ # # ]: 0 : if (wid_caps & AC_WCAP_IN_AMP) {
826 : 0 : snd_iprintf(buffer, " Amp-In caps: ");
827 : 0 : print_amp_caps(buffer, codec, nid, HDA_INPUT);
828 : 0 : snd_iprintf(buffer, " Amp-In vals: ");
829 [ # # ]: 0 : if (wid_type == AC_WID_PIN ||
830 [ # # # # ]: 0 : (codec->single_adc_amp &&
831 : : wid_type == AC_WID_AUD_IN))
832 : 0 : print_amp_vals(buffer, codec, nid, HDA_INPUT,
833 : : wid_caps, 1);
834 : : else
835 : 0 : print_amp_vals(buffer, codec, nid, HDA_INPUT,
836 : : wid_caps, conn_len);
837 : : }
838 [ # # ]: 0 : if (wid_caps & AC_WCAP_OUT_AMP) {
839 : 0 : snd_iprintf(buffer, " Amp-Out caps: ");
840 : 0 : print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
841 : 0 : snd_iprintf(buffer, " Amp-Out vals: ");
842 [ # # # # ]: 0 : if (wid_type == AC_WID_PIN &&
843 : : codec->pin_amp_workaround)
844 : 0 : print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
845 : : wid_caps, conn_len);
846 : : else
847 : 0 : print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
848 : : wid_caps, 1);
849 : : }
850 : :
851 [ # # # # ]: 0 : switch (wid_type) {
852 : 0 : case AC_WID_PIN: {
853 : 0 : int supports_vref;
854 : 0 : print_pin_caps(buffer, codec, nid, &supports_vref);
855 : 0 : print_pin_ctls(buffer, codec, nid, supports_vref);
856 : 0 : break;
857 : : }
858 : 0 : case AC_WID_VOL_KNB:
859 : 0 : print_vol_knob(buffer, codec, nid);
860 : 0 : break;
861 : 0 : case AC_WID_AUD_OUT:
862 : : case AC_WID_AUD_IN:
863 : 0 : print_audio_io(buffer, codec, nid, wid_type);
864 [ # # ]: 0 : if (wid_caps & AC_WCAP_DIGITAL)
865 : 0 : print_digital_conv(buffer, codec, nid);
866 [ # # ]: 0 : if (wid_caps & AC_WCAP_FORMAT_OVRD) {
867 : 0 : snd_iprintf(buffer, " PCM:\n");
868 : 0 : print_pcm_caps(buffer, codec, nid);
869 : : }
870 : : break;
871 : : }
872 : :
873 [ # # ]: 0 : if (wid_caps & AC_WCAP_UNSOL_CAP)
874 : 0 : print_unsol_cap(buffer, codec, nid);
875 : :
876 [ # # ]: 0 : if (wid_caps & AC_WCAP_POWER)
877 : 0 : print_power_state(buffer, codec, nid);
878 : :
879 [ # # ]: 0 : if (wid_caps & AC_WCAP_DELAY)
880 : 0 : snd_iprintf(buffer, " Delay: %d samples\n",
881 : : (wid_caps & AC_WCAP_DELAY) >>
882 : : AC_WCAP_DELAY_SHIFT);
883 : :
884 [ # # # # ]: 0 : if (wid_type == AC_WID_PIN && codec->dp_mst)
885 : 0 : print_device_list(buffer, codec, nid);
886 : :
887 [ # # ]: 0 : if (wid_caps & AC_WCAP_CONN_LIST)
888 : 0 : print_conn_list(buffer, codec, nid, wid_type,
889 : : conn, conn_len);
890 : :
891 [ # # ]: 0 : if (wid_caps & AC_WCAP_PROC_WID)
892 : 0 : print_proc_caps(buffer, codec, nid);
893 : :
894 [ # # ]: 0 : if (codec->proc_widget_hook)
895 : 0 : codec->proc_widget_hook(buffer, codec, nid);
896 : :
897 : 0 : kfree(conn);
898 : : }
899 : 0 : snd_hda_power_down(codec);
900 : : }
901 : :
902 : : /*
903 : : * create a proc read
904 : : */
905 : 0 : int snd_hda_codec_proc_new(struct hda_codec *codec)
906 : : {
907 : 0 : char name[32];
908 : :
909 : 0 : snprintf(name, sizeof(name), "codec#%d", codec->core.addr);
910 : 0 : return snd_card_ro_proc_new(codec->card, name, codec, print_codec_info);
911 : : }
912 : :
|