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