xref: /openbmc/linux/sound/pci/hda/hda_sysfs.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2648a8d27STakashi Iwai /*
3648a8d27STakashi Iwai  * sysfs interface for HD-audio codec
4648a8d27STakashi Iwai  *
5648a8d27STakashi Iwai  * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de>
6648a8d27STakashi Iwai  *
7648a8d27STakashi Iwai  * split from hda_hwdep.c
8648a8d27STakashi Iwai  */
9648a8d27STakashi Iwai 
10648a8d27STakashi Iwai #include <linux/init.h>
11648a8d27STakashi Iwai #include <linux/slab.h>
12648a8d27STakashi Iwai #include <linux/compat.h>
13648a8d27STakashi Iwai #include <linux/mutex.h>
14648a8d27STakashi Iwai #include <linux/ctype.h>
15648a8d27STakashi Iwai #include <linux/string.h>
16648a8d27STakashi Iwai #include <linux/export.h>
17648a8d27STakashi Iwai #include <sound/core.h>
18be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h>
19648a8d27STakashi Iwai #include "hda_local.h"
20648a8d27STakashi Iwai #include <sound/hda_hwdep.h>
21648a8d27STakashi Iwai #include <sound/minors.h>
22648a8d27STakashi Iwai 
23648a8d27STakashi Iwai /* hint string pair */
24648a8d27STakashi Iwai struct hda_hint {
25648a8d27STakashi Iwai 	const char *key;
26648a8d27STakashi Iwai 	const char *val;	/* contained in the same alloc as key */
27648a8d27STakashi Iwai };
28648a8d27STakashi Iwai 
29648a8d27STakashi Iwai #ifdef CONFIG_PM
power_on_acct_show(struct device * dev,struct device_attribute * attr,char * buf)30648a8d27STakashi Iwai static ssize_t power_on_acct_show(struct device *dev,
31648a8d27STakashi Iwai 				  struct device_attribute *attr,
32648a8d27STakashi Iwai 				  char *buf)
33648a8d27STakashi Iwai {
34648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
35648a8d27STakashi Iwai 	snd_hda_update_power_acct(codec);
36*17daae7aSTakashi Iwai 	return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
37648a8d27STakashi Iwai }
38648a8d27STakashi Iwai 
power_off_acct_show(struct device * dev,struct device_attribute * attr,char * buf)39648a8d27STakashi Iwai static ssize_t power_off_acct_show(struct device *dev,
40648a8d27STakashi Iwai 				   struct device_attribute *attr,
41648a8d27STakashi Iwai 				   char *buf)
42648a8d27STakashi Iwai {
43648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
44648a8d27STakashi Iwai 	snd_hda_update_power_acct(codec);
45*17daae7aSTakashi Iwai 	return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
46648a8d27STakashi Iwai }
47648a8d27STakashi Iwai 
48648a8d27STakashi Iwai static DEVICE_ATTR_RO(power_on_acct);
49648a8d27STakashi Iwai static DEVICE_ATTR_RO(power_off_acct);
50648a8d27STakashi Iwai #endif /* CONFIG_PM */
51648a8d27STakashi Iwai 
527639a06cSTakashi Iwai #define CODEC_INFO_SHOW(type, field)				\
53b989d044STakashi Iwai static ssize_t type##_show(struct device *dev,			\
54b989d044STakashi Iwai 			   struct device_attribute *attr,	\
55b989d044STakashi Iwai 			   char *buf)				\
56b989d044STakashi Iwai {								\
57b989d044STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);		\
58*17daae7aSTakashi Iwai 	return sysfs_emit(buf, "0x%x\n", codec->field);		\
59b989d044STakashi Iwai }
60b989d044STakashi Iwai 
617639a06cSTakashi Iwai #define CODEC_INFO_STR_SHOW(type, field)			\
62b989d044STakashi Iwai static ssize_t type##_show(struct device *dev,			\
63b989d044STakashi Iwai 			     struct device_attribute *attr,	\
64b989d044STakashi Iwai 					char *buf)		\
65b989d044STakashi Iwai {								\
66b989d044STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);		\
67*17daae7aSTakashi Iwai 	return sysfs_emit(buf, "%s\n",				\
687639a06cSTakashi Iwai 			  codec->field ? codec->field : "");	\
69b989d044STakashi Iwai }
70b989d044STakashi Iwai 
717639a06cSTakashi Iwai CODEC_INFO_SHOW(vendor_id, core.vendor_id);
727639a06cSTakashi Iwai CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
737639a06cSTakashi Iwai CODEC_INFO_SHOW(revision_id, core.revision_id);
747639a06cSTakashi Iwai CODEC_INFO_SHOW(afg, core.afg);
757639a06cSTakashi Iwai CODEC_INFO_SHOW(mfg, core.mfg);
767639a06cSTakashi Iwai CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
777639a06cSTakashi Iwai CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
787639a06cSTakashi Iwai CODEC_INFO_STR_SHOW(modelname, modelname);
79b989d044STakashi Iwai 
pin_configs_show(struct hda_codec * codec,struct snd_array * list,char * buf)80b989d044STakashi Iwai static ssize_t pin_configs_show(struct hda_codec *codec,
81b989d044STakashi Iwai 				struct snd_array *list,
82b989d044STakashi Iwai 				char *buf)
83b989d044STakashi Iwai {
84a9c2dfc8STakashi Iwai 	const struct hda_pincfg *pin;
85b989d044STakashi Iwai 	int i, len = 0;
86b989d044STakashi Iwai 	mutex_lock(&codec->user_mutex);
87a9c2dfc8STakashi Iwai 	snd_array_for_each(list, i, pin) {
88*17daae7aSTakashi Iwai 		len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n",
89b989d044STakashi Iwai 				     pin->nid, pin->cfg);
90b989d044STakashi Iwai 	}
91b989d044STakashi Iwai 	mutex_unlock(&codec->user_mutex);
92b989d044STakashi Iwai 	return len;
93b989d044STakashi Iwai }
94b989d044STakashi Iwai 
init_pin_configs_show(struct device * dev,struct device_attribute * attr,char * buf)95b989d044STakashi Iwai static ssize_t init_pin_configs_show(struct device *dev,
96b989d044STakashi Iwai 				     struct device_attribute *attr,
97b989d044STakashi Iwai 				     char *buf)
98b989d044STakashi Iwai {
99b989d044STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
100b989d044STakashi Iwai 	return pin_configs_show(codec, &codec->init_pins, buf);
101b989d044STakashi Iwai }
102b989d044STakashi Iwai 
driver_pin_configs_show(struct device * dev,struct device_attribute * attr,char * buf)103b989d044STakashi Iwai static ssize_t driver_pin_configs_show(struct device *dev,
104b989d044STakashi Iwai 				       struct device_attribute *attr,
105b989d044STakashi Iwai 				       char *buf)
106b989d044STakashi Iwai {
107b989d044STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
108b989d044STakashi Iwai 	return pin_configs_show(codec, &codec->driver_pins, buf);
109b989d044STakashi Iwai }
110b989d044STakashi Iwai 
111648a8d27STakashi Iwai #ifdef CONFIG_SND_HDA_RECONFIG
112648a8d27STakashi Iwai 
113648a8d27STakashi Iwai /*
114648a8d27STakashi Iwai  * sysfs interface
115648a8d27STakashi Iwai  */
116648a8d27STakashi Iwai 
clear_codec(struct hda_codec * codec)117648a8d27STakashi Iwai static int clear_codec(struct hda_codec *codec)
118648a8d27STakashi Iwai {
119648a8d27STakashi Iwai 	int err;
120648a8d27STakashi Iwai 
121648a8d27STakashi Iwai 	err = snd_hda_codec_reset(codec);
122648a8d27STakashi Iwai 	if (err < 0) {
1234e76a883STakashi Iwai 		codec_err(codec, "The codec is being used, can't free.\n");
124648a8d27STakashi Iwai 		return err;
125648a8d27STakashi Iwai 	}
126648a8d27STakashi Iwai 	snd_hda_sysfs_clear(codec);
127648a8d27STakashi Iwai 	return 0;
128648a8d27STakashi Iwai }
129648a8d27STakashi Iwai 
reconfig_codec(struct hda_codec * codec)130648a8d27STakashi Iwai static int reconfig_codec(struct hda_codec *codec)
131648a8d27STakashi Iwai {
132648a8d27STakashi Iwai 	int err;
133648a8d27STakashi Iwai 
134648a8d27STakashi Iwai 	snd_hda_power_up(codec);
1354e76a883STakashi Iwai 	codec_info(codec, "hda-codec: reconfiguring\n");
136648a8d27STakashi Iwai 	err = snd_hda_codec_reset(codec);
137648a8d27STakashi Iwai 	if (err < 0) {
1384e76a883STakashi Iwai 		codec_err(codec,
139648a8d27STakashi Iwai 			   "The codec is being used, can't reconfigure.\n");
140648a8d27STakashi Iwai 		goto error;
141648a8d27STakashi Iwai 	}
1422506318eSTakashi Iwai 	err = device_reprobe(hda_codec_dev(codec));
143648a8d27STakashi Iwai 	if (err < 0)
144648a8d27STakashi Iwai 		goto error;
1456efdd851STakashi Iwai 	err = snd_card_register(codec->card);
146648a8d27STakashi Iwai  error:
147648a8d27STakashi Iwai 	snd_hda_power_down(codec);
148648a8d27STakashi Iwai 	return err;
149648a8d27STakashi Iwai }
150648a8d27STakashi Iwai 
151648a8d27STakashi Iwai /*
152648a8d27STakashi Iwai  * allocate a string at most len chars, and remove the trailing EOL
153648a8d27STakashi Iwai  */
kstrndup_noeol(const char * src,size_t len)154648a8d27STakashi Iwai static char *kstrndup_noeol(const char *src, size_t len)
155648a8d27STakashi Iwai {
156648a8d27STakashi Iwai 	char *s = kstrndup(src, len, GFP_KERNEL);
157648a8d27STakashi Iwai 	char *p;
158648a8d27STakashi Iwai 	if (!s)
159648a8d27STakashi Iwai 		return NULL;
160648a8d27STakashi Iwai 	p = strchr(s, '\n');
161648a8d27STakashi Iwai 	if (p)
162648a8d27STakashi Iwai 		*p = 0;
163648a8d27STakashi Iwai 	return s;
164648a8d27STakashi Iwai }
165648a8d27STakashi Iwai 
1667639a06cSTakashi Iwai #define CODEC_INFO_STORE(type, field)				\
167648a8d27STakashi Iwai static ssize_t type##_store(struct device *dev,			\
168648a8d27STakashi Iwai 			    struct device_attribute *attr,	\
169648a8d27STakashi Iwai 			    const char *buf, size_t count)	\
170648a8d27STakashi Iwai {								\
171648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);		\
172648a8d27STakashi Iwai 	unsigned long val;					\
173648a8d27STakashi Iwai 	int err = kstrtoul(buf, 0, &val);			\
174648a8d27STakashi Iwai 	if (err < 0)						\
175648a8d27STakashi Iwai 		return err;					\
1767639a06cSTakashi Iwai 	codec->field = val;					\
177648a8d27STakashi Iwai 	return count;						\
178648a8d27STakashi Iwai }
179648a8d27STakashi Iwai 
1807639a06cSTakashi Iwai #define CODEC_INFO_STR_STORE(type, field)			\
181648a8d27STakashi Iwai static ssize_t type##_store(struct device *dev,			\
182648a8d27STakashi Iwai 			    struct device_attribute *attr,	\
183648a8d27STakashi Iwai 			    const char *buf, size_t count)	\
184648a8d27STakashi Iwai {								\
185648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);		\
186648a8d27STakashi Iwai 	char *s = kstrndup_noeol(buf, 64);			\
187648a8d27STakashi Iwai 	if (!s)							\
188648a8d27STakashi Iwai 		return -ENOMEM;					\
1897639a06cSTakashi Iwai 	kfree(codec->field);					\
1907639a06cSTakashi Iwai 	codec->field = s;					\
191648a8d27STakashi Iwai 	return count;						\
192648a8d27STakashi Iwai }
193648a8d27STakashi Iwai 
1947639a06cSTakashi Iwai CODEC_INFO_STORE(vendor_id, core.vendor_id);
1957639a06cSTakashi Iwai CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
1967639a06cSTakashi Iwai CODEC_INFO_STORE(revision_id, core.revision_id);
1977639a06cSTakashi Iwai CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
1987639a06cSTakashi Iwai CODEC_INFO_STR_STORE(chip_name, core.chip_name);
1997639a06cSTakashi Iwai CODEC_INFO_STR_STORE(modelname, modelname);
200648a8d27STakashi Iwai 
201648a8d27STakashi Iwai #define CODEC_ACTION_STORE(type)				\
202648a8d27STakashi Iwai static ssize_t type##_store(struct device *dev,			\
203648a8d27STakashi Iwai 			    struct device_attribute *attr,	\
204648a8d27STakashi Iwai 			    const char *buf, size_t count)	\
205648a8d27STakashi Iwai {								\
206648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);		\
207648a8d27STakashi Iwai 	int err = 0;						\
208648a8d27STakashi Iwai 	if (*buf)						\
209648a8d27STakashi Iwai 		err = type##_codec(codec);			\
210648a8d27STakashi Iwai 	return err < 0 ? err : count;				\
211648a8d27STakashi Iwai }
212648a8d27STakashi Iwai 
213648a8d27STakashi Iwai CODEC_ACTION_STORE(reconfig);
214648a8d27STakashi Iwai CODEC_ACTION_STORE(clear);
215648a8d27STakashi Iwai 
init_verbs_show(struct device * dev,struct device_attribute * attr,char * buf)216648a8d27STakashi Iwai static ssize_t init_verbs_show(struct device *dev,
217648a8d27STakashi Iwai 			       struct device_attribute *attr,
218648a8d27STakashi Iwai 			       char *buf)
219648a8d27STakashi Iwai {
220648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
221a9c2dfc8STakashi Iwai 	const struct hda_verb *v;
222648a8d27STakashi Iwai 	int i, len = 0;
223648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
224a9c2dfc8STakashi Iwai 	snd_array_for_each(&codec->init_verbs, i, v) {
225*17daae7aSTakashi Iwai 		len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n",
226648a8d27STakashi Iwai 				     v->nid, v->verb, v->param);
227648a8d27STakashi Iwai 	}
228648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
229648a8d27STakashi Iwai 	return len;
230648a8d27STakashi Iwai }
231648a8d27STakashi Iwai 
parse_init_verbs(struct hda_codec * codec,const char * buf)232648a8d27STakashi Iwai static int parse_init_verbs(struct hda_codec *codec, const char *buf)
233648a8d27STakashi Iwai {
234648a8d27STakashi Iwai 	struct hda_verb *v;
235648a8d27STakashi Iwai 	int nid, verb, param;
236648a8d27STakashi Iwai 
237648a8d27STakashi Iwai 	if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
238648a8d27STakashi Iwai 		return -EINVAL;
239648a8d27STakashi Iwai 	if (!nid || !verb)
240648a8d27STakashi Iwai 		return -EINVAL;
241648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
242648a8d27STakashi Iwai 	v = snd_array_new(&codec->init_verbs);
243648a8d27STakashi Iwai 	if (!v) {
244648a8d27STakashi Iwai 		mutex_unlock(&codec->user_mutex);
245648a8d27STakashi Iwai 		return -ENOMEM;
246648a8d27STakashi Iwai 	}
247648a8d27STakashi Iwai 	v->nid = nid;
248648a8d27STakashi Iwai 	v->verb = verb;
249648a8d27STakashi Iwai 	v->param = param;
250648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
251648a8d27STakashi Iwai 	return 0;
252648a8d27STakashi Iwai }
253648a8d27STakashi Iwai 
init_verbs_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)254648a8d27STakashi Iwai static ssize_t init_verbs_store(struct device *dev,
255648a8d27STakashi Iwai 				struct device_attribute *attr,
256648a8d27STakashi Iwai 				const char *buf, size_t count)
257648a8d27STakashi Iwai {
258648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
259648a8d27STakashi Iwai 	int err = parse_init_verbs(codec, buf);
260648a8d27STakashi Iwai 	if (err < 0)
261648a8d27STakashi Iwai 		return err;
262648a8d27STakashi Iwai 	return count;
263648a8d27STakashi Iwai }
264648a8d27STakashi Iwai 
hints_show(struct device * dev,struct device_attribute * attr,char * buf)265648a8d27STakashi Iwai static ssize_t hints_show(struct device *dev,
266648a8d27STakashi Iwai 			  struct device_attribute *attr,
267648a8d27STakashi Iwai 			  char *buf)
268648a8d27STakashi Iwai {
269648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
270a9c2dfc8STakashi Iwai 	const struct hda_hint *hint;
271648a8d27STakashi Iwai 	int i, len = 0;
272648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
273a9c2dfc8STakashi Iwai 	snd_array_for_each(&codec->hints, i, hint) {
274*17daae7aSTakashi Iwai 		len += sysfs_emit_at(buf, len, "%s = %s\n",
275*17daae7aSTakashi Iwai 				     hint->key, hint->val);
276648a8d27STakashi Iwai 	}
277648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
278648a8d27STakashi Iwai 	return len;
279648a8d27STakashi Iwai }
280648a8d27STakashi Iwai 
get_hint(struct hda_codec * codec,const char * key)281648a8d27STakashi Iwai static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
282648a8d27STakashi Iwai {
283a9c2dfc8STakashi Iwai 	struct hda_hint *hint;
284648a8d27STakashi Iwai 	int i;
285648a8d27STakashi Iwai 
286a9c2dfc8STakashi Iwai 	snd_array_for_each(&codec->hints, i, hint) {
287648a8d27STakashi Iwai 		if (!strcmp(hint->key, key))
288648a8d27STakashi Iwai 			return hint;
289648a8d27STakashi Iwai 	}
290648a8d27STakashi Iwai 	return NULL;
291648a8d27STakashi Iwai }
292648a8d27STakashi Iwai 
remove_trail_spaces(char * str)293648a8d27STakashi Iwai static void remove_trail_spaces(char *str)
294648a8d27STakashi Iwai {
295648a8d27STakashi Iwai 	char *p;
296648a8d27STakashi Iwai 	if (!*str)
297648a8d27STakashi Iwai 		return;
298648a8d27STakashi Iwai 	p = str + strlen(str) - 1;
299648a8d27STakashi Iwai 	for (; isspace(*p); p--) {
300648a8d27STakashi Iwai 		*p = 0;
301648a8d27STakashi Iwai 		if (p == str)
302648a8d27STakashi Iwai 			return;
303648a8d27STakashi Iwai 	}
304648a8d27STakashi Iwai }
305648a8d27STakashi Iwai 
306648a8d27STakashi Iwai #define MAX_HINTS	1024
307648a8d27STakashi Iwai 
parse_hints(struct hda_codec * codec,const char * buf)308648a8d27STakashi Iwai static int parse_hints(struct hda_codec *codec, const char *buf)
309648a8d27STakashi Iwai {
310648a8d27STakashi Iwai 	char *key, *val;
311648a8d27STakashi Iwai 	struct hda_hint *hint;
312648a8d27STakashi Iwai 	int err = 0;
313648a8d27STakashi Iwai 
314648a8d27STakashi Iwai 	buf = skip_spaces(buf);
315648a8d27STakashi Iwai 	if (!*buf || *buf == '#' || *buf == '\n')
316648a8d27STakashi Iwai 		return 0;
317648a8d27STakashi Iwai 	if (*buf == '=')
318648a8d27STakashi Iwai 		return -EINVAL;
319648a8d27STakashi Iwai 	key = kstrndup_noeol(buf, 1024);
320648a8d27STakashi Iwai 	if (!key)
321648a8d27STakashi Iwai 		return -ENOMEM;
322648a8d27STakashi Iwai 	/* extract key and val */
323648a8d27STakashi Iwai 	val = strchr(key, '=');
324648a8d27STakashi Iwai 	if (!val) {
325648a8d27STakashi Iwai 		kfree(key);
326648a8d27STakashi Iwai 		return -EINVAL;
327648a8d27STakashi Iwai 	}
328648a8d27STakashi Iwai 	*val++ = 0;
329648a8d27STakashi Iwai 	val = skip_spaces(val);
330648a8d27STakashi Iwai 	remove_trail_spaces(key);
331648a8d27STakashi Iwai 	remove_trail_spaces(val);
332648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
333648a8d27STakashi Iwai 	hint = get_hint(codec, key);
334648a8d27STakashi Iwai 	if (hint) {
335648a8d27STakashi Iwai 		/* replace */
336648a8d27STakashi Iwai 		kfree(hint->key);
337648a8d27STakashi Iwai 		hint->key = key;
338648a8d27STakashi Iwai 		hint->val = val;
339648a8d27STakashi Iwai 		goto unlock;
340648a8d27STakashi Iwai 	}
341648a8d27STakashi Iwai 	/* allocate a new hint entry */
342648a8d27STakashi Iwai 	if (codec->hints.used >= MAX_HINTS)
343648a8d27STakashi Iwai 		hint = NULL;
344648a8d27STakashi Iwai 	else
345648a8d27STakashi Iwai 		hint = snd_array_new(&codec->hints);
346648a8d27STakashi Iwai 	if (hint) {
347648a8d27STakashi Iwai 		hint->key = key;
348648a8d27STakashi Iwai 		hint->val = val;
349648a8d27STakashi Iwai 	} else {
350648a8d27STakashi Iwai 		err = -ENOMEM;
351648a8d27STakashi Iwai 	}
352648a8d27STakashi Iwai  unlock:
353648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
354648a8d27STakashi Iwai 	if (err)
355648a8d27STakashi Iwai 		kfree(key);
356648a8d27STakashi Iwai 	return err;
357648a8d27STakashi Iwai }
358648a8d27STakashi Iwai 
hints_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)359648a8d27STakashi Iwai static ssize_t hints_store(struct device *dev,
360648a8d27STakashi Iwai 			   struct device_attribute *attr,
361648a8d27STakashi Iwai 			   const char *buf, size_t count)
362648a8d27STakashi Iwai {
363648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
364648a8d27STakashi Iwai 	int err = parse_hints(codec, buf);
365648a8d27STakashi Iwai 	if (err < 0)
366648a8d27STakashi Iwai 		return err;
367648a8d27STakashi Iwai 	return count;
368648a8d27STakashi Iwai }
369648a8d27STakashi Iwai 
user_pin_configs_show(struct device * dev,struct device_attribute * attr,char * buf)370648a8d27STakashi Iwai static ssize_t user_pin_configs_show(struct device *dev,
371648a8d27STakashi Iwai 				     struct device_attribute *attr,
372648a8d27STakashi Iwai 				     char *buf)
373648a8d27STakashi Iwai {
374648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
375648a8d27STakashi Iwai 	return pin_configs_show(codec, &codec->user_pins, buf);
376648a8d27STakashi Iwai }
377648a8d27STakashi Iwai 
parse_user_pin_configs(struct hda_codec * codec,const char * buf)378648a8d27STakashi Iwai static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
379648a8d27STakashi Iwai {
380648a8d27STakashi Iwai 	int nid, cfg, err;
381648a8d27STakashi Iwai 
382648a8d27STakashi Iwai 	if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
383648a8d27STakashi Iwai 		return -EINVAL;
384648a8d27STakashi Iwai 	if (!nid)
385648a8d27STakashi Iwai 		return -EINVAL;
386648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
387648a8d27STakashi Iwai 	err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
388648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
389648a8d27STakashi Iwai 	return err;
390648a8d27STakashi Iwai }
391648a8d27STakashi Iwai 
user_pin_configs_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)392648a8d27STakashi Iwai static ssize_t user_pin_configs_store(struct device *dev,
393648a8d27STakashi Iwai 				      struct device_attribute *attr,
394648a8d27STakashi Iwai 				      const char *buf, size_t count)
395648a8d27STakashi Iwai {
396648a8d27STakashi Iwai 	struct hda_codec *codec = dev_get_drvdata(dev);
397648a8d27STakashi Iwai 	int err = parse_user_pin_configs(codec, buf);
398648a8d27STakashi Iwai 	if (err < 0)
399648a8d27STakashi Iwai 		return err;
400648a8d27STakashi Iwai 	return count;
401648a8d27STakashi Iwai }
402648a8d27STakashi Iwai 
403b989d044STakashi Iwai /* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
404648a8d27STakashi Iwai static DEVICE_ATTR_RW(init_verbs);
405648a8d27STakashi Iwai static DEVICE_ATTR_RW(hints);
406648a8d27STakashi Iwai static DEVICE_ATTR_RW(user_pin_configs);
407648a8d27STakashi Iwai static DEVICE_ATTR_WO(reconfig);
408648a8d27STakashi Iwai static DEVICE_ATTR_WO(clear);
409648a8d27STakashi Iwai 
41095a962c3STakashi Iwai /**
41195a962c3STakashi Iwai  * snd_hda_get_hint - Look for hint string
41295a962c3STakashi Iwai  * @codec: the HDA codec
41395a962c3STakashi Iwai  * @key: the hint key string
41495a962c3STakashi Iwai  *
41595a962c3STakashi Iwai  * Look for a hint key/value pair matching with the given key string
41695a962c3STakashi Iwai  * and returns the value string.  If nothing found, returns NULL.
417648a8d27STakashi Iwai  */
snd_hda_get_hint(struct hda_codec * codec,const char * key)418648a8d27STakashi Iwai const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
419648a8d27STakashi Iwai {
420648a8d27STakashi Iwai 	struct hda_hint *hint = get_hint(codec, key);
421648a8d27STakashi Iwai 	return hint ? hint->val : NULL;
422648a8d27STakashi Iwai }
423648a8d27STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_hint);
424648a8d27STakashi Iwai 
42595a962c3STakashi Iwai /**
42695a962c3STakashi Iwai  * snd_hda_get_bool_hint - Get a boolean hint value
42795a962c3STakashi Iwai  * @codec: the HDA codec
42895a962c3STakashi Iwai  * @key: the hint key string
42995a962c3STakashi Iwai  *
43095a962c3STakashi Iwai  * Look for a hint key/value pair matching with the given key string
43195a962c3STakashi Iwai  * and returns a boolean value parsed from the value.  If no matching
43295a962c3STakashi Iwai  * key is found, return a negative value.
43395a962c3STakashi Iwai  */
snd_hda_get_bool_hint(struct hda_codec * codec,const char * key)434648a8d27STakashi Iwai int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
435648a8d27STakashi Iwai {
436648a8d27STakashi Iwai 	const char *p;
437648a8d27STakashi Iwai 	int ret;
438648a8d27STakashi Iwai 
439648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
440648a8d27STakashi Iwai 	p = snd_hda_get_hint(codec, key);
441648a8d27STakashi Iwai 	if (!p || !*p)
442648a8d27STakashi Iwai 		ret = -ENOENT;
443648a8d27STakashi Iwai 	else {
444648a8d27STakashi Iwai 		switch (toupper(*p)) {
445648a8d27STakashi Iwai 		case 'T': /* true */
446648a8d27STakashi Iwai 		case 'Y': /* yes */
447648a8d27STakashi Iwai 		case '1':
448648a8d27STakashi Iwai 			ret = 1;
449648a8d27STakashi Iwai 			break;
450648a8d27STakashi Iwai 		default:
451648a8d27STakashi Iwai 			ret = 0;
452648a8d27STakashi Iwai 			break;
453648a8d27STakashi Iwai 		}
454648a8d27STakashi Iwai 	}
455648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
456648a8d27STakashi Iwai 	return ret;
457648a8d27STakashi Iwai }
458648a8d27STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
459648a8d27STakashi Iwai 
46095a962c3STakashi Iwai /**
461c10b11f6STakashi Iwai  * snd_hda_get_int_hint - Get an integer hint value
46295a962c3STakashi Iwai  * @codec: the HDA codec
46395a962c3STakashi Iwai  * @key: the hint key string
46495a962c3STakashi Iwai  * @valp: pointer to store a value
46595a962c3STakashi Iwai  *
46695a962c3STakashi Iwai  * Look for a hint key/value pair matching with the given key string
46795a962c3STakashi Iwai  * and stores the integer value to @valp.  If no matching key is found,
46895a962c3STakashi Iwai  * return a negative error code.  Otherwise it returns zero.
46995a962c3STakashi Iwai  */
snd_hda_get_int_hint(struct hda_codec * codec,const char * key,int * valp)470648a8d27STakashi Iwai int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
471648a8d27STakashi Iwai {
472648a8d27STakashi Iwai 	const char *p;
473648a8d27STakashi Iwai 	unsigned long val;
474648a8d27STakashi Iwai 	int ret;
475648a8d27STakashi Iwai 
476648a8d27STakashi Iwai 	mutex_lock(&codec->user_mutex);
477648a8d27STakashi Iwai 	p = snd_hda_get_hint(codec, key);
478648a8d27STakashi Iwai 	if (!p)
479648a8d27STakashi Iwai 		ret = -ENOENT;
480648a8d27STakashi Iwai 	else if (kstrtoul(p, 0, &val))
481648a8d27STakashi Iwai 		ret = -EINVAL;
482648a8d27STakashi Iwai 	else {
483648a8d27STakashi Iwai 		*valp = val;
484648a8d27STakashi Iwai 		ret = 0;
485648a8d27STakashi Iwai 	}
486648a8d27STakashi Iwai 	mutex_unlock(&codec->user_mutex);
487648a8d27STakashi Iwai 	return ret;
488648a8d27STakashi Iwai }
489648a8d27STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
490648a8d27STakashi Iwai #endif /* CONFIG_SND_HDA_RECONFIG */
491648a8d27STakashi Iwai 
492b989d044STakashi Iwai /*
493b989d044STakashi Iwai  * common sysfs attributes
494b989d044STakashi Iwai  */
495b989d044STakashi Iwai #ifdef CONFIG_SND_HDA_RECONFIG
496b989d044STakashi Iwai #define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RW(name)
497b989d044STakashi Iwai #else
498b989d044STakashi Iwai #define RECONFIG_DEVICE_ATTR(name)	DEVICE_ATTR_RO(name)
499b989d044STakashi Iwai #endif
500b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(vendor_id);
501b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(subsystem_id);
502b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(revision_id);
503b989d044STakashi Iwai static DEVICE_ATTR_RO(afg);
504b989d044STakashi Iwai static DEVICE_ATTR_RO(mfg);
505b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(vendor_name);
506b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(chip_name);
507b989d044STakashi Iwai static RECONFIG_DEVICE_ATTR(modelname);
508b989d044STakashi Iwai static DEVICE_ATTR_RO(init_pin_configs);
509b989d044STakashi Iwai static DEVICE_ATTR_RO(driver_pin_configs);
510b989d044STakashi Iwai 
511b989d044STakashi Iwai 
512648a8d27STakashi Iwai #ifdef CONFIG_SND_HDA_PATCH_LOADER
513648a8d27STakashi Iwai 
514648a8d27STakashi Iwai /* parser mode */
515648a8d27STakashi Iwai enum {
516648a8d27STakashi Iwai 	LINE_MODE_NONE,
517648a8d27STakashi Iwai 	LINE_MODE_CODEC,
518648a8d27STakashi Iwai 	LINE_MODE_MODEL,
519648a8d27STakashi Iwai 	LINE_MODE_PINCFG,
520648a8d27STakashi Iwai 	LINE_MODE_VERB,
521648a8d27STakashi Iwai 	LINE_MODE_HINT,
522648a8d27STakashi Iwai 	LINE_MODE_VENDOR_ID,
523648a8d27STakashi Iwai 	LINE_MODE_SUBSYSTEM_ID,
524648a8d27STakashi Iwai 	LINE_MODE_REVISION_ID,
525648a8d27STakashi Iwai 	LINE_MODE_CHIP_NAME,
526648a8d27STakashi Iwai 	NUM_LINE_MODES,
527648a8d27STakashi Iwai };
528648a8d27STakashi Iwai 
strmatch(const char * a,const char * b)529648a8d27STakashi Iwai static inline int strmatch(const char *a, const char *b)
530648a8d27STakashi Iwai {
5318bb1ffdfSRasmus Villemoes 	return strncasecmp(a, b, strlen(b)) == 0;
532648a8d27STakashi Iwai }
533648a8d27STakashi Iwai 
534648a8d27STakashi Iwai /* parse the contents after the line "[codec]"
535648a8d27STakashi Iwai  * accept only the line with three numbers, and assign the current codec
536648a8d27STakashi Iwai  */
parse_codec_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)537648a8d27STakashi Iwai static void parse_codec_mode(char *buf, struct hda_bus *bus,
538648a8d27STakashi Iwai 			     struct hda_codec **codecp)
539648a8d27STakashi Iwai {
540648a8d27STakashi Iwai 	int vendorid, subid, caddr;
541648a8d27STakashi Iwai 	struct hda_codec *codec;
542648a8d27STakashi Iwai 
543648a8d27STakashi Iwai 	*codecp = NULL;
544648a8d27STakashi Iwai 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
545d068ebc2STakashi Iwai 		list_for_each_codec(codec, bus) {
5467639a06cSTakashi Iwai 			if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
5477639a06cSTakashi Iwai 			    (subid <= 0 || codec->core.subsystem_id == subid) &&
5487639a06cSTakashi Iwai 			    codec->core.addr == caddr) {
549648a8d27STakashi Iwai 				*codecp = codec;
550648a8d27STakashi Iwai 				break;
551648a8d27STakashi Iwai 			}
552648a8d27STakashi Iwai 		}
553648a8d27STakashi Iwai 	}
554648a8d27STakashi Iwai }
555648a8d27STakashi Iwai 
556648a8d27STakashi Iwai /* parse the contents after the other command tags, [pincfg], [verb],
557648a8d27STakashi Iwai  * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
558648a8d27STakashi Iwai  * just pass to the sysfs helper (only when any codec was specified)
559648a8d27STakashi Iwai  */
parse_pincfg_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)560648a8d27STakashi Iwai static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
561648a8d27STakashi Iwai 			      struct hda_codec **codecp)
562648a8d27STakashi Iwai {
563648a8d27STakashi Iwai 	parse_user_pin_configs(*codecp, buf);
564648a8d27STakashi Iwai }
565648a8d27STakashi Iwai 
parse_verb_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)566648a8d27STakashi Iwai static void parse_verb_mode(char *buf, struct hda_bus *bus,
567648a8d27STakashi Iwai 			    struct hda_codec **codecp)
568648a8d27STakashi Iwai {
569648a8d27STakashi Iwai 	parse_init_verbs(*codecp, buf);
570648a8d27STakashi Iwai }
571648a8d27STakashi Iwai 
parse_hint_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)572648a8d27STakashi Iwai static void parse_hint_mode(char *buf, struct hda_bus *bus,
573648a8d27STakashi Iwai 			    struct hda_codec **codecp)
574648a8d27STakashi Iwai {
575648a8d27STakashi Iwai 	parse_hints(*codecp, buf);
576648a8d27STakashi Iwai }
577648a8d27STakashi Iwai 
parse_model_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)578648a8d27STakashi Iwai static void parse_model_mode(char *buf, struct hda_bus *bus,
579648a8d27STakashi Iwai 			     struct hda_codec **codecp)
580648a8d27STakashi Iwai {
581648a8d27STakashi Iwai 	kfree((*codecp)->modelname);
582648a8d27STakashi Iwai 	(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
583648a8d27STakashi Iwai }
584648a8d27STakashi Iwai 
parse_chip_name_mode(char * buf,struct hda_bus * bus,struct hda_codec ** codecp)585648a8d27STakashi Iwai static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
586648a8d27STakashi Iwai 				 struct hda_codec **codecp)
587648a8d27STakashi Iwai {
588ded255beSTakashi Iwai 	snd_hda_codec_set_name(*codecp, buf);
589648a8d27STakashi Iwai }
590648a8d27STakashi Iwai 
591648a8d27STakashi Iwai #define DEFINE_PARSE_ID_MODE(name) \
592648a8d27STakashi Iwai static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
593648a8d27STakashi Iwai 				 struct hda_codec **codecp) \
594648a8d27STakashi Iwai { \
595648a8d27STakashi Iwai 	unsigned long val; \
596648a8d27STakashi Iwai 	if (!kstrtoul(buf, 0, &val)) \
5977639a06cSTakashi Iwai 		(*codecp)->core.name = val; \
598648a8d27STakashi Iwai }
599648a8d27STakashi Iwai 
600648a8d27STakashi Iwai DEFINE_PARSE_ID_MODE(vendor_id);
601648a8d27STakashi Iwai DEFINE_PARSE_ID_MODE(subsystem_id);
602648a8d27STakashi Iwai DEFINE_PARSE_ID_MODE(revision_id);
603648a8d27STakashi Iwai 
604648a8d27STakashi Iwai 
605648a8d27STakashi Iwai struct hda_patch_item {
606648a8d27STakashi Iwai 	const char *tag;
607648a8d27STakashi Iwai 	const char *alias;
608648a8d27STakashi Iwai 	void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
609648a8d27STakashi Iwai };
610648a8d27STakashi Iwai 
611bf82326fSTakashi Iwai static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
612648a8d27STakashi Iwai 	[LINE_MODE_CODEC] = {
613648a8d27STakashi Iwai 		.tag = "[codec]",
614648a8d27STakashi Iwai 		.parser = parse_codec_mode,
615648a8d27STakashi Iwai 	},
616648a8d27STakashi Iwai 	[LINE_MODE_MODEL] = {
617648a8d27STakashi Iwai 		.tag = "[model]",
618648a8d27STakashi Iwai 		.parser = parse_model_mode,
619648a8d27STakashi Iwai 	},
620648a8d27STakashi Iwai 	[LINE_MODE_VERB] = {
621648a8d27STakashi Iwai 		.tag = "[verb]",
622648a8d27STakashi Iwai 		.alias = "[init_verbs]",
623648a8d27STakashi Iwai 		.parser = parse_verb_mode,
624648a8d27STakashi Iwai 	},
625648a8d27STakashi Iwai 	[LINE_MODE_PINCFG] = {
626648a8d27STakashi Iwai 		.tag = "[pincfg]",
627648a8d27STakashi Iwai 		.alias = "[user_pin_configs]",
628648a8d27STakashi Iwai 		.parser = parse_pincfg_mode,
629648a8d27STakashi Iwai 	},
630648a8d27STakashi Iwai 	[LINE_MODE_HINT] = {
631648a8d27STakashi Iwai 		.tag = "[hint]",
632648a8d27STakashi Iwai 		.alias = "[hints]",
633648a8d27STakashi Iwai 		.parser = parse_hint_mode
634648a8d27STakashi Iwai 	},
635648a8d27STakashi Iwai 	[LINE_MODE_VENDOR_ID] = {
636648a8d27STakashi Iwai 		.tag = "[vendor_id]",
637648a8d27STakashi Iwai 		.parser = parse_vendor_id_mode,
638648a8d27STakashi Iwai 	},
639648a8d27STakashi Iwai 	[LINE_MODE_SUBSYSTEM_ID] = {
640648a8d27STakashi Iwai 		.tag = "[subsystem_id]",
641648a8d27STakashi Iwai 		.parser = parse_subsystem_id_mode,
642648a8d27STakashi Iwai 	},
643648a8d27STakashi Iwai 	[LINE_MODE_REVISION_ID] = {
644648a8d27STakashi Iwai 		.tag = "[revision_id]",
645648a8d27STakashi Iwai 		.parser = parse_revision_id_mode,
646648a8d27STakashi Iwai 	},
647648a8d27STakashi Iwai 	[LINE_MODE_CHIP_NAME] = {
648648a8d27STakashi Iwai 		.tag = "[chip_name]",
649648a8d27STakashi Iwai 		.parser = parse_chip_name_mode,
650648a8d27STakashi Iwai 	},
651648a8d27STakashi Iwai };
652648a8d27STakashi Iwai 
653648a8d27STakashi Iwai /* check the line starting with '[' -- change the parser mode accodingly */
parse_line_mode(char * buf,struct hda_bus * bus)654648a8d27STakashi Iwai static int parse_line_mode(char *buf, struct hda_bus *bus)
655648a8d27STakashi Iwai {
656648a8d27STakashi Iwai 	int i;
657648a8d27STakashi Iwai 	for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
658648a8d27STakashi Iwai 		if (!patch_items[i].tag)
659648a8d27STakashi Iwai 			continue;
660648a8d27STakashi Iwai 		if (strmatch(buf, patch_items[i].tag))
661648a8d27STakashi Iwai 			return i;
662648a8d27STakashi Iwai 		if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
663648a8d27STakashi Iwai 			return i;
664648a8d27STakashi Iwai 	}
665648a8d27STakashi Iwai 	return LINE_MODE_NONE;
666648a8d27STakashi Iwai }
667648a8d27STakashi Iwai 
668648a8d27STakashi Iwai /* copy one line from the buffer in fw, and update the fields in fw
669648a8d27STakashi Iwai  * return zero if it reaches to the end of the buffer, or non-zero
670648a8d27STakashi Iwai  * if successfully copied a line
671648a8d27STakashi Iwai  *
672648a8d27STakashi Iwai  * the spaces at the beginning and the end of the line are stripped
673648a8d27STakashi Iwai  */
get_line_from_fw(char * buf,int size,size_t * fw_size_p,const void ** fw_data_p)674648a8d27STakashi Iwai static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
675648a8d27STakashi Iwai 			    const void **fw_data_p)
676648a8d27STakashi Iwai {
677648a8d27STakashi Iwai 	int len;
678648a8d27STakashi Iwai 	size_t fw_size = *fw_size_p;
679648a8d27STakashi Iwai 	const char *p = *fw_data_p;
680648a8d27STakashi Iwai 
681648a8d27STakashi Iwai 	while (isspace(*p) && fw_size) {
682648a8d27STakashi Iwai 		p++;
683648a8d27STakashi Iwai 		fw_size--;
684648a8d27STakashi Iwai 	}
685648a8d27STakashi Iwai 	if (!fw_size)
686648a8d27STakashi Iwai 		return 0;
687648a8d27STakashi Iwai 
688648a8d27STakashi Iwai 	for (len = 0; len < fw_size; len++) {
689648a8d27STakashi Iwai 		if (!*p)
690648a8d27STakashi Iwai 			break;
691648a8d27STakashi Iwai 		if (*p == '\n') {
692648a8d27STakashi Iwai 			p++;
693648a8d27STakashi Iwai 			len++;
694648a8d27STakashi Iwai 			break;
695648a8d27STakashi Iwai 		}
696648a8d27STakashi Iwai 		if (len < size)
697648a8d27STakashi Iwai 			*buf++ = *p++;
698648a8d27STakashi Iwai 	}
699648a8d27STakashi Iwai 	*buf = 0;
700648a8d27STakashi Iwai 	*fw_size_p = fw_size - len;
701648a8d27STakashi Iwai 	*fw_data_p = p;
702648a8d27STakashi Iwai 	remove_trail_spaces(buf);
703648a8d27STakashi Iwai 	return 1;
704648a8d27STakashi Iwai }
705648a8d27STakashi Iwai 
70695a962c3STakashi Iwai /**
70795a962c3STakashi Iwai  * snd_hda_load_patch - load a "patch" firmware file and parse it
70895a962c3STakashi Iwai  * @bus: HD-audio bus
70995a962c3STakashi Iwai  * @fw_size: the firmware byte size
71095a962c3STakashi Iwai  * @fw_buf: the firmware data
711648a8d27STakashi Iwai  */
snd_hda_load_patch(struct hda_bus * bus,size_t fw_size,const void * fw_buf)712648a8d27STakashi Iwai int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
713648a8d27STakashi Iwai {
714648a8d27STakashi Iwai 	char buf[128];
715648a8d27STakashi Iwai 	struct hda_codec *codec;
716648a8d27STakashi Iwai 	int line_mode;
717648a8d27STakashi Iwai 
718648a8d27STakashi Iwai 	line_mode = LINE_MODE_NONE;
719648a8d27STakashi Iwai 	codec = NULL;
720648a8d27STakashi Iwai 	while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
721648a8d27STakashi Iwai 		if (!*buf || *buf == '#' || *buf == '\n')
722648a8d27STakashi Iwai 			continue;
723648a8d27STakashi Iwai 		if (*buf == '[')
724648a8d27STakashi Iwai 			line_mode = parse_line_mode(buf, bus);
725648a8d27STakashi Iwai 		else if (patch_items[line_mode].parser &&
726648a8d27STakashi Iwai 			 (codec || line_mode <= LINE_MODE_CODEC))
727648a8d27STakashi Iwai 			patch_items[line_mode].parser(buf, bus, &codec);
728648a8d27STakashi Iwai 	}
729648a8d27STakashi Iwai 	return 0;
730648a8d27STakashi Iwai }
731648a8d27STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_load_patch);
732648a8d27STakashi Iwai #endif /* CONFIG_SND_HDA_PATCH_LOADER */
733648a8d27STakashi Iwai 
734648a8d27STakashi Iwai /*
735648a8d27STakashi Iwai  * sysfs entries
736648a8d27STakashi Iwai  */
737648a8d27STakashi Iwai static struct attribute *hda_dev_attrs[] = {
738648a8d27STakashi Iwai 	&dev_attr_vendor_id.attr,
739648a8d27STakashi Iwai 	&dev_attr_subsystem_id.attr,
740648a8d27STakashi Iwai 	&dev_attr_revision_id.attr,
741648a8d27STakashi Iwai 	&dev_attr_afg.attr,
742648a8d27STakashi Iwai 	&dev_attr_mfg.attr,
743648a8d27STakashi Iwai 	&dev_attr_vendor_name.attr,
744648a8d27STakashi Iwai 	&dev_attr_chip_name.attr,
745648a8d27STakashi Iwai 	&dev_attr_modelname.attr,
746b989d044STakashi Iwai 	&dev_attr_init_pin_configs.attr,
747b989d044STakashi Iwai 	&dev_attr_driver_pin_configs.attr,
748b989d044STakashi Iwai #ifdef CONFIG_PM
749b989d044STakashi Iwai 	&dev_attr_power_on_acct.attr,
750b989d044STakashi Iwai 	&dev_attr_power_off_acct.attr,
751b989d044STakashi Iwai #endif
752b989d044STakashi Iwai #ifdef CONFIG_SND_HDA_RECONFIG
753648a8d27STakashi Iwai 	&dev_attr_init_verbs.attr,
754648a8d27STakashi Iwai 	&dev_attr_hints.attr,
755648a8d27STakashi Iwai 	&dev_attr_user_pin_configs.attr,
756648a8d27STakashi Iwai 	&dev_attr_reconfig.attr,
757648a8d27STakashi Iwai 	&dev_attr_clear.attr,
758648a8d27STakashi Iwai #endif
759648a8d27STakashi Iwai 	NULL
760648a8d27STakashi Iwai };
761648a8d27STakashi Iwai 
762a5a041b6SArvind Yadav static const struct attribute_group hda_dev_attr_group = {
763648a8d27STakashi Iwai 	.attrs	= hda_dev_attrs,
764648a8d27STakashi Iwai };
765648a8d27STakashi Iwai 
766648a8d27STakashi Iwai const struct attribute_group *snd_hda_dev_attr_groups[] = {
767648a8d27STakashi Iwai 	&hda_dev_attr_group,
768648a8d27STakashi Iwai 	NULL
769648a8d27STakashi Iwai };
770648a8d27STakashi Iwai 
snd_hda_sysfs_init(struct hda_codec * codec)771648a8d27STakashi Iwai void snd_hda_sysfs_init(struct hda_codec *codec)
772648a8d27STakashi Iwai {
773648a8d27STakashi Iwai 	mutex_init(&codec->user_mutex);
774b989d044STakashi Iwai #ifdef CONFIG_SND_HDA_RECONFIG
775648a8d27STakashi Iwai 	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
776648a8d27STakashi Iwai 	snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
777648a8d27STakashi Iwai 	snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
778648a8d27STakashi Iwai #endif
779648a8d27STakashi Iwai }
780648a8d27STakashi Iwai 
snd_hda_sysfs_clear(struct hda_codec * codec)781648a8d27STakashi Iwai void snd_hda_sysfs_clear(struct hda_codec *codec)
782648a8d27STakashi Iwai {
783648a8d27STakashi Iwai #ifdef CONFIG_SND_HDA_RECONFIG
784a9c2dfc8STakashi Iwai 	struct hda_hint *hint;
785648a8d27STakashi Iwai 	int i;
786648a8d27STakashi Iwai 
787648a8d27STakashi Iwai 	/* clear init verbs */
788648a8d27STakashi Iwai 	snd_array_free(&codec->init_verbs);
789648a8d27STakashi Iwai 	/* clear hints */
790a9c2dfc8STakashi Iwai 	snd_array_for_each(&codec->hints, i, hint) {
791648a8d27STakashi Iwai 		kfree(hint->key); /* we don't need to free hint->val */
792648a8d27STakashi Iwai 	}
793648a8d27STakashi Iwai 	snd_array_free(&codec->hints);
794648a8d27STakashi Iwai 	snd_array_free(&codec->user_pins);
795648a8d27STakashi Iwai #endif
796648a8d27STakashi Iwai }
797