Linux Audio

Check our new training course

Open-source upstreaming

Need help get the support for your hardware in upstream Linux?
Loading...
Note: File does not exist in v3.5.6.
  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 sprintf(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 sprintf(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 sprintf(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 sprintf(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 += sprintf(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 = snd_hda_codec_configure(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 += scnprintf(buf + len, PAGE_SIZE - len,
226				"0x%02x 0x%03x 0x%04x\n",
227				v->nid, v->verb, v->param);
228	}
229	mutex_unlock(&codec->user_mutex);
230	return len;
231}
232
233static int parse_init_verbs(struct hda_codec *codec, const char *buf)
234{
235	struct hda_verb *v;
236	int nid, verb, param;
237
238	if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
239		return -EINVAL;
240	if (!nid || !verb)
241		return -EINVAL;
242	mutex_lock(&codec->user_mutex);
243	v = snd_array_new(&codec->init_verbs);
244	if (!v) {
245		mutex_unlock(&codec->user_mutex);
246		return -ENOMEM;
247	}
248	v->nid = nid;
249	v->verb = verb;
250	v->param = param;
251	mutex_unlock(&codec->user_mutex);
252	return 0;
253}
254
255static ssize_t init_verbs_store(struct device *dev,
256				struct device_attribute *attr,
257				const char *buf, size_t count)
258{
259	struct hda_codec *codec = dev_get_drvdata(dev);
260	int err = parse_init_verbs(codec, buf);
261	if (err < 0)
262		return err;
263	return count;
264}
265
266static ssize_t hints_show(struct device *dev,
267			  struct device_attribute *attr,
268			  char *buf)
269{
270	struct hda_codec *codec = dev_get_drvdata(dev);
271	const struct hda_hint *hint;
272	int i, len = 0;
273	mutex_lock(&codec->user_mutex);
274	snd_array_for_each(&codec->hints, i, hint) {
275		len += scnprintf(buf + len, PAGE_SIZE - len,
276				"%s = %s\n", hint->key, hint->val);
277	}
278	mutex_unlock(&codec->user_mutex);
279	return len;
280}
281
282static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
283{
284	struct hda_hint *hint;
285	int i;
286
287	snd_array_for_each(&codec->hints, i, hint) {
288		if (!strcmp(hint->key, key))
289			return hint;
290	}
291	return NULL;
292}
293
294static void remove_trail_spaces(char *str)
295{
296	char *p;
297	if (!*str)
298		return;
299	p = str + strlen(str) - 1;
300	for (; isspace(*p); p--) {
301		*p = 0;
302		if (p == str)
303			return;
304	}
305}
306
307#define MAX_HINTS	1024
308
309static int parse_hints(struct hda_codec *codec, const char *buf)
310{
311	char *key, *val;
312	struct hda_hint *hint;
313	int err = 0;
314
315	buf = skip_spaces(buf);
316	if (!*buf || *buf == '#' || *buf == '\n')
317		return 0;
318	if (*buf == '=')
319		return -EINVAL;
320	key = kstrndup_noeol(buf, 1024);
321	if (!key)
322		return -ENOMEM;
323	/* extract key and val */
324	val = strchr(key, '=');
325	if (!val) {
326		kfree(key);
327		return -EINVAL;
328	}
329	*val++ = 0;
330	val = skip_spaces(val);
331	remove_trail_spaces(key);
332	remove_trail_spaces(val);
333	mutex_lock(&codec->user_mutex);
334	hint = get_hint(codec, key);
335	if (hint) {
336		/* replace */
337		kfree(hint->key);
338		hint->key = key;
339		hint->val = val;
340		goto unlock;
341	}
342	/* allocate a new hint entry */
343	if (codec->hints.used >= MAX_HINTS)
344		hint = NULL;
345	else
346		hint = snd_array_new(&codec->hints);
347	if (hint) {
348		hint->key = key;
349		hint->val = val;
350	} else {
351		err = -ENOMEM;
352	}
353 unlock:
354	mutex_unlock(&codec->user_mutex);
355	if (err)
356		kfree(key);
357	return err;
358}
359
360static ssize_t hints_store(struct device *dev,
361			   struct device_attribute *attr,
362			   const char *buf, size_t count)
363{
364	struct hda_codec *codec = dev_get_drvdata(dev);
365	int err = parse_hints(codec, buf);
366	if (err < 0)
367		return err;
368	return count;
369}
370
371static ssize_t user_pin_configs_show(struct device *dev,
372				     struct device_attribute *attr,
373				     char *buf)
374{
375	struct hda_codec *codec = dev_get_drvdata(dev);
376	return pin_configs_show(codec, &codec->user_pins, buf);
377}
378
379#define MAX_PIN_CONFIGS		32
380
381static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
382{
383	int nid, cfg, err;
384
385	if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
386		return -EINVAL;
387	if (!nid)
388		return -EINVAL;
389	mutex_lock(&codec->user_mutex);
390	err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
391	mutex_unlock(&codec->user_mutex);
392	return err;
393}
394
395static ssize_t user_pin_configs_store(struct device *dev,
396				      struct device_attribute *attr,
397				      const char *buf, size_t count)
398{
399	struct hda_codec *codec = dev_get_drvdata(dev);
400	int err = parse_user_pin_configs(codec, buf);
401	if (err < 0)
402		return err;
403	return count;
404}
405
406/* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
407static DEVICE_ATTR_RW(init_verbs);
408static DEVICE_ATTR_RW(hints);
409static DEVICE_ATTR_RW(user_pin_configs);
410static DEVICE_ATTR_WO(reconfig);
411static DEVICE_ATTR_WO(clear);
412
413/**
414 * snd_hda_get_hint - Look for hint string
415 * @codec: the HDA codec
416 * @key: the hint key string
417 *
418 * Look for a hint key/value pair matching with the given key string
419 * and returns the value string.  If nothing found, returns NULL.
420 */
421const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
422{
423	struct hda_hint *hint = get_hint(codec, key);
424	return hint ? hint->val : NULL;
425}
426EXPORT_SYMBOL_GPL(snd_hda_get_hint);
427
428/**
429 * snd_hda_get_bool_hint - Get a boolean hint value
430 * @codec: the HDA codec
431 * @key: the hint key string
432 *
433 * Look for a hint key/value pair matching with the given key string
434 * and returns a boolean value parsed from the value.  If no matching
435 * key is found, return a negative value.
436 */
437int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
438{
439	const char *p;
440	int ret;
441
442	mutex_lock(&codec->user_mutex);
443	p = snd_hda_get_hint(codec, key);
444	if (!p || !*p)
445		ret = -ENOENT;
446	else {
447		switch (toupper(*p)) {
448		case 'T': /* true */
449		case 'Y': /* yes */
450		case '1':
451			ret = 1;
452			break;
453		default:
454			ret = 0;
455			break;
456		}
457	}
458	mutex_unlock(&codec->user_mutex);
459	return ret;
460}
461EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
462
463/**
464 * snd_hda_get_int_hint - Get an integer hint value
465 * @codec: the HDA codec
466 * @key: the hint key string
467 * @valp: pointer to store a value
468 *
469 * Look for a hint key/value pair matching with the given key string
470 * and stores the integer value to @valp.  If no matching key is found,
471 * return a negative error code.  Otherwise it returns zero.
472 */
473int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
474{
475	const char *p;
476	unsigned long val;
477	int ret;
478
479	mutex_lock(&codec->user_mutex);
480	p = snd_hda_get_hint(codec, key);
481	if (!p)
482		ret = -ENOENT;
483	else if (kstrtoul(p, 0, &val))
484		ret = -EINVAL;
485	else {
486		*valp = val;
487		ret = 0;
488	}
489	mutex_unlock(&codec->user_mutex);
490	return ret;
491}
492EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
493#endif /* CONFIG_SND_HDA_RECONFIG */
494
495/*
496 * common sysfs attributes
497 */
498#ifdef CONFIG_SND_HDA_RECONFIG
499#define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RW(name)
500#else
501#define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RO(name)
502#endif
503static RECONFIG_DEVICE_ATTR(vendor_id);
504static RECONFIG_DEVICE_ATTR(subsystem_id);
505static RECONFIG_DEVICE_ATTR(revision_id);
506static DEVICE_ATTR_RO(afg);
507static DEVICE_ATTR_RO(mfg);
508static RECONFIG_DEVICE_ATTR(vendor_name);
509static RECONFIG_DEVICE_ATTR(chip_name);
510static RECONFIG_DEVICE_ATTR(modelname);
511static DEVICE_ATTR_RO(init_pin_configs);
512static DEVICE_ATTR_RO(driver_pin_configs);
513
514
515#ifdef CONFIG_SND_HDA_PATCH_LOADER
516
517/* parser mode */
518enum {
519	LINE_MODE_NONE,
520	LINE_MODE_CODEC,
521	LINE_MODE_MODEL,
522	LINE_MODE_PINCFG,
523	LINE_MODE_VERB,
524	LINE_MODE_HINT,
525	LINE_MODE_VENDOR_ID,
526	LINE_MODE_SUBSYSTEM_ID,
527	LINE_MODE_REVISION_ID,
528	LINE_MODE_CHIP_NAME,
529	NUM_LINE_MODES,
530};
531
532static inline int strmatch(const char *a, const char *b)
533{
534	return strncasecmp(a, b, strlen(b)) == 0;
535}
536
537/* parse the contents after the line "[codec]"
538 * accept only the line with three numbers, and assign the current codec
539 */
540static void parse_codec_mode(char *buf, struct hda_bus *bus,
541			     struct hda_codec **codecp)
542{
543	int vendorid, subid, caddr;
544	struct hda_codec *codec;
545
546	*codecp = NULL;
547	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
548		list_for_each_codec(codec, bus) {
549			if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
550			    (subid <= 0 || codec->core.subsystem_id == subid) &&
551			    codec->core.addr == caddr) {
552				*codecp = codec;
553				break;
554			}
555		}
556	}
557}
558
559/* parse the contents after the other command tags, [pincfg], [verb],
560 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
561 * just pass to the sysfs helper (only when any codec was specified)
562 */
563static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
564			      struct hda_codec **codecp)
565{
566	parse_user_pin_configs(*codecp, buf);
567}
568
569static void parse_verb_mode(char *buf, struct hda_bus *bus,
570			    struct hda_codec **codecp)
571{
572	parse_init_verbs(*codecp, buf);
573}
574
575static void parse_hint_mode(char *buf, struct hda_bus *bus,
576			    struct hda_codec **codecp)
577{
578	parse_hints(*codecp, buf);
579}
580
581static void parse_model_mode(char *buf, struct hda_bus *bus,
582			     struct hda_codec **codecp)
583{
584	kfree((*codecp)->modelname);
585	(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
586}
587
588static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
589				 struct hda_codec **codecp)
590{
591	snd_hda_codec_set_name(*codecp, buf);
592}
593
594#define DEFINE_PARSE_ID_MODE(name) \
595static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
596				 struct hda_codec **codecp) \
597{ \
598	unsigned long val; \
599	if (!kstrtoul(buf, 0, &val)) \
600		(*codecp)->core.name = val; \
601}
602
603DEFINE_PARSE_ID_MODE(vendor_id);
604DEFINE_PARSE_ID_MODE(subsystem_id);
605DEFINE_PARSE_ID_MODE(revision_id);
606
607
608struct hda_patch_item {
609	const char *tag;
610	const char *alias;
611	void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
612};
613
614static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
615	[LINE_MODE_CODEC] = {
616		.tag = "[codec]",
617		.parser = parse_codec_mode,
618	},
619	[LINE_MODE_MODEL] = {
620		.tag = "[model]",
621		.parser = parse_model_mode,
622	},
623	[LINE_MODE_VERB] = {
624		.tag = "[verb]",
625		.alias = "[init_verbs]",
626		.parser = parse_verb_mode,
627	},
628	[LINE_MODE_PINCFG] = {
629		.tag = "[pincfg]",
630		.alias = "[user_pin_configs]",
631		.parser = parse_pincfg_mode,
632	},
633	[LINE_MODE_HINT] = {
634		.tag = "[hint]",
635		.alias = "[hints]",
636		.parser = parse_hint_mode
637	},
638	[LINE_MODE_VENDOR_ID] = {
639		.tag = "[vendor_id]",
640		.parser = parse_vendor_id_mode,
641	},
642	[LINE_MODE_SUBSYSTEM_ID] = {
643		.tag = "[subsystem_id]",
644		.parser = parse_subsystem_id_mode,
645	},
646	[LINE_MODE_REVISION_ID] = {
647		.tag = "[revision_id]",
648		.parser = parse_revision_id_mode,
649	},
650	[LINE_MODE_CHIP_NAME] = {
651		.tag = "[chip_name]",
652		.parser = parse_chip_name_mode,
653	},
654};
655
656/* check the line starting with '[' -- change the parser mode accodingly */
657static int parse_line_mode(char *buf, struct hda_bus *bus)
658{
659	int i;
660	for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
661		if (!patch_items[i].tag)
662			continue;
663		if (strmatch(buf, patch_items[i].tag))
664			return i;
665		if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
666			return i;
667	}
668	return LINE_MODE_NONE;
669}
670
671/* copy one line from the buffer in fw, and update the fields in fw
672 * return zero if it reaches to the end of the buffer, or non-zero
673 * if successfully copied a line
674 *
675 * the spaces at the beginning and the end of the line are stripped
676 */
677static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
678			    const void **fw_data_p)
679{
680	int len;
681	size_t fw_size = *fw_size_p;
682	const char *p = *fw_data_p;
683
684	while (isspace(*p) && fw_size) {
685		p++;
686		fw_size--;
687	}
688	if (!fw_size)
689		return 0;
690
691	for (len = 0; len < fw_size; len++) {
692		if (!*p)
693			break;
694		if (*p == '\n') {
695			p++;
696			len++;
697			break;
698		}
699		if (len < size)
700			*buf++ = *p++;
701	}
702	*buf = 0;
703	*fw_size_p = fw_size - len;
704	*fw_data_p = p;
705	remove_trail_spaces(buf);
706	return 1;
707}
708
709/**
710 * snd_hda_load_patch - load a "patch" firmware file and parse it
711 * @bus: HD-audio bus
712 * @fw_size: the firmware byte size
713 * @fw_buf: the firmware data
714 */
715int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
716{
717	char buf[128];
718	struct hda_codec *codec;
719	int line_mode;
720
721	line_mode = LINE_MODE_NONE;
722	codec = NULL;
723	while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
724		if (!*buf || *buf == '#' || *buf == '\n')
725			continue;
726		if (*buf == '[')
727			line_mode = parse_line_mode(buf, bus);
728		else if (patch_items[line_mode].parser &&
729			 (codec || line_mode <= LINE_MODE_CODEC))
730			patch_items[line_mode].parser(buf, bus, &codec);
731	}
732	return 0;
733}
734EXPORT_SYMBOL_GPL(snd_hda_load_patch);
735#endif /* CONFIG_SND_HDA_PATCH_LOADER */
736
737/*
738 * sysfs entries
739 */
740static struct attribute *hda_dev_attrs[] = {
741	&dev_attr_vendor_id.attr,
742	&dev_attr_subsystem_id.attr,
743	&dev_attr_revision_id.attr,
744	&dev_attr_afg.attr,
745	&dev_attr_mfg.attr,
746	&dev_attr_vendor_name.attr,
747	&dev_attr_chip_name.attr,
748	&dev_attr_modelname.attr,
749	&dev_attr_init_pin_configs.attr,
750	&dev_attr_driver_pin_configs.attr,
751#ifdef CONFIG_PM
752	&dev_attr_power_on_acct.attr,
753	&dev_attr_power_off_acct.attr,
754#endif
755#ifdef CONFIG_SND_HDA_RECONFIG
756	&dev_attr_init_verbs.attr,
757	&dev_attr_hints.attr,
758	&dev_attr_user_pin_configs.attr,
759	&dev_attr_reconfig.attr,
760	&dev_attr_clear.attr,
761#endif
762	NULL
763};
764
765static const struct attribute_group hda_dev_attr_group = {
766	.attrs	= hda_dev_attrs,
767};
768
769const struct attribute_group *snd_hda_dev_attr_groups[] = {
770	&hda_dev_attr_group,
771	NULL
772};
773
774void snd_hda_sysfs_init(struct hda_codec *codec)
775{
776	mutex_init(&codec->user_mutex);
777#ifdef CONFIG_SND_HDA_RECONFIG
778	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
779	snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
780	snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
781#endif
782}
783
784void snd_hda_sysfs_clear(struct hda_codec *codec)
785{
786#ifdef CONFIG_SND_HDA_RECONFIG
787	struct hda_hint *hint;
788	int i;
789
790	/* clear init verbs */
791	snd_array_free(&codec->init_verbs);
792	/* clear hints */
793	snd_array_for_each(&codec->hints, i, hint) {
794		kfree(hint->key); /* we don't need to free hint->val */
795	}
796	snd_array_free(&codec->hints);
797	snd_array_free(&codec->user_pins);
798#endif
799}