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