~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/hda/hda_sysfs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php