aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-02-25 04:38:13 -0500
committerTakashi Iwai <tiwai@suse.de>2014-02-25 06:12:54 -0500
commit648a8d276ed10062addd4a4e18aaf9ff84f14543 (patch)
tree5f0dcf8587dfb6123b51fe379e8aaf8812368ef2
parent13aeaf68019d297be79c99f828c2a9d6affef06b (diff)
ALSA: hda - Add sysfs to codec object, too
We have currently sysfs attributes for each hwdep, but basically these should belong to the codec itself, per se. Let's add them to the codec object while keeping them for hwdep as is for compatibility. While we are at it, split the sysfs-related stuff into a separate source file, hda_sysfs.c, and keep only the stuff necessary for hwdep in hda_hwdep.c. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/Kconfig4
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c11
-rw-r--r--sound/pci/hda/hda_codec.h7
-rw-r--r--sound/pci/hda/hda_hwdep.c754
-rw-r--r--sound/pci/hda/hda_local.h5
-rw-r--r--sound/pci/hda/hda_sysfs.c769
7 files changed, 788 insertions, 764 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 0e53634dbbd8..f2032dd7e35e 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -41,7 +41,6 @@ config SND_HDA_HWDEP
41 41
42config SND_HDA_RECONFIG 42config SND_HDA_RECONFIG
43 bool "Allow dynamic codec reconfiguration" 43 bool "Allow dynamic codec reconfiguration"
44 depends on SND_HDA_HWDEP
45 help 44 help
46 Say Y here to enable the HD-audio codec re-configuration feature. 45 Say Y here to enable the HD-audio codec re-configuration feature.
47 This adds the sysfs interfaces to allow user to clear the whole 46 This adds the sysfs interfaces to allow user to clear the whole
@@ -76,7 +75,6 @@ config SND_HDA_INPUT_JACK
76config SND_HDA_PATCH_LOADER 75config SND_HDA_PATCH_LOADER
77 bool "Support initialization patch loading for HD-audio" 76 bool "Support initialization patch loading for HD-audio"
78 select FW_LOADER 77 select FW_LOADER
79 select SND_HDA_HWDEP
80 select SND_HDA_RECONFIG 78 select SND_HDA_RECONFIG
81 help 79 help
82 Say Y here to allow the HD-audio driver to load a pseudo 80 Say Y here to allow the HD-audio driver to load a pseudo
@@ -84,8 +82,6 @@ config SND_HDA_PATCH_LOADER
84 start up. The "patch" file can be specified via patch module 82 start up. The "patch" file can be specified via patch module
85 option, such as patch=hda-init. 83 option, such as patch=hda-init.
86 84
87 This option turns on hwdep and reconfig features automatically.
88
89config SND_HDA_CODEC_REALTEK 85config SND_HDA_CODEC_REALTEK
90 tristate "Build Realtek HD-audio codec support" 86 tristate "Build Realtek HD-audio codec support"
91 select SND_HDA_GENERIC 87 select SND_HDA_GENERIC
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 1fcb118e480a..083b338e0783 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -2,7 +2,7 @@ snd-hda-intel-objs := hda_intel.o
2# for haswell power well 2# for haswell power well
3snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o 3snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o
4 4
5snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o 5snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
6snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o 6snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
7snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o 7snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
8snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o 8snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 98baf5674a63..2cba4dc6349a 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1170,7 +1170,7 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
1170{ 1170{
1171 struct hda_pincfg *pin; 1171 struct hda_pincfg *pin;
1172 1172
1173#ifdef CONFIG_SND_HDA_HWDEP 1173#ifdef CONFIG_SND_HDA_RECONFIG
1174 { 1174 {
1175 unsigned int cfg = 0; 1175 unsigned int cfg = 0;
1176 mutex_lock(&codec->user_mutex); 1176 mutex_lock(&codec->user_mutex);
@@ -1285,7 +1285,7 @@ static void free_hda_cache(struct hda_cache_rec *cache);
1285static void free_init_pincfgs(struct hda_codec *codec) 1285static void free_init_pincfgs(struct hda_codec *codec)
1286{ 1286{
1287 snd_array_free(&codec->driver_pins); 1287 snd_array_free(&codec->driver_pins);
1288#ifdef CONFIG_SND_HDA_HWDEP 1288#ifdef CONFIG_SND_HDA_RECONFIG
1289 snd_array_free(&codec->user_pins); 1289 snd_array_free(&codec->user_pins);
1290#endif 1290#endif
1291 snd_array_free(&codec->init_pins); 1291 snd_array_free(&codec->init_pins);
@@ -1359,6 +1359,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
1359 if (codec->patch_ops.free) 1359 if (codec->patch_ops.free)
1360 codec->patch_ops.free(codec); 1360 codec->patch_ops.free(codec);
1361 hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ 1361 hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
1362 snd_hda_sysfs_clear(codec);
1362 unload_parser(codec); 1363 unload_parser(codec);
1363 module_put(codec->owner); 1364 module_put(codec->owner);
1364 free_hda_cache(&codec->amp_cache); 1365 free_hda_cache(&codec->amp_cache);
@@ -1447,8 +1448,10 @@ int snd_hda_codec_new(struct hda_bus *bus,
1447 codec->dev.parent = &bus->card->card_dev; 1448 codec->dev.parent = &bus->card->card_dev;
1448 codec->dev.class = sound_class; 1449 codec->dev.class = sound_class;
1449 codec->dev.release = snd_hda_codec_dev_release; 1450 codec->dev.release = snd_hda_codec_dev_release;
1451 codec->dev.groups = snd_hda_dev_attr_groups;
1450 dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number, 1452 dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
1451 codec_addr); 1453 codec_addr);
1454 dev_set_drvdata(&codec->dev, codec); /* for sysfs */
1452 1455
1453 codec->bus = bus; 1456 codec->bus = bus;
1454 codec->addr = codec_addr; 1457 codec->addr = codec_addr;
@@ -1480,6 +1483,8 @@ int snd_hda_codec_new(struct hda_bus *bus,
1480 hda_keep_power_on(codec); 1483 hda_keep_power_on(codec);
1481#endif 1484#endif
1482 1485
1486 snd_hda_sysfs_init(codec);
1487
1483 if (codec->bus->modelname) { 1488 if (codec->bus->modelname) {
1484 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); 1489 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
1485 if (!codec->modelname) { 1490 if (!codec->modelname) {
@@ -4038,7 +4043,7 @@ static void sync_power_up_states(struct hda_codec *codec)
4038 } 4043 }
4039} 4044}
4040 4045
4041#ifdef CONFIG_SND_HDA_HWDEP 4046#ifdef CONFIG_SND_HDA_RECONFIG
4042/* execute additional init verbs */ 4047/* execute additional init verbs */
4043static void hda_exec_init_verbs(struct hda_codec *codec) 4048static void hda_exec_init_verbs(struct hda_codec *codec)
4044{ 4049{
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 4d9dd2b70f4a..ad5871f3a669 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -333,14 +333,17 @@ struct hda_codec {
333 struct snd_array driver_pins; /* pin configs set by codec parser */ 333 struct snd_array driver_pins; /* pin configs set by codec parser */
334 struct snd_array cvt_setups; /* audio convert setups */ 334 struct snd_array cvt_setups; /* audio convert setups */
335 335
336#ifdef CONFIG_SND_HDA_HWDEP 336#ifdef CONFIG_SND_HDA_RECONFIG
337 struct mutex user_mutex; 337 struct mutex user_mutex;
338 struct snd_hwdep *hwdep; /* assigned hwdep device */
339 struct snd_array init_verbs; /* additional init verbs */ 338 struct snd_array init_verbs; /* additional init verbs */
340 struct snd_array hints; /* additional hints */ 339 struct snd_array hints; /* additional hints */
341 struct snd_array user_pins; /* default pin configs to override */ 340 struct snd_array user_pins; /* default pin configs to override */
342#endif 341#endif
343 342
343#ifdef CONFIG_SND_HDA_HWDEP
344 struct snd_hwdep *hwdep; /* assigned hwdep device */
345#endif
346
344 /* misc flags */ 347 /* misc flags */
345 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each 348 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
346 * status change 349 * status change
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 896d116ca951..014a7849e8fd 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -21,22 +21,12 @@
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/compat.h> 23#include <linux/compat.h>
24#include <linux/mutex.h>
25#include <linux/ctype.h>
26#include <linux/string.h>
27#include <linux/export.h>
28#include <sound/core.h> 24#include <sound/core.h>
29#include "hda_codec.h" 25#include "hda_codec.h"
30#include "hda_local.h" 26#include "hda_local.h"
31#include <sound/hda_hwdep.h> 27#include <sound/hda_hwdep.h>
32#include <sound/minors.h> 28#include <sound/minors.h>
33 29
34/* hint string pair */
35struct hda_hint {
36 const char *key;
37 const char *val; /* contained in the same alloc as key */
38};
39
40/* 30/*
41 * write/read an out-of-bound verb 31 * write/read an out-of-bound verb
42 */ 32 */
@@ -104,28 +94,6 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
104 return 0; 94 return 0;
105} 95}
106 96
107static void clear_hwdep_elements(struct hda_codec *codec)
108{
109 int i;
110
111 /* clear init verbs */
112 snd_array_free(&codec->init_verbs);
113 /* clear hints */
114 for (i = 0; i < codec->hints.used; i++) {
115 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
116 kfree(hint->key); /* we don't need to free hint->val */
117 }
118 snd_array_free(&codec->hints);
119 snd_array_free(&codec->user_pins);
120}
121
122static void hwdep_free(struct snd_hwdep *hwdep)
123{
124 clear_hwdep_elements(hwdep->private_data);
125}
126
127static const struct attribute_group *snd_hda_dev_attr_groups[];
128
129int snd_hda_create_hwdep(struct hda_codec *codec) 97int snd_hda_create_hwdep(struct hda_codec *codec)
130{ 98{
131 char hwname[16]; 99 char hwname[16];
@@ -140,7 +108,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
140 sprintf(hwdep->name, "HDA Codec %d", codec->addr); 108 sprintf(hwdep->name, "HDA Codec %d", codec->addr);
141 hwdep->iface = SNDRV_HWDEP_IFACE_HDA; 109 hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
142 hwdep->private_data = codec; 110 hwdep->private_data = codec;
143 hwdep->private_free = hwdep_free;
144 hwdep->exclusive = 1; 111 hwdep->exclusive = 1;
145 hwdep->groups = snd_hda_dev_attr_groups; 112 hwdep->groups = snd_hda_dev_attr_groups;
146 113
@@ -150,729 +117,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
150 hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; 117 hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
151#endif 118#endif
152 119
153 mutex_init(&codec->user_mutex);
154 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
155 snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
156 snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
157
158 /* link to codec */ 120 /* link to codec */
159 hwdep->dev = &codec->dev; 121 hwdep->dev = &codec->dev;
160 122
161 return 0; 123 return 0;
162} 124}
163
164#ifdef CONFIG_PM
165static ssize_t power_on_acct_show(struct device *dev,
166 struct device_attribute *attr,
167 char *buf)
168{
169 struct hda_codec *codec = dev_get_drvdata(dev);
170 snd_hda_update_power_acct(codec);
171 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
172}
173
174static ssize_t power_off_acct_show(struct device *dev,
175 struct device_attribute *attr,
176 char *buf)
177{
178 struct hda_codec *codec = dev_get_drvdata(dev);
179 snd_hda_update_power_acct(codec);
180 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
181}
182
183static DEVICE_ATTR_RO(power_on_acct);
184static DEVICE_ATTR_RO(power_off_acct);
185#endif /* CONFIG_PM */
186
187#ifdef CONFIG_SND_HDA_RECONFIG
188
189/*
190 * sysfs interface
191 */
192
193static int clear_codec(struct hda_codec *codec)
194{
195 int err;
196
197 err = snd_hda_codec_reset(codec);
198 if (err < 0) {
199 snd_printk(KERN_ERR "The codec is being used, can't free.\n");
200 return err;
201 }
202 clear_hwdep_elements(codec);
203 return 0;
204}
205
206static int reconfig_codec(struct hda_codec *codec)
207{
208 int err;
209
210 snd_hda_power_up(codec);
211 snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
212 err = snd_hda_codec_reset(codec);
213 if (err < 0) {
214 snd_printk(KERN_ERR
215 "The codec is being used, can't reconfigure.\n");
216 goto error;
217 }
218 err = snd_hda_codec_configure(codec);
219 if (err < 0)
220 goto error;
221 /* rebuild PCMs */
222 err = snd_hda_codec_build_pcms(codec);
223 if (err < 0)
224 goto error;
225 /* rebuild mixers */
226 err = snd_hda_codec_build_controls(codec);
227 if (err < 0)
228 goto error;
229 err = snd_card_register(codec->bus->card);
230 error:
231 snd_hda_power_down(codec);
232 return err;
233}
234
235/*
236 * allocate a string at most len chars, and remove the trailing EOL
237 */
238static char *kstrndup_noeol(const char *src, size_t len)
239{
240 char *s = kstrndup(src, len, GFP_KERNEL);
241 char *p;
242 if (!s)
243 return NULL;
244 p = strchr(s, '\n');
245 if (p)
246 *p = 0;
247 return s;
248}
249
250#define CODEC_INFO_SHOW(type) \
251static ssize_t type##_show(struct device *dev, \
252 struct device_attribute *attr, \
253 char *buf) \
254{ \
255 struct hda_codec *codec = dev_get_drvdata(dev); \
256 return sprintf(buf, "0x%x\n", codec->type); \
257}
258
259#define CODEC_INFO_STR_SHOW(type) \
260static ssize_t type##_show(struct device *dev, \
261 struct device_attribute *attr, \
262 char *buf) \
263{ \
264 struct hda_codec *codec = dev_get_drvdata(dev); \
265 return sprintf(buf, "%s\n", \
266 codec->type ? codec->type : ""); \
267}
268
269CODEC_INFO_SHOW(vendor_id);
270CODEC_INFO_SHOW(subsystem_id);
271CODEC_INFO_SHOW(revision_id);
272CODEC_INFO_SHOW(afg);
273CODEC_INFO_SHOW(mfg);
274CODEC_INFO_STR_SHOW(vendor_name);
275CODEC_INFO_STR_SHOW(chip_name);
276CODEC_INFO_STR_SHOW(modelname);
277
278#define CODEC_INFO_STORE(type) \
279static ssize_t type##_store(struct device *dev, \
280 struct device_attribute *attr, \
281 const char *buf, size_t count) \
282{ \
283 struct hda_codec *codec = dev_get_drvdata(dev); \
284 unsigned long val; \
285 int err = kstrtoul(buf, 0, &val); \
286 if (err < 0) \
287 return err; \
288 codec->type = val; \
289 return count; \
290}
291
292#define CODEC_INFO_STR_STORE(type) \
293static ssize_t type##_store(struct device *dev, \
294 struct device_attribute *attr, \
295 const char *buf, size_t count) \
296{ \
297 struct hda_codec *codec = dev_get_drvdata(dev); \
298 char *s = kstrndup_noeol(buf, 64); \
299 if (!s) \
300 return -ENOMEM; \
301 kfree(codec->type); \
302 codec->type = s; \
303 return count; \
304}
305
306CODEC_INFO_STORE(vendor_id);
307CODEC_INFO_STORE(subsystem_id);
308CODEC_INFO_STORE(revision_id);
309CODEC_INFO_STR_STORE(vendor_name);
310CODEC_INFO_STR_STORE(chip_name);
311CODEC_INFO_STR_STORE(modelname);
312
313#define CODEC_ACTION_STORE(type) \
314static ssize_t type##_store(struct device *dev, \
315 struct device_attribute *attr, \
316 const char *buf, size_t count) \
317{ \
318 struct hda_codec *codec = dev_get_drvdata(dev); \
319 int err = 0; \
320 if (*buf) \
321 err = type##_codec(codec); \
322 return err < 0 ? err : count; \
323}
324
325CODEC_ACTION_STORE(reconfig);
326CODEC_ACTION_STORE(clear);
327
328static ssize_t init_verbs_show(struct device *dev,
329 struct device_attribute *attr,
330 char *buf)
331{
332 struct hda_codec *codec = dev_get_drvdata(dev);
333 int i, len = 0;
334 mutex_lock(&codec->user_mutex);
335 for (i = 0; i < codec->init_verbs.used; i++) {
336 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
337 len += snprintf(buf + len, PAGE_SIZE - len,
338 "0x%02x 0x%03x 0x%04x\n",
339 v->nid, v->verb, v->param);
340 }
341 mutex_unlock(&codec->user_mutex);
342 return len;
343}
344
345static int parse_init_verbs(struct hda_codec *codec, const char *buf)
346{
347 struct hda_verb *v;
348 int nid, verb, param;
349
350 if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
351 return -EINVAL;
352 if (!nid || !verb)
353 return -EINVAL;
354 mutex_lock(&codec->user_mutex);
355 v = snd_array_new(&codec->init_verbs);
356 if (!v) {
357 mutex_unlock(&codec->user_mutex);
358 return -ENOMEM;
359 }
360 v->nid = nid;
361 v->verb = verb;
362 v->param = param;
363 mutex_unlock(&codec->user_mutex);
364 return 0;
365}
366
367static ssize_t init_verbs_store(struct device *dev,
368 struct device_attribute *attr,
369 const char *buf, size_t count)
370{
371 struct hda_codec *codec = dev_get_drvdata(dev);
372 int err = parse_init_verbs(codec, buf);
373 if (err < 0)
374 return err;
375 return count;
376}
377
378static ssize_t hints_show(struct device *dev,
379 struct device_attribute *attr,
380 char *buf)
381{
382 struct hda_codec *codec = dev_get_drvdata(dev);
383 int i, len = 0;
384 mutex_lock(&codec->user_mutex);
385 for (i = 0; i < codec->hints.used; i++) {
386 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
387 len += snprintf(buf + len, PAGE_SIZE - len,
388 "%s = %s\n", hint->key, hint->val);
389 }
390 mutex_unlock(&codec->user_mutex);
391 return len;
392}
393
394static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
395{
396 int i;
397
398 for (i = 0; i < codec->hints.used; i++) {
399 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
400 if (!strcmp(hint->key, key))
401 return hint;
402 }
403 return NULL;
404}
405
406static void remove_trail_spaces(char *str)
407{
408 char *p;
409 if (!*str)
410 return;
411 p = str + strlen(str) - 1;
412 for (; isspace(*p); p--) {
413 *p = 0;
414 if (p == str)
415 return;
416 }
417}
418
419#define MAX_HINTS 1024
420
421static int parse_hints(struct hda_codec *codec, const char *buf)
422{
423 char *key, *val;
424 struct hda_hint *hint;
425 int err = 0;
426
427 buf = skip_spaces(buf);
428 if (!*buf || *buf == '#' || *buf == '\n')
429 return 0;
430 if (*buf == '=')
431 return -EINVAL;
432 key = kstrndup_noeol(buf, 1024);
433 if (!key)
434 return -ENOMEM;
435 /* extract key and val */
436 val = strchr(key, '=');
437 if (!val) {
438 kfree(key);
439 return -EINVAL;
440 }
441 *val++ = 0;
442 val = skip_spaces(val);
443 remove_trail_spaces(key);
444 remove_trail_spaces(val);
445 mutex_lock(&codec->user_mutex);
446 hint = get_hint(codec, key);
447 if (hint) {
448 /* replace */
449 kfree(hint->key);
450 hint->key = key;
451 hint->val = val;
452 goto unlock;
453 }
454 /* allocate a new hint entry */
455 if (codec->hints.used >= MAX_HINTS)
456 hint = NULL;
457 else
458 hint = snd_array_new(&codec->hints);
459 if (hint) {
460 hint->key = key;
461 hint->val = val;
462 } else {
463 err = -ENOMEM;
464 }
465 unlock:
466 mutex_unlock(&codec->user_mutex);
467 if (err)
468 kfree(key);
469 return err;
470}
471
472static ssize_t hints_store(struct device *dev,
473 struct device_attribute *attr,
474 const char *buf, size_t count)
475{
476 struct hda_codec *codec = dev_get_drvdata(dev);
477 int err = parse_hints(codec, buf);
478 if (err < 0)
479 return err;
480 return count;
481}
482
483static ssize_t pin_configs_show(struct hda_codec *codec,
484 struct snd_array *list,
485 char *buf)
486{
487 int i, len = 0;
488 mutex_lock(&codec->user_mutex);
489 for (i = 0; i < list->used; i++) {
490 struct hda_pincfg *pin = snd_array_elem(list, i);
491 len += sprintf(buf + len, "0x%02x 0x%08x\n",
492 pin->nid, pin->cfg);
493 }
494 mutex_unlock(&codec->user_mutex);
495 return len;
496}
497
498static ssize_t init_pin_configs_show(struct device *dev,
499 struct device_attribute *attr,
500 char *buf)
501{
502 struct hda_codec *codec = dev_get_drvdata(dev);
503 return pin_configs_show(codec, &codec->init_pins, buf);
504}
505
506static ssize_t user_pin_configs_show(struct device *dev,
507 struct device_attribute *attr,
508 char *buf)
509{
510 struct hda_codec *codec = dev_get_drvdata(dev);
511 return pin_configs_show(codec, &codec->user_pins, buf);
512}
513
514static ssize_t driver_pin_configs_show(struct device *dev,
515 struct device_attribute *attr,
516 char *buf)
517{
518 struct hda_codec *codec = dev_get_drvdata(dev);
519 return pin_configs_show(codec, &codec->driver_pins, buf);
520}
521
522#define MAX_PIN_CONFIGS 32
523
524static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
525{
526 int nid, cfg, err;
527
528 if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
529 return -EINVAL;
530 if (!nid)
531 return -EINVAL;
532 mutex_lock(&codec->user_mutex);
533 err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
534 mutex_unlock(&codec->user_mutex);
535 return err;
536}
537
538static ssize_t user_pin_configs_store(struct device *dev,
539 struct device_attribute *attr,
540 const char *buf, size_t count)
541{
542 struct hda_codec *codec = dev_get_drvdata(dev);
543 int err = parse_user_pin_configs(codec, buf);
544 if (err < 0)
545 return err;
546 return count;
547}
548
549static DEVICE_ATTR_RW(vendor_id);
550static DEVICE_ATTR_RW(subsystem_id);
551static DEVICE_ATTR_RW(revision_id);
552static DEVICE_ATTR_RO(afg);
553static DEVICE_ATTR_RO(mfg);
554static DEVICE_ATTR_RW(vendor_name);
555static DEVICE_ATTR_RW(chip_name);
556static DEVICE_ATTR_RW(modelname);
557static DEVICE_ATTR_RW(init_verbs);
558static DEVICE_ATTR_RW(hints);
559static DEVICE_ATTR_RO(init_pin_configs);
560static DEVICE_ATTR_RW(user_pin_configs);
561static DEVICE_ATTR_RO(driver_pin_configs);
562static DEVICE_ATTR_WO(reconfig);
563static DEVICE_ATTR_WO(clear);
564
565/*
566 * Look for hint string
567 */
568const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
569{
570 struct hda_hint *hint = get_hint(codec, key);
571 return hint ? hint->val : NULL;
572}
573EXPORT_SYMBOL_GPL(snd_hda_get_hint);
574
575int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
576{
577 const char *p;
578 int ret;
579
580 mutex_lock(&codec->user_mutex);
581 p = snd_hda_get_hint(codec, key);
582 if (!p || !*p)
583 ret = -ENOENT;
584 else {
585 switch (toupper(*p)) {
586 case 'T': /* true */
587 case 'Y': /* yes */
588 case '1':
589 ret = 1;
590 break;
591 default:
592 ret = 0;
593 break;
594 }
595 }
596 mutex_unlock(&codec->user_mutex);
597 return ret;
598}
599EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
600
601int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
602{
603 const char *p;
604 unsigned long val;
605 int ret;
606
607 mutex_lock(&codec->user_mutex);
608 p = snd_hda_get_hint(codec, key);
609 if (!p)
610 ret = -ENOENT;
611 else if (kstrtoul(p, 0, &val))
612 ret = -EINVAL;
613 else {
614 *valp = val;
615 ret = 0;
616 }
617 mutex_unlock(&codec->user_mutex);
618 return ret;
619}
620EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
621#endif /* CONFIG_SND_HDA_RECONFIG */
622
623#ifdef CONFIG_SND_HDA_PATCH_LOADER
624
625/* parser mode */
626enum {
627 LINE_MODE_NONE,
628 LINE_MODE_CODEC,
629 LINE_MODE_MODEL,
630 LINE_MODE_PINCFG,
631 LINE_MODE_VERB,
632 LINE_MODE_HINT,
633 LINE_MODE_VENDOR_ID,
634 LINE_MODE_SUBSYSTEM_ID,
635 LINE_MODE_REVISION_ID,
636 LINE_MODE_CHIP_NAME,
637 NUM_LINE_MODES,
638};
639
640static inline int strmatch(const char *a, const char *b)
641{
642 return strnicmp(a, b, strlen(b)) == 0;
643}
644
645/* parse the contents after the line "[codec]"
646 * accept only the line with three numbers, and assign the current codec
647 */
648static void parse_codec_mode(char *buf, struct hda_bus *bus,
649 struct hda_codec **codecp)
650{
651 int vendorid, subid, caddr;
652 struct hda_codec *codec;
653
654 *codecp = NULL;
655 if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
656 list_for_each_entry(codec, &bus->codec_list, list) {
657 if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
658 (subid <= 0 || codec->subsystem_id == subid) &&
659 codec->addr == caddr) {
660 *codecp = codec;
661 break;
662 }
663 }
664 }
665}
666
667/* parse the contents after the other command tags, [pincfg], [verb],
668 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
669 * just pass to the sysfs helper (only when any codec was specified)
670 */
671static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
672 struct hda_codec **codecp)
673{
674 parse_user_pin_configs(*codecp, buf);
675}
676
677static void parse_verb_mode(char *buf, struct hda_bus *bus,
678 struct hda_codec **codecp)
679{
680 parse_init_verbs(*codecp, buf);
681}
682
683static void parse_hint_mode(char *buf, struct hda_bus *bus,
684 struct hda_codec **codecp)
685{
686 parse_hints(*codecp, buf);
687}
688
689static void parse_model_mode(char *buf, struct hda_bus *bus,
690 struct hda_codec **codecp)
691{
692 kfree((*codecp)->modelname);
693 (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
694}
695
696static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
697 struct hda_codec **codecp)
698{
699 kfree((*codecp)->chip_name);
700 (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
701}
702
703#define DEFINE_PARSE_ID_MODE(name) \
704static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
705 struct hda_codec **codecp) \
706{ \
707 unsigned long val; \
708 if (!kstrtoul(buf, 0, &val)) \
709 (*codecp)->name = val; \
710}
711
712DEFINE_PARSE_ID_MODE(vendor_id);
713DEFINE_PARSE_ID_MODE(subsystem_id);
714DEFINE_PARSE_ID_MODE(revision_id);
715
716
717struct hda_patch_item {
718 const char *tag;
719 const char *alias;
720 void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
721};
722
723static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
724 [LINE_MODE_CODEC] = {
725 .tag = "[codec]",
726 .parser = parse_codec_mode,
727 },
728 [LINE_MODE_MODEL] = {
729 .tag = "[model]",
730 .parser = parse_model_mode,
731 },
732 [LINE_MODE_VERB] = {
733 .tag = "[verb]",
734 .alias = "[init_verbs]",
735 .parser = parse_verb_mode,
736 },
737 [LINE_MODE_PINCFG] = {
738 .tag = "[pincfg]",
739 .alias = "[user_pin_configs]",
740 .parser = parse_pincfg_mode,
741 },
742 [LINE_MODE_HINT] = {
743 .tag = "[hint]",
744 .alias = "[hints]",
745 .parser = parse_hint_mode
746 },
747 [LINE_MODE_VENDOR_ID] = {
748 .tag = "[vendor_id]",
749 .parser = parse_vendor_id_mode,
750 },
751 [LINE_MODE_SUBSYSTEM_ID] = {
752 .tag = "[subsystem_id]",
753 .parser = parse_subsystem_id_mode,
754 },
755 [LINE_MODE_REVISION_ID] = {
756 .tag = "[revision_id]",
757 .parser = parse_revision_id_mode,
758 },
759 [LINE_MODE_CHIP_NAME] = {
760 .tag = "[chip_name]",
761 .parser = parse_chip_name_mode,
762 },
763};
764
765/* check the line starting with '[' -- change the parser mode accodingly */
766static int parse_line_mode(char *buf, struct hda_bus *bus)
767{
768 int i;
769 for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
770 if (!patch_items[i].tag)
771 continue;
772 if (strmatch(buf, patch_items[i].tag))
773 return i;
774 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
775 return i;
776 }
777 return LINE_MODE_NONE;
778}
779
780/* copy one line from the buffer in fw, and update the fields in fw
781 * return zero if it reaches to the end of the buffer, or non-zero
782 * if successfully copied a line
783 *
784 * the spaces at the beginning and the end of the line are stripped
785 */
786static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
787 const void **fw_data_p)
788{
789 int len;
790 size_t fw_size = *fw_size_p;
791 const char *p = *fw_data_p;
792
793 while (isspace(*p) && fw_size) {
794 p++;
795 fw_size--;
796 }
797 if (!fw_size)
798 return 0;
799
800 for (len = 0; len < fw_size; len++) {
801 if (!*p)
802 break;
803 if (*p == '\n') {
804 p++;
805 len++;
806 break;
807 }
808 if (len < size)
809 *buf++ = *p++;
810 }
811 *buf = 0;
812 *fw_size_p = fw_size - len;
813 *fw_data_p = p;
814 remove_trail_spaces(buf);
815 return 1;
816}
817
818/*
819 * load a "patch" firmware file and parse it
820 */
821int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
822{
823 char buf[128];
824 struct hda_codec *codec;
825 int line_mode;
826
827 line_mode = LINE_MODE_NONE;
828 codec = NULL;
829 while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
830 if (!*buf || *buf == '#' || *buf == '\n')
831 continue;
832 if (*buf == '[')
833 line_mode = parse_line_mode(buf, bus);
834 else if (patch_items[line_mode].parser &&
835 (codec || line_mode <= LINE_MODE_CODEC))
836 patch_items[line_mode].parser(buf, bus, &codec);
837 }
838 return 0;
839}
840EXPORT_SYMBOL_GPL(snd_hda_load_patch);
841#endif /* CONFIG_SND_HDA_PATCH_LOADER */
842
843/*
844 * sysfs entries
845 */
846static struct attribute *hda_dev_attrs[] = {
847#ifdef CONFIG_PM
848 &dev_attr_power_on_acct.attr,
849 &dev_attr_power_off_acct.attr,
850#endif
851#ifdef CONFIG_SND_HDA_RECONFIG
852 &dev_attr_vendor_id.attr,
853 &dev_attr_subsystem_id.attr,
854 &dev_attr_revision_id.attr,
855 &dev_attr_afg.attr,
856 &dev_attr_mfg.attr,
857 &dev_attr_vendor_name.attr,
858 &dev_attr_chip_name.attr,
859 &dev_attr_modelname.attr,
860 &dev_attr_init_verbs.attr,
861 &dev_attr_hints.attr,
862 &dev_attr_init_pin_configs.attr,
863 &dev_attr_user_pin_configs.attr,
864 &dev_attr_driver_pin_configs.attr,
865 &dev_attr_reconfig.attr,
866 &dev_attr_clear.attr,
867#endif
868 NULL
869};
870
871static struct attribute_group hda_dev_attr_group = {
872 .attrs = hda_dev_attrs,
873};
874
875static const struct attribute_group *snd_hda_dev_attr_groups[] = {
876 &hda_dev_attr_group,
877 NULL
878};
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 31545923f6ac..a489243f243b 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -597,6 +597,11 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
597static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } 597static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
598#endif 598#endif
599 599
600void snd_hda_sysfs_init(struct hda_codec *codec);
601void snd_hda_sysfs_clear(struct hda_codec *codec);
602
603extern const struct attribute_group *snd_hda_dev_attr_groups[];
604
600#ifdef CONFIG_SND_HDA_RECONFIG 605#ifdef CONFIG_SND_HDA_RECONFIG
601const char *snd_hda_get_hint(struct hda_codec *codec, const char *key); 606const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
602int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key); 607int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
new file mode 100644
index 000000000000..c92ac267f5af
--- /dev/null
+++ b/sound/pci/hda/hda_sysfs.c
@@ -0,0 +1,769 @@
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#ifdef CONFIG_SND_HDA_RECONFIG
52
53/*
54 * sysfs interface
55 */
56
57static int clear_codec(struct hda_codec *codec)
58{
59 int err;
60
61 err = snd_hda_codec_reset(codec);
62 if (err < 0) {
63 snd_printk(KERN_ERR "The codec is being used, can't free.\n");
64 return err;
65 }
66 snd_hda_sysfs_clear(codec);
67 return 0;
68}
69
70static int reconfig_codec(struct hda_codec *codec)
71{
72 int err;
73
74 snd_hda_power_up(codec);
75 snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
76 err = snd_hda_codec_reset(codec);
77 if (err < 0) {
78 snd_printk(KERN_ERR
79 "The codec is being used, can't reconfigure.\n");
80 goto error;
81 }
82 err = snd_hda_codec_configure(codec);
83 if (err < 0)
84 goto error;
85 /* rebuild PCMs */
86 err = snd_hda_codec_build_pcms(codec);
87 if (err < 0)
88 goto error;
89 /* rebuild mixers */
90 err = snd_hda_codec_build_controls(codec);
91 if (err < 0)
92 goto error;
93 err = snd_card_register(codec->bus->card);
94 error:
95 snd_hda_power_down(codec);
96 return err;
97}
98
99/*
100 * allocate a string at most len chars, and remove the trailing EOL
101 */
102static char *kstrndup_noeol(const char *src, size_t len)
103{
104 char *s = kstrndup(src, len, GFP_KERNEL);
105 char *p;
106 if (!s)
107 return NULL;
108 p = strchr(s, '\n');
109 if (p)
110 *p = 0;
111 return s;
112}
113
114#define CODEC_INFO_SHOW(type) \
115static ssize_t type##_show(struct device *dev, \
116 struct device_attribute *attr, \
117 char *buf) \
118{ \
119 struct hda_codec *codec = dev_get_drvdata(dev); \
120 return sprintf(buf, "0x%x\n", codec->type); \
121}
122
123#define CODEC_INFO_STR_SHOW(type) \
124static ssize_t type##_show(struct device *dev, \
125 struct device_attribute *attr, \
126 char *buf) \
127{ \
128 struct hda_codec *codec = dev_get_drvdata(dev); \
129 return sprintf(buf, "%s\n", \
130 codec->type ? codec->type : ""); \
131}
132
133CODEC_INFO_SHOW(vendor_id);
134CODEC_INFO_SHOW(subsystem_id);
135CODEC_INFO_SHOW(revision_id);
136CODEC_INFO_SHOW(afg);
137CODEC_INFO_SHOW(mfg);
138CODEC_INFO_STR_SHOW(vendor_name);
139CODEC_INFO_STR_SHOW(chip_name);
140CODEC_INFO_STR_SHOW(modelname);
141
142#define CODEC_INFO_STORE(type) \
143static ssize_t type##_store(struct device *dev, \
144 struct device_attribute *attr, \
145 const char *buf, size_t count) \
146{ \
147 struct hda_codec *codec = dev_get_drvdata(dev); \
148 unsigned long val; \
149 int err = kstrtoul(buf, 0, &val); \
150 if (err < 0) \
151 return err; \
152 codec->type = val; \
153 return count; \
154}
155
156#define CODEC_INFO_STR_STORE(type) \
157static ssize_t type##_store(struct device *dev, \
158 struct device_attribute *attr, \
159 const char *buf, size_t count) \
160{ \
161 struct hda_codec *codec = dev_get_drvdata(dev); \
162 char *s = kstrndup_noeol(buf, 64); \
163 if (!s) \
164 return -ENOMEM; \
165 kfree(codec->type); \
166 codec->type = s; \
167 return count; \
168}
169
170CODEC_INFO_STORE(vendor_id);
171CODEC_INFO_STORE(subsystem_id);
172CODEC_INFO_STORE(revision_id);
173CODEC_INFO_STR_STORE(vendor_name);
174CODEC_INFO_STR_STORE(chip_name);
175CODEC_INFO_STR_STORE(modelname);
176
177#define CODEC_ACTION_STORE(type) \
178static ssize_t type##_store(struct device *dev, \
179 struct device_attribute *attr, \
180 const char *buf, size_t count) \
181{ \
182 struct hda_codec *codec = dev_get_drvdata(dev); \
183 int err = 0; \
184 if (*buf) \
185 err = type##_codec(codec); \
186 return err < 0 ? err : count; \
187}
188
189CODEC_ACTION_STORE(reconfig);
190CODEC_ACTION_STORE(clear);
191
192static ssize_t init_verbs_show(struct device *dev,
193 struct device_attribute *attr,
194 char *buf)
195{
196 struct hda_codec *codec = dev_get_drvdata(dev);
197 int i, len = 0;
198 mutex_lock(&codec->user_mutex);
199 for (i = 0; i < codec->init_verbs.used; i++) {
200 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
201 len += snprintf(buf + len, PAGE_SIZE - len,
202 "0x%02x 0x%03x 0x%04x\n",
203 v->nid, v->verb, v->param);
204 }
205 mutex_unlock(&codec->user_mutex);
206 return len;
207}
208
209static int parse_init_verbs(struct hda_codec *codec, const char *buf)
210{
211 struct hda_verb *v;
212 int nid, verb, param;
213
214 if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
215 return -EINVAL;
216 if (!nid || !verb)
217 return -EINVAL;
218 mutex_lock(&codec->user_mutex);
219 v = snd_array_new(&codec->init_verbs);
220 if (!v) {
221 mutex_unlock(&codec->user_mutex);
222 return -ENOMEM;
223 }
224 v->nid = nid;
225 v->verb = verb;
226 v->param = param;
227 mutex_unlock(&codec->user_mutex);
228 return 0;
229}
230
231static ssize_t init_verbs_store(struct device *dev,
232 struct device_attribute *attr,
233 const char *buf, size_t count)
234{
235 struct hda_codec *codec = dev_get_drvdata(dev);
236 int err = parse_init_verbs(codec, buf);
237 if (err < 0)
238 return err;
239 return count;
240}
241
242static ssize_t hints_show(struct device *dev,
243 struct device_attribute *attr,
244 char *buf)
245{
246 struct hda_codec *codec = dev_get_drvdata(dev);
247 int i, len = 0;
248 mutex_lock(&codec->user_mutex);
249 for (i = 0; i < codec->hints.used; i++) {
250 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
251 len += snprintf(buf + len, PAGE_SIZE - len,
252 "%s = %s\n", hint->key, hint->val);
253 }
254 mutex_unlock(&codec->user_mutex);
255 return len;
256}
257
258static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
259{
260 int i;
261
262 for (i = 0; i < codec->hints.used; i++) {
263 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
264 if (!strcmp(hint->key, key))
265 return hint;
266 }
267 return NULL;
268}
269
270static void remove_trail_spaces(char *str)
271{
272 char *p;
273 if (!*str)
274 return;
275 p = str + strlen(str) - 1;
276 for (; isspace(*p); p--) {
277 *p = 0;
278 if (p == str)
279 return;
280 }
281}
282
283#define MAX_HINTS 1024
284
285static int parse_hints(struct hda_codec *codec, const char *buf)
286{
287 char *key, *val;
288 struct hda_hint *hint;
289 int err = 0;
290
291 buf = skip_spaces(buf);
292 if (!*buf || *buf == '#' || *buf == '\n')
293 return 0;
294 if (*buf == '=')
295 return -EINVAL;
296 key = kstrndup_noeol(buf, 1024);
297 if (!key)
298 return -ENOMEM;
299 /* extract key and val */
300 val = strchr(key, '=');
301 if (!val) {
302 kfree(key);
303 return -EINVAL;
304 }
305 *val++ = 0;
306 val = skip_spaces(val);
307 remove_trail_spaces(key);
308 remove_trail_spaces(val);
309 mutex_lock(&codec->user_mutex);
310 hint = get_hint(codec, key);
311 if (hint) {
312 /* replace */
313 kfree(hint->key);
314 hint->key = key;
315 hint->val = val;
316 goto unlock;
317 }
318 /* allocate a new hint entry */
319 if (codec->hints.used >= MAX_HINTS)
320 hint = NULL;
321 else
322 hint = snd_array_new(&codec->hints);
323 if (hint) {
324 hint->key = key;
325 hint->val = val;
326 } else {
327 err = -ENOMEM;
328 }
329 unlock:
330 mutex_unlock(&codec->user_mutex);
331 if (err)
332 kfree(key);
333 return err;
334}
335
336static ssize_t hints_store(struct device *dev,
337 struct device_attribute *attr,
338 const char *buf, size_t count)
339{
340 struct hda_codec *codec = dev_get_drvdata(dev);
341 int err = parse_hints(codec, buf);
342 if (err < 0)
343 return err;
344 return count;
345}
346
347static ssize_t pin_configs_show(struct hda_codec *codec,
348 struct snd_array *list,
349 char *buf)
350{
351 int i, len = 0;
352 mutex_lock(&codec->user_mutex);
353 for (i = 0; i < list->used; i++) {
354 struct hda_pincfg *pin = snd_array_elem(list, i);
355 len += sprintf(buf + len, "0x%02x 0x%08x\n",
356 pin->nid, pin->cfg);
357 }
358 mutex_unlock(&codec->user_mutex);
359 return len;
360}
361
362static ssize_t init_pin_configs_show(struct device *dev,
363 struct device_attribute *attr,
364 char *buf)
365{
366 struct hda_codec *codec = dev_get_drvdata(dev);
367 return pin_configs_show(codec, &codec->init_pins, buf);
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 ssize_t driver_pin_configs_show(struct device *dev,
379 struct device_attribute *attr,
380 char *buf)
381{
382 struct hda_codec *codec = dev_get_drvdata(dev);
383 return pin_configs_show(codec, &codec->driver_pins, buf);
384}
385
386#define MAX_PIN_CONFIGS 32
387
388static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
389{
390 int nid, cfg, err;
391
392 if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
393 return -EINVAL;
394 if (!nid)
395 return -EINVAL;
396 mutex_lock(&codec->user_mutex);
397 err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
398 mutex_unlock(&codec->user_mutex);
399 return err;
400}
401
402static ssize_t user_pin_configs_store(struct device *dev,
403 struct device_attribute *attr,
404 const char *buf, size_t count)
405{
406 struct hda_codec *codec = dev_get_drvdata(dev);
407 int err = parse_user_pin_configs(codec, buf);
408 if (err < 0)
409 return err;
410 return count;
411}
412
413static DEVICE_ATTR_RW(vendor_id);
414static DEVICE_ATTR_RW(subsystem_id);
415static DEVICE_ATTR_RW(revision_id);
416static DEVICE_ATTR_RO(afg);
417static DEVICE_ATTR_RO(mfg);
418static DEVICE_ATTR_RW(vendor_name);
419static DEVICE_ATTR_RW(chip_name);
420static DEVICE_ATTR_RW(modelname);
421static DEVICE_ATTR_RW(init_verbs);
422static DEVICE_ATTR_RW(hints);
423static DEVICE_ATTR_RO(init_pin_configs);
424static DEVICE_ATTR_RW(user_pin_configs);
425static DEVICE_ATTR_RO(driver_pin_configs);
426static DEVICE_ATTR_WO(reconfig);
427static DEVICE_ATTR_WO(clear);
428
429/*
430 * Look for hint string
431 */
432const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
433{
434 struct hda_hint *hint = get_hint(codec, key);
435 return hint ? hint->val : NULL;
436}
437EXPORT_SYMBOL_GPL(snd_hda_get_hint);
438
439int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
440{
441 const char *p;
442 int ret;
443
444 mutex_lock(&codec->user_mutex);
445 p = snd_hda_get_hint(codec, key);
446 if (!p || !*p)
447 ret = -ENOENT;
448 else {
449 switch (toupper(*p)) {
450 case 'T': /* true */
451 case 'Y': /* yes */
452 case '1':
453 ret = 1;
454 break;
455 default:
456 ret = 0;
457 break;
458 }
459 }
460 mutex_unlock(&codec->user_mutex);
461 return ret;
462}
463EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
464
465int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
466{
467 const char *p;
468 unsigned long val;
469 int ret;
470
471 mutex_lock(&codec->user_mutex);
472 p = snd_hda_get_hint(codec, key);
473 if (!p)
474 ret = -ENOENT;
475 else if (kstrtoul(p, 0, &val))
476 ret = -EINVAL;
477 else {
478 *valp = val;
479 ret = 0;
480 }
481 mutex_unlock(&codec->user_mutex);
482 return ret;
483}
484EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
485#endif /* CONFIG_SND_HDA_RECONFIG */
486
487#ifdef CONFIG_SND_HDA_PATCH_LOADER
488
489/* parser mode */
490enum {
491 LINE_MODE_NONE,
492 LINE_MODE_CODEC,
493 LINE_MODE_MODEL,
494 LINE_MODE_PINCFG,
495 LINE_MODE_VERB,
496 LINE_MODE_HINT,
497 LINE_MODE_VENDOR_ID,
498 LINE_MODE_SUBSYSTEM_ID,
499 LINE_MODE_REVISION_ID,
500 LINE_MODE_CHIP_NAME,
501 NUM_LINE_MODES,
502};
503
504static inline int strmatch(const char *a, const char *b)
505{
506 return strnicmp(a, b, strlen(b)) == 0;
507}
508
509/* parse the contents after the line "[codec]"
510 * accept only the line with three numbers, and assign the current codec
511 */
512static void parse_codec_mode(char *buf, struct hda_bus *bus,
513 struct hda_codec **codecp)
514{
515 int vendorid, subid, caddr;
516 struct hda_codec *codec;
517
518 *codecp = NULL;
519 if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
520 list_for_each_entry(codec, &bus->codec_list, list) {
521 if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
522 (subid <= 0 || codec->subsystem_id == subid) &&
523 codec->addr == caddr) {
524 *codecp = codec;
525 break;
526 }
527 }
528 }
529}
530
531/* parse the contents after the other command tags, [pincfg], [verb],
532 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
533 * just pass to the sysfs helper (only when any codec was specified)
534 */
535static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
536 struct hda_codec **codecp)
537{
538 parse_user_pin_configs(*codecp, buf);
539}
540
541static void parse_verb_mode(char *buf, struct hda_bus *bus,
542 struct hda_codec **codecp)
543{
544 parse_init_verbs(*codecp, buf);
545}
546
547static void parse_hint_mode(char *buf, struct hda_bus *bus,
548 struct hda_codec **codecp)
549{
550 parse_hints(*codecp, buf);
551}
552
553static void parse_model_mode(char *buf, struct hda_bus *bus,
554 struct hda_codec **codecp)
555{
556 kfree((*codecp)->modelname);
557 (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
558}
559
560static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
561 struct hda_codec **codecp)
562{
563 kfree((*codecp)->chip_name);
564 (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
565}
566
567#define DEFINE_PARSE_ID_MODE(name) \
568static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
569 struct hda_codec **codecp) \
570{ \
571 unsigned long val; \
572 if (!kstrtoul(buf, 0, &val)) \
573 (*codecp)->name = val; \
574}
575
576DEFINE_PARSE_ID_MODE(vendor_id);
577DEFINE_PARSE_ID_MODE(subsystem_id);
578DEFINE_PARSE_ID_MODE(revision_id);
579
580
581struct hda_patch_item {
582 const char *tag;
583 const char *alias;
584 void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
585};
586
587static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
588 [LINE_MODE_CODEC] = {
589 .tag = "[codec]",
590 .parser = parse_codec_mode,
591 },
592 [LINE_MODE_MODEL] = {
593 .tag = "[model]",
594 .parser = parse_model_mode,
595 },
596 [LINE_MODE_VERB] = {
597 .tag = "[verb]",
598 .alias = "[init_verbs]",
599 .parser = parse_verb_mode,
600 },
601 [LINE_MODE_PINCFG] = {
602 .tag = "[pincfg]",
603 .alias = "[user_pin_configs]",
604 .parser = parse_pincfg_mode,
605 },
606 [LINE_MODE_HINT] = {
607 .tag = "[hint]",
608 .alias = "[hints]",
609 .parser = parse_hint_mode
610 },
611 [LINE_MODE_VENDOR_ID] = {
612 .tag = "[vendor_id]",
613 .parser = parse_vendor_id_mode,
614 },
615 [LINE_MODE_SUBSYSTEM_ID] = {
616 .tag = "[subsystem_id]",
617 .parser = parse_subsystem_id_mode,
618 },
619 [LINE_MODE_REVISION_ID] = {
620 .tag = "[revision_id]",
621 .parser = parse_revision_id_mode,
622 },
623 [LINE_MODE_CHIP_NAME] = {
624 .tag = "[chip_name]",
625 .parser = parse_chip_name_mode,
626 },
627};
628
629/* check the line starting with '[' -- change the parser mode accodingly */
630static int parse_line_mode(char *buf, struct hda_bus *bus)
631{
632 int i;
633 for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
634 if (!patch_items[i].tag)
635 continue;
636 if (strmatch(buf, patch_items[i].tag))
637 return i;
638 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
639 return i;
640 }
641 return LINE_MODE_NONE;
642}
643
644/* copy one line from the buffer in fw, and update the fields in fw
645 * return zero if it reaches to the end of the buffer, or non-zero
646 * if successfully copied a line
647 *
648 * the spaces at the beginning and the end of the line are stripped
649 */
650static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
651 const void **fw_data_p)
652{
653 int len;
654 size_t fw_size = *fw_size_p;
655 const char *p = *fw_data_p;
656
657 while (isspace(*p) && fw_size) {
658 p++;
659 fw_size--;
660 }
661 if (!fw_size)
662 return 0;
663
664 for (len = 0; len < fw_size; len++) {
665 if (!*p)
666 break;
667 if (*p == '\n') {
668 p++;
669 len++;
670 break;
671 }
672 if (len < size)
673 *buf++ = *p++;
674 }
675 *buf = 0;
676 *fw_size_p = fw_size - len;
677 *fw_data_p = p;
678 remove_trail_spaces(buf);
679 return 1;
680}
681
682/*
683 * load a "patch" firmware file and parse it
684 */
685int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
686{
687 char buf[128];
688 struct hda_codec *codec;
689 int line_mode;
690
691 line_mode = LINE_MODE_NONE;
692 codec = NULL;
693 while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
694 if (!*buf || *buf == '#' || *buf == '\n')
695 continue;
696 if (*buf == '[')
697 line_mode = parse_line_mode(buf, bus);
698 else if (patch_items[line_mode].parser &&
699 (codec || line_mode <= LINE_MODE_CODEC))
700 patch_items[line_mode].parser(buf, bus, &codec);
701 }
702 return 0;
703}
704EXPORT_SYMBOL_GPL(snd_hda_load_patch);
705#endif /* CONFIG_SND_HDA_PATCH_LOADER */
706
707/*
708 * sysfs entries
709 */
710static struct attribute *hda_dev_attrs[] = {
711#ifdef CONFIG_PM
712 &dev_attr_power_on_acct.attr,
713 &dev_attr_power_off_acct.attr,
714#endif
715#ifdef CONFIG_SND_HDA_RECONFIG
716 &dev_attr_vendor_id.attr,
717 &dev_attr_subsystem_id.attr,
718 &dev_attr_revision_id.attr,
719 &dev_attr_afg.attr,
720 &dev_attr_mfg.attr,
721 &dev_attr_vendor_name.attr,
722 &dev_attr_chip_name.attr,
723 &dev_attr_modelname.attr,
724 &dev_attr_init_verbs.attr,
725 &dev_attr_hints.attr,
726 &dev_attr_init_pin_configs.attr,
727 &dev_attr_user_pin_configs.attr,
728 &dev_attr_driver_pin_configs.attr,
729 &dev_attr_reconfig.attr,
730 &dev_attr_clear.attr,
731#endif
732 NULL
733};
734
735static struct attribute_group hda_dev_attr_group = {
736 .attrs = hda_dev_attrs,
737};
738
739const struct attribute_group *snd_hda_dev_attr_groups[] = {
740 &hda_dev_attr_group,
741 NULL
742};
743
744void snd_hda_sysfs_init(struct hda_codec *codec)
745{
746#ifdef CONFIG_SND_HDA_RECONFIG
747 mutex_init(&codec->user_mutex);
748 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
749 snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
750 snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
751#endif
752}
753
754void snd_hda_sysfs_clear(struct hda_codec *codec)
755{
756#ifdef CONFIG_SND_HDA_RECONFIG
757 int i;
758
759 /* clear init verbs */
760 snd_array_free(&codec->init_verbs);
761 /* clear hints */
762 for (i = 0; i < codec->hints.used; i++) {
763 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
764 kfree(hint->key); /* we don't need to free hint->val */
765 }
766 snd_array_free(&codec->hints);
767 snd_array_free(&codec->user_pins);
768#endif
769}