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