Branch data Line data Source code
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 */
24 : : struct hda_hint {
25 : : const char *key;
26 : : const char *val; /* contained in the same alloc as key */
27 : : };
28 : :
29 : : #ifdef CONFIG_PM
30 : 0 : static ssize_t power_on_acct_show(struct device *dev,
31 : : struct device_attribute *attr,
32 : : char *buf)
33 : : {
34 : 0 : struct hda_codec *codec = dev_get_drvdata(dev);
35 : 0 : snd_hda_update_power_acct(codec);
36 : 0 : return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
37 : : }
38 : :
39 : 0 : static ssize_t power_off_acct_show(struct device *dev,
40 : : struct device_attribute *attr,
41 : : char *buf)
42 : : {
43 : 0 : struct hda_codec *codec = dev_get_drvdata(dev);
44 : 0 : snd_hda_update_power_acct(codec);
45 : 0 : return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
46 : : }
47 : :
48 : : static DEVICE_ATTR_RO(power_on_acct);
49 : : static DEVICE_ATTR_RO(power_off_acct);
50 : : #endif /* CONFIG_PM */
51 : :
52 : : #define CODEC_INFO_SHOW(type, field) \
53 : : static 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) \
62 : : static 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 : :
71 : 0 : CODEC_INFO_SHOW(vendor_id, core.vendor_id);
72 : 0 : CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
73 : 0 : CODEC_INFO_SHOW(revision_id, core.revision_id);
74 : 0 : CODEC_INFO_SHOW(afg, core.afg);
75 : 0 : CODEC_INFO_SHOW(mfg, core.mfg);
76 [ # # ]: 0 : CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
77 [ # # ]: 0 : CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
78 [ # # ]: 0 : CODEC_INFO_STR_SHOW(modelname, modelname);
79 : :
80 : 0 : static ssize_t pin_configs_show(struct hda_codec *codec,
81 : : struct snd_array *list,
82 : : char *buf)
83 : : {
84 : 0 : const struct hda_pincfg *pin;
85 : 0 : int i, len = 0;
86 : 0 : mutex_lock(&codec->user_mutex);
87 [ # # ]: 0 : snd_array_for_each(list, i, pin) {
88 : 0 : len += sprintf(buf + len, "0x%02x 0x%08x\n",
89 : 0 : pin->nid, pin->cfg);
90 : : }
91 : 0 : mutex_unlock(&codec->user_mutex);
92 : 0 : return len;
93 : : }
94 : :
95 : 0 : static ssize_t init_pin_configs_show(struct device *dev,
96 : : struct device_attribute *attr,
97 : : char *buf)
98 : : {
99 : 0 : struct hda_codec *codec = dev_get_drvdata(dev);
100 : 0 : return pin_configs_show(codec, &codec->init_pins, buf);
101 : : }
102 : :
103 : 0 : static ssize_t driver_pin_configs_show(struct device *dev,
104 : : struct device_attribute *attr,
105 : : char *buf)
106 : : {
107 : 0 : struct hda_codec *codec = dev_get_drvdata(dev);
108 : 0 : return pin_configs_show(codec, &codec->driver_pins, buf);
109 : : }
110 : :
111 : : #ifdef CONFIG_SND_HDA_RECONFIG
112 : :
113 : : /*
114 : : * sysfs interface
115 : : */
116 : :
117 : : static 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 : :
130 : : static 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 : : */
154 : : static 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) \
167 : : static 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) \
181 : : static 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 : :
194 : : CODEC_INFO_STORE(vendor_id, core.vendor_id);
195 : : CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
196 : : CODEC_INFO_STORE(revision_id, core.revision_id);
197 : : CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
198 : : CODEC_INFO_STR_STORE(chip_name, core.chip_name);
199 : : CODEC_INFO_STR_STORE(modelname, modelname);
200 : :
201 : : #define CODEC_ACTION_STORE(type) \
202 : : static 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 : :
213 : : CODEC_ACTION_STORE(reconfig);
214 : : CODEC_ACTION_STORE(clear);
215 : :
216 : : static 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 : :
233 : : static 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, ¶m) != 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 : :
255 : : static 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 : :
266 : : static 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 : :
282 : : static 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 : :
294 : : static 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 : :
309 : : static 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 : :
360 : : static 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 : :
371 : : static 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 : :
381 : : static 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 : :
395 : : static 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 */
407 : : static DEVICE_ATTR_RW(init_verbs);
408 : : static DEVICE_ATTR_RW(hints);
409 : : static DEVICE_ATTR_RW(user_pin_configs);
410 : : static DEVICE_ATTR_WO(reconfig);
411 : : static 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 : : */
421 : : const 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 : : }
426 : : EXPORT_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 : : */
437 : : int 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 : : }
461 : : EXPORT_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 : : */
473 : : int 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 : : }
492 : : EXPORT_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
503 : : static RECONFIG_DEVICE_ATTR(vendor_id);
504 : : static RECONFIG_DEVICE_ATTR(subsystem_id);
505 : : static RECONFIG_DEVICE_ATTR(revision_id);
506 : : static DEVICE_ATTR_RO(afg);
507 : : static DEVICE_ATTR_RO(mfg);
508 : : static RECONFIG_DEVICE_ATTR(vendor_name);
509 : : static RECONFIG_DEVICE_ATTR(chip_name);
510 : : static RECONFIG_DEVICE_ATTR(modelname);
511 : : static DEVICE_ATTR_RO(init_pin_configs);
512 : : static DEVICE_ATTR_RO(driver_pin_configs);
513 : :
514 : :
515 : : #ifdef CONFIG_SND_HDA_PATCH_LOADER
516 : :
517 : : /* parser mode */
518 : : enum {
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 : :
532 : : static 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 : : */
540 : : static 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 : : */
563 : : static 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 : :
569 : : static void parse_verb_mode(char *buf, struct hda_bus *bus,
570 : : struct hda_codec **codecp)
571 : : {
572 : : parse_init_verbs(*codecp, buf);
573 : : }
574 : :
575 : : static void parse_hint_mode(char *buf, struct hda_bus *bus,
576 : : struct hda_codec **codecp)
577 : : {
578 : : parse_hints(*codecp, buf);
579 : : }
580 : :
581 : : static 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 : :
588 : : static 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) \
595 : : static 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 : :
603 : : DEFINE_PARSE_ID_MODE(vendor_id);
604 : : DEFINE_PARSE_ID_MODE(subsystem_id);
605 : : DEFINE_PARSE_ID_MODE(revision_id);
606 : :
607 : :
608 : : struct 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 : :
614 : : static 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 */
657 : : static 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 : : */
677 : : static 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 : : */
715 : : int 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 : : }
734 : : EXPORT_SYMBOL_GPL(snd_hda_load_patch);
735 : : #endif /* CONFIG_SND_HDA_PATCH_LOADER */
736 : :
737 : : /*
738 : : * sysfs entries
739 : : */
740 : : static 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 : :
765 : : static const struct attribute_group hda_dev_attr_group = {
766 : : .attrs = hda_dev_attrs,
767 : : };
768 : :
769 : : const struct attribute_group *snd_hda_dev_attr_groups[] = {
770 : : &hda_dev_attr_group,
771 : : NULL
772 : : };
773 : :
774 : 0 : void snd_hda_sysfs_init(struct hda_codec *codec)
775 : : {
776 : 0 : 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 : 0 : }
783 : :
784 : 0 : void 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 : 0 : }
|