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