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