xref: /linux/sound/hda/common/sysfs.c (revision ca220141fa8ebae09765a242076b2b77338106b0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * sysfs interface for HD-audio codec
4  *
5  * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de>
6  *
7  * split from hda_hwdep.c
8  */
9 
10 #include <linux/init.h>
11 #include <linux/slab.h>
12 #include <linux/compat.h>
13 #include <linux/mutex.h>
14 #include <linux/ctype.h>
15 #include <linux/string.h>
16 #include <linux/export.h>
17 #include <sound/core.h>
18 #include <sound/hda_codec.h>
19 #include "hda_local.h"
20 #include <sound/hda_hwdep.h>
21 #include <sound/minors.h>
22 
23 /* hint string pair */
24 struct hda_hint {
25 	const char *key;
26 	const char *val;	/* contained in the same alloc as key */
27 };
28 
29 static ssize_t power_on_acct_show(struct device *dev,
30 				  struct device_attribute *attr,
31 				  char *buf)
32 {
33 	struct hda_codec *codec = dev_get_drvdata(dev);
34 	snd_hda_update_power_acct(codec);
35 	return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
36 }
37 
38 static ssize_t power_off_acct_show(struct device *dev,
39 				   struct device_attribute *attr,
40 				   char *buf)
41 {
42 	struct hda_codec *codec = dev_get_drvdata(dev);
43 	snd_hda_update_power_acct(codec);
44 	return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
45 }
46 
47 static DEVICE_ATTR_RO(power_on_acct);
48 static DEVICE_ATTR_RO(power_off_acct);
49 
50 #define CODEC_INFO_SHOW(type, field)				\
51 static ssize_t type##_show(struct device *dev,			\
52 			   struct device_attribute *attr,	\
53 			   char *buf)				\
54 {								\
55 	struct hda_codec *codec = dev_get_drvdata(dev);		\
56 	return sysfs_emit(buf, "0x%x\n", codec->field);		\
57 }
58 
59 #define CODEC_INFO_STR_SHOW(type, field)			\
60 static ssize_t type##_show(struct device *dev,			\
61 			     struct device_attribute *attr,	\
62 					char *buf)		\
63 {								\
64 	struct hda_codec *codec = dev_get_drvdata(dev);		\
65 	return sysfs_emit(buf, "%s\n",				\
66 			  codec->field ? codec->field : "");	\
67 }
68 
69 CODEC_INFO_SHOW(vendor_id, core.vendor_id);
70 CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
71 CODEC_INFO_SHOW(revision_id, core.revision_id);
72 CODEC_INFO_SHOW(afg, core.afg);
73 CODEC_INFO_SHOW(mfg, core.mfg);
74 CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
75 CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
76 CODEC_INFO_STR_SHOW(modelname, modelname);
77 
78 static ssize_t pin_configs_show(struct hda_codec *codec,
79 				struct snd_array *list,
80 				char *buf)
81 {
82 	const struct hda_pincfg *pin;
83 	int i, len = 0;
84 
85 	guard(mutex)(&codec->user_mutex);
86 	snd_array_for_each(list, i, pin) {
87 		len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n",
88 				     pin->nid, pin->cfg);
89 	}
90 	return len;
91 }
92 
93 static ssize_t init_pin_configs_show(struct device *dev,
94 				     struct device_attribute *attr,
95 				     char *buf)
96 {
97 	struct hda_codec *codec = dev_get_drvdata(dev);
98 	return pin_configs_show(codec, &codec->init_pins, buf);
99 }
100 
101 static ssize_t driver_pin_configs_show(struct device *dev,
102 				       struct device_attribute *attr,
103 				       char *buf)
104 {
105 	struct hda_codec *codec = dev_get_drvdata(dev);
106 	return pin_configs_show(codec, &codec->driver_pins, buf);
107 }
108 
109 #ifdef CONFIG_SND_HDA_RECONFIG
110 
111 /*
112  * sysfs interface
113  */
114 
115 static int clear_codec(struct hda_codec *codec)
116 {
117 	int err;
118 
119 	err = snd_hda_codec_reset(codec);
120 	if (err < 0) {
121 		codec_err(codec, "The codec is being used, can't free.\n");
122 		return err;
123 	}
124 	snd_hda_sysfs_clear(codec);
125 	return 0;
126 }
127 
128 static int reconfig_codec(struct hda_codec *codec)
129 {
130 	int err;
131 
132 	CLASS(snd_hda_power, pm)(codec);
133 	codec_info(codec, "hda-codec: reconfiguring\n");
134 	err = snd_hda_codec_reset(codec);
135 	if (err < 0) {
136 		codec_err(codec,
137 			   "The codec is being used, can't reconfigure.\n");
138 		return err;
139 	}
140 	err = device_reprobe(hda_codec_dev(codec));
141 	if (err < 0)
142 		return err;
143 	return snd_card_register(codec->card);
144 }
145 
146 /*
147  * allocate a string at most len chars, and remove the trailing EOL
148  */
149 static char *kstrndup_noeol(const char *src, size_t len)
150 {
151 	char *s = kstrndup(src, len, GFP_KERNEL);
152 	char *p;
153 	if (!s)
154 		return NULL;
155 	p = strchr(s, '\n');
156 	if (p)
157 		*p = 0;
158 	return s;
159 }
160 
161 #define CODEC_INFO_STORE(type, field)				\
162 static ssize_t type##_store(struct device *dev,			\
163 			    struct device_attribute *attr,	\
164 			    const char *buf, size_t count)	\
165 {								\
166 	struct hda_codec *codec = dev_get_drvdata(dev);		\
167 	unsigned long val;					\
168 	int err = kstrtoul(buf, 0, &val);			\
169 	if (err < 0)						\
170 		return err;					\
171 	codec->field = val;					\
172 	return count;						\
173 }
174 
175 #define CODEC_INFO_STR_STORE(type, field)			\
176 static ssize_t type##_store(struct device *dev,			\
177 			    struct device_attribute *attr,	\
178 			    const char *buf, size_t count)	\
179 {								\
180 	struct hda_codec *codec = dev_get_drvdata(dev);		\
181 	char *s = kstrndup_noeol(buf, 64);			\
182 	if (!s)							\
183 		return -ENOMEM;					\
184 	kfree(codec->field);					\
185 	codec->field = s;					\
186 	return count;						\
187 }
188 
189 CODEC_INFO_STORE(vendor_id, core.vendor_id);
190 CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
191 CODEC_INFO_STORE(revision_id, core.revision_id);
192 CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
193 CODEC_INFO_STR_STORE(chip_name, core.chip_name);
194 CODEC_INFO_STR_STORE(modelname, modelname);
195 
196 #define CODEC_ACTION_STORE(type)				\
197 static ssize_t type##_store(struct device *dev,			\
198 			    struct device_attribute *attr,	\
199 			    const char *buf, size_t count)	\
200 {								\
201 	struct hda_codec *codec = dev_get_drvdata(dev);		\
202 	int err = 0;						\
203 	if (*buf)						\
204 		err = type##_codec(codec);			\
205 	return err < 0 ? err : count;				\
206 }
207 
208 CODEC_ACTION_STORE(reconfig);
209 CODEC_ACTION_STORE(clear);
210 
211 static ssize_t init_verbs_show(struct device *dev,
212 			       struct device_attribute *attr,
213 			       char *buf)
214 {
215 	struct hda_codec *codec = dev_get_drvdata(dev);
216 	const struct hda_verb *v;
217 	int i, len = 0;
218 
219 	guard(mutex)(&codec->user_mutex);
220 	snd_array_for_each(&codec->init_verbs, i, v) {
221 		len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n",
222 				     v->nid, v->verb, v->param);
223 	}
224 	return len;
225 }
226 
227 static int parse_init_verbs(struct hda_codec *codec, const char *buf)
228 {
229 	struct hda_verb *v;
230 	int nid, verb, param;
231 
232 	if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
233 		return -EINVAL;
234 	if (!nid || !verb)
235 		return -EINVAL;
236 	guard(mutex)(&codec->user_mutex);
237 	v = snd_array_new(&codec->init_verbs);
238 	if (!v)
239 		return -ENOMEM;
240 	v->nid = nid;
241 	v->verb = verb;
242 	v->param = param;
243 	return 0;
244 }
245 
246 static ssize_t init_verbs_store(struct device *dev,
247 				struct device_attribute *attr,
248 				const char *buf, size_t count)
249 {
250 	struct hda_codec *codec = dev_get_drvdata(dev);
251 	int err = parse_init_verbs(codec, buf);
252 	if (err < 0)
253 		return err;
254 	return count;
255 }
256 
257 static ssize_t hints_show(struct device *dev,
258 			  struct device_attribute *attr,
259 			  char *buf)
260 {
261 	struct hda_codec *codec = dev_get_drvdata(dev);
262 	const struct hda_hint *hint;
263 	int i, len = 0;
264 
265 	guard(mutex)(&codec->user_mutex);
266 	snd_array_for_each(&codec->hints, i, hint) {
267 		len += sysfs_emit_at(buf, len, "%s = %s\n",
268 				     hint->key, hint->val);
269 	}
270 	return len;
271 }
272 
273 static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
274 {
275 	struct hda_hint *hint;
276 	int i;
277 
278 	snd_array_for_each(&codec->hints, i, hint) {
279 		if (!strcmp(hint->key, key))
280 			return hint;
281 	}
282 	return NULL;
283 }
284 
285 static void remove_trail_spaces(char *str)
286 {
287 	char *p;
288 	if (!*str)
289 		return;
290 	p = str + strlen(str) - 1;
291 	for (; isspace(*p); p--) {
292 		*p = 0;
293 		if (p == str)
294 			return;
295 	}
296 }
297 
298 #define MAX_HINTS	1024
299 
300 static int parse_hints(struct hda_codec *codec, const char *buf)
301 {
302 	char *val;
303 	struct hda_hint *hint;
304 
305 	buf = skip_spaces(buf);
306 	if (!*buf || *buf == '#' || *buf == '\n')
307 		return 0;
308 	if (*buf == '=')
309 		return -EINVAL;
310 
311 	char *key __free(kfree) =
312 		kstrndup_noeol(buf, 1024);
313 	if (!key)
314 		return -ENOMEM;
315 	/* extract key and val */
316 	val = strchr(key, '=');
317 	if (!val)
318 		return -EINVAL;
319 	*val++ = 0;
320 	val = skip_spaces(val);
321 	remove_trail_spaces(key);
322 	remove_trail_spaces(val);
323 	guard(mutex)(&codec->user_mutex);
324 	hint = get_hint(codec, key);
325 	if (hint) {
326 		/* replace */
327 		kfree(hint->key);
328 		goto replace;
329 	}
330 	/* allocate a new hint entry */
331 	if (codec->hints.used >= MAX_HINTS)
332 		return -ENOMEM;
333 	hint = snd_array_new(&codec->hints);
334 	if (!hint)
335 		return -ENOMEM;
336  replace:
337 	hint->key = no_free_ptr(key);
338 	hint->val = val;
339 	return 0;
340 }
341 
342 static ssize_t hints_store(struct device *dev,
343 			   struct device_attribute *attr,
344 			   const char *buf, size_t count)
345 {
346 	struct hda_codec *codec = dev_get_drvdata(dev);
347 	int err = parse_hints(codec, buf);
348 	if (err < 0)
349 		return err;
350 	return count;
351 }
352 
353 static ssize_t user_pin_configs_show(struct device *dev,
354 				     struct device_attribute *attr,
355 				     char *buf)
356 {
357 	struct hda_codec *codec = dev_get_drvdata(dev);
358 	return pin_configs_show(codec, &codec->user_pins, buf);
359 }
360 
361 static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
362 {
363 	int nid, cfg;
364 
365 	if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
366 		return -EINVAL;
367 	if (!nid)
368 		return -EINVAL;
369 	guard(mutex)(&codec->user_mutex);
370 	return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
371 }
372 
373 static ssize_t user_pin_configs_store(struct device *dev,
374 				      struct device_attribute *attr,
375 				      const char *buf, size_t count)
376 {
377 	struct hda_codec *codec = dev_get_drvdata(dev);
378 	int err = parse_user_pin_configs(codec, buf);
379 	if (err < 0)
380 		return err;
381 	return count;
382 }
383 
384 /* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
385 static DEVICE_ATTR_RW(init_verbs);
386 static DEVICE_ATTR_RW(hints);
387 static DEVICE_ATTR_RW(user_pin_configs);
388 static DEVICE_ATTR_WO(reconfig);
389 static DEVICE_ATTR_WO(clear);
390 
391 /**
392  * snd_hda_get_hint - Look for hint string
393  * @codec: the HDA codec
394  * @key: the hint key string
395  *
396  * Look for a hint key/value pair matching with the given key string
397  * and returns the value string.  If nothing found, returns NULL.
398  */
399 const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
400 {
401 	struct hda_hint *hint = get_hint(codec, key);
402 	return hint ? hint->val : NULL;
403 }
404 EXPORT_SYMBOL_GPL(snd_hda_get_hint);
405 
406 /**
407  * snd_hda_get_bool_hint - Get a boolean hint value
408  * @codec: the HDA codec
409  * @key: the hint key string
410  *
411  * Look for a hint key/value pair matching with the given key string
412  * and returns a boolean value parsed from the value.  If no matching
413  * key is found, return a negative value.
414  */
415 int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
416 {
417 	const char *p;
418 
419 	guard(mutex)(&codec->user_mutex);
420 	p = snd_hda_get_hint(codec, key);
421 	if (!p || !*p)
422 		return -ENOENT;
423 	switch (toupper(*p)) {
424 	case 'T': /* true */
425 	case 'Y': /* yes */
426 	case '1':
427 		return 1;
428 	default:
429 		return 0;
430 	}
431 }
432 EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
433 
434 /**
435  * snd_hda_get_int_hint - Get an integer hint value
436  * @codec: the HDA codec
437  * @key: the hint key string
438  * @valp: pointer to store a value
439  *
440  * Look for a hint key/value pair matching with the given key string
441  * and stores the integer value to @valp.  If no matching key is found,
442  * return a negative error code.  Otherwise it returns zero.
443  */
444 int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
445 {
446 	const char *p;
447 	unsigned long val;
448 
449 	guard(mutex)(&codec->user_mutex);
450 	p = snd_hda_get_hint(codec, key);
451 	if (!p)
452 		return -ENOENT;
453 	else if (kstrtoul(p, 0, &val))
454 		return -EINVAL;
455 	else {
456 		*valp = val;
457 		return 0;
458 	}
459 }
460 EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
461 #endif /* CONFIG_SND_HDA_RECONFIG */
462 
463 /*
464  * common sysfs attributes
465  */
466 #ifdef CONFIG_SND_HDA_RECONFIG
467 #define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RW(name)
468 #else
469 #define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RO(name)
470 #endif
471 static RECONFIG_DEVICE_ATTR(vendor_id);
472 static RECONFIG_DEVICE_ATTR(subsystem_id);
473 static RECONFIG_DEVICE_ATTR(revision_id);
474 static DEVICE_ATTR_RO(afg);
475 static DEVICE_ATTR_RO(mfg);
476 static RECONFIG_DEVICE_ATTR(vendor_name);
477 static RECONFIG_DEVICE_ATTR(chip_name);
478 static RECONFIG_DEVICE_ATTR(modelname);
479 static DEVICE_ATTR_RO(init_pin_configs);
480 static DEVICE_ATTR_RO(driver_pin_configs);
481 
482 
483 #ifdef CONFIG_SND_HDA_PATCH_LOADER
484 
485 /* parser mode */
486 enum {
487 	LINE_MODE_NONE,
488 	LINE_MODE_CODEC,
489 	LINE_MODE_MODEL,
490 	LINE_MODE_PINCFG,
491 	LINE_MODE_VERB,
492 	LINE_MODE_HINT,
493 	LINE_MODE_VENDOR_ID,
494 	LINE_MODE_SUBSYSTEM_ID,
495 	LINE_MODE_REVISION_ID,
496 	LINE_MODE_CHIP_NAME,
497 	NUM_LINE_MODES,
498 };
499 
500 static inline int strmatch(const char *a, const char *b)
501 {
502 	return strncasecmp(a, b, strlen(b)) == 0;
503 }
504 
505 /* parse the contents after the line "[codec]"
506  * accept only the line with three numbers, and assign the current codec
507  */
508 static void parse_codec_mode(char *buf, struct hda_bus *bus,
509 			     struct hda_codec **codecp)
510 {
511 	int vendorid, subid, caddr;
512 	struct hda_codec *codec;
513 
514 	*codecp = NULL;
515 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
516 		list_for_each_codec(codec, bus) {
517 			if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
518 			    (subid <= 0 || codec->core.subsystem_id == subid) &&
519 			    codec->core.addr == caddr) {
520 				*codecp = codec;
521 				break;
522 			}
523 		}
524 	}
525 }
526 
527 /* parse the contents after the other command tags, [pincfg], [verb],
528  * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
529  * just pass to the sysfs helper (only when any codec was specified)
530  */
531 static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
532 			      struct hda_codec **codecp)
533 {
534 	parse_user_pin_configs(*codecp, buf);
535 }
536 
537 static void parse_verb_mode(char *buf, struct hda_bus *bus,
538 			    struct hda_codec **codecp)
539 {
540 	parse_init_verbs(*codecp, buf);
541 }
542 
543 static void parse_hint_mode(char *buf, struct hda_bus *bus,
544 			    struct hda_codec **codecp)
545 {
546 	parse_hints(*codecp, buf);
547 }
548 
549 static void parse_model_mode(char *buf, struct hda_bus *bus,
550 			     struct hda_codec **codecp)
551 {
552 	kfree((*codecp)->modelname);
553 	(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
554 }
555 
556 static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
557 				 struct hda_codec **codecp)
558 {
559 	snd_hda_codec_set_name(*codecp, buf);
560 }
561 
562 #define DEFINE_PARSE_ID_MODE(name) \
563 static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
564 				 struct hda_codec **codecp) \
565 { \
566 	unsigned long val; \
567 	if (!kstrtoul(buf, 0, &val)) \
568 		(*codecp)->core.name = val; \
569 }
570 
571 DEFINE_PARSE_ID_MODE(vendor_id);
572 DEFINE_PARSE_ID_MODE(subsystem_id);
573 DEFINE_PARSE_ID_MODE(revision_id);
574 
575 
576 struct hda_patch_item {
577 	const char *tag;
578 	const char *alias;
579 	void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
580 };
581 
582 static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
583 	[LINE_MODE_CODEC] = {
584 		.tag = "[codec]",
585 		.parser = parse_codec_mode,
586 	},
587 	[LINE_MODE_MODEL] = {
588 		.tag = "[model]",
589 		.parser = parse_model_mode,
590 	},
591 	[LINE_MODE_VERB] = {
592 		.tag = "[verb]",
593 		.alias = "[init_verbs]",
594 		.parser = parse_verb_mode,
595 	},
596 	[LINE_MODE_PINCFG] = {
597 		.tag = "[pincfg]",
598 		.alias = "[user_pin_configs]",
599 		.parser = parse_pincfg_mode,
600 	},
601 	[LINE_MODE_HINT] = {
602 		.tag = "[hint]",
603 		.alias = "[hints]",
604 		.parser = parse_hint_mode
605 	},
606 	[LINE_MODE_VENDOR_ID] = {
607 		.tag = "[vendor_id]",
608 		.parser = parse_vendor_id_mode,
609 	},
610 	[LINE_MODE_SUBSYSTEM_ID] = {
611 		.tag = "[subsystem_id]",
612 		.parser = parse_subsystem_id_mode,
613 	},
614 	[LINE_MODE_REVISION_ID] = {
615 		.tag = "[revision_id]",
616 		.parser = parse_revision_id_mode,
617 	},
618 	[LINE_MODE_CHIP_NAME] = {
619 		.tag = "[chip_name]",
620 		.parser = parse_chip_name_mode,
621 	},
622 };
623 
624 /* check the line starting with '[' -- change the parser mode accordingly */
625 static int parse_line_mode(char *buf, struct hda_bus *bus)
626 {
627 	int i;
628 	for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
629 		if (!patch_items[i].tag)
630 			continue;
631 		if (strmatch(buf, patch_items[i].tag))
632 			return i;
633 		if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
634 			return i;
635 	}
636 	return LINE_MODE_NONE;
637 }
638 
639 /* copy one line from the buffer in fw, and update the fields in fw
640  * return zero if it reaches to the end of the buffer, or non-zero
641  * if successfully copied a line
642  *
643  * the spaces at the beginning and the end of the line are stripped
644  */
645 static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
646 			    const void **fw_data_p)
647 {
648 	int len;
649 	size_t fw_size = *fw_size_p;
650 	const char *p = *fw_data_p;
651 
652 	while (isspace(*p) && fw_size) {
653 		p++;
654 		fw_size--;
655 	}
656 	if (!fw_size)
657 		return 0;
658 
659 	for (len = 0; len < fw_size; len++) {
660 		if (!*p)
661 			break;
662 		if (*p == '\n') {
663 			p++;
664 			len++;
665 			break;
666 		}
667 		if (len < size)
668 			*buf++ = *p++;
669 	}
670 	*buf = 0;
671 	*fw_size_p = fw_size - len;
672 	*fw_data_p = p;
673 	remove_trail_spaces(buf);
674 	return 1;
675 }
676 
677 /**
678  * snd_hda_load_patch - load a "patch" firmware file and parse it
679  * @bus: HD-audio bus
680  * @fw_size: the firmware byte size
681  * @fw_buf: the firmware data
682  */
683 int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
684 {
685 	char buf[128];
686 	struct hda_codec *codec;
687 	int line_mode;
688 
689 	line_mode = LINE_MODE_NONE;
690 	codec = NULL;
691 	while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
692 		if (!*buf || *buf == '#' || *buf == '\n')
693 			continue;
694 		if (*buf == '[')
695 			line_mode = parse_line_mode(buf, bus);
696 		else if (patch_items[line_mode].parser &&
697 			 (codec || line_mode <= LINE_MODE_CODEC))
698 			patch_items[line_mode].parser(buf, bus, &codec);
699 	}
700 	return 0;
701 }
702 EXPORT_SYMBOL_GPL(snd_hda_load_patch);
703 #endif /* CONFIG_SND_HDA_PATCH_LOADER */
704 
705 /*
706  * sysfs entries
707  */
708 static struct attribute *hda_dev_attrs[] = {
709 	&dev_attr_vendor_id.attr,
710 	&dev_attr_subsystem_id.attr,
711 	&dev_attr_revision_id.attr,
712 	&dev_attr_afg.attr,
713 	&dev_attr_mfg.attr,
714 	&dev_attr_vendor_name.attr,
715 	&dev_attr_chip_name.attr,
716 	&dev_attr_modelname.attr,
717 	&dev_attr_init_pin_configs.attr,
718 	&dev_attr_driver_pin_configs.attr,
719 	&dev_attr_power_on_acct.attr,
720 	&dev_attr_power_off_acct.attr,
721 #ifdef CONFIG_SND_HDA_RECONFIG
722 	&dev_attr_init_verbs.attr,
723 	&dev_attr_hints.attr,
724 	&dev_attr_user_pin_configs.attr,
725 	&dev_attr_reconfig.attr,
726 	&dev_attr_clear.attr,
727 #endif
728 	NULL
729 };
730 
731 static const struct attribute_group hda_dev_attr_group = {
732 	.attrs	= hda_dev_attrs,
733 };
734 
735 const struct attribute_group *snd_hda_dev_attr_groups[] = {
736 	&hda_dev_attr_group,
737 	NULL
738 };
739 
740 void snd_hda_sysfs_init(struct hda_codec *codec)
741 {
742 	mutex_init(&codec->user_mutex);
743 #ifdef CONFIG_SND_HDA_RECONFIG
744 	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
745 	snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
746 	snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
747 #endif
748 }
749 
750 void snd_hda_sysfs_clear(struct hda_codec *codec)
751 {
752 #ifdef CONFIG_SND_HDA_RECONFIG
753 	struct hda_hint *hint;
754 	int i;
755 
756 	/* clear init verbs */
757 	snd_array_free(&codec->init_verbs);
758 	/* clear hints */
759 	snd_array_for_each(&codec->hints, i, hint) {
760 		kfree(hint->key); /* we don't need to free hint->val */
761 	}
762 	snd_array_free(&codec->hints);
763 	snd_array_free(&codec->user_pins);
764 #endif
765 }
766