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 *val; 303 struct hda_hint *hint; 304 305 buf = skip_spaces(buf); 306 if (!*buf || *buf == '#' || *buf == '\n') 307 return 0; 308 if (*buf == '=') 309 return -EINVAL; 310 311 char *key __free(kfree) = 312 kstrndup_noeol(buf, 1024); 313 if (!key) 314 return -ENOMEM; 315 /* extract key and val */ 316 val = strchr(key, '='); 317 if (!val) 318 return -EINVAL; 319 *val++ = 0; 320 val = skip_spaces(val); 321 remove_trail_spaces(key); 322 remove_trail_spaces(val); 323 guard(mutex)(&codec->user_mutex); 324 hint = get_hint(codec, key); 325 if (hint) { 326 /* replace */ 327 kfree(hint->key); 328 goto replace; 329 } 330 /* allocate a new hint entry */ 331 if (codec->hints.used >= MAX_HINTS) 332 return -ENOMEM; 333 hint = snd_array_new(&codec->hints); 334 if (!hint) 335 return -ENOMEM; 336 replace: 337 hint->key = no_free_ptr(key); 338 hint->val = val; 339 return 0; 340 } 341 342 static ssize_t hints_store(struct device *dev, 343 struct device_attribute *attr, 344 const char *buf, size_t count) 345 { 346 struct hda_codec *codec = dev_get_drvdata(dev); 347 int err = parse_hints(codec, buf); 348 if (err < 0) 349 return err; 350 return count; 351 } 352 353 static ssize_t user_pin_configs_show(struct device *dev, 354 struct device_attribute *attr, 355 char *buf) 356 { 357 struct hda_codec *codec = dev_get_drvdata(dev); 358 return pin_configs_show(codec, &codec->user_pins, buf); 359 } 360 361 static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) 362 { 363 int nid, cfg; 364 365 if (sscanf(buf, "%i %i", &nid, &cfg) != 2) 366 return -EINVAL; 367 if (!nid) 368 return -EINVAL; 369 guard(mutex)(&codec->user_mutex); 370 return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); 371 } 372 373 static ssize_t user_pin_configs_store(struct device *dev, 374 struct device_attribute *attr, 375 const char *buf, size_t count) 376 { 377 struct hda_codec *codec = dev_get_drvdata(dev); 378 int err = parse_user_pin_configs(codec, buf); 379 if (err < 0) 380 return err; 381 return count; 382 } 383 384 /* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */ 385 static DEVICE_ATTR_RW(init_verbs); 386 static DEVICE_ATTR_RW(hints); 387 static DEVICE_ATTR_RW(user_pin_configs); 388 static DEVICE_ATTR_WO(reconfig); 389 static DEVICE_ATTR_WO(clear); 390 391 /** 392 * snd_hda_get_hint - Look for hint string 393 * @codec: the HDA codec 394 * @key: the hint key string 395 * 396 * Look for a hint key/value pair matching with the given key string 397 * and returns the value string. If nothing found, returns NULL. 398 */ 399 const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) 400 { 401 struct hda_hint *hint = get_hint(codec, key); 402 return hint ? hint->val : NULL; 403 } 404 EXPORT_SYMBOL_GPL(snd_hda_get_hint); 405 406 /** 407 * snd_hda_get_bool_hint - Get a boolean hint value 408 * @codec: the HDA codec 409 * @key: the hint key string 410 * 411 * Look for a hint key/value pair matching with the given key string 412 * and returns a boolean value parsed from the value. If no matching 413 * key is found, return a negative value. 414 */ 415 int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) 416 { 417 const char *p; 418 419 guard(mutex)(&codec->user_mutex); 420 p = snd_hda_get_hint(codec, key); 421 if (!p || !*p) 422 return -ENOENT; 423 switch (toupper(*p)) { 424 case 'T': /* true */ 425 case 'Y': /* yes */ 426 case '1': 427 return 1; 428 default: 429 return 0; 430 } 431 } 432 EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint); 433 434 /** 435 * snd_hda_get_int_hint - Get an integer hint value 436 * @codec: the HDA codec 437 * @key: the hint key string 438 * @valp: pointer to store a value 439 * 440 * Look for a hint key/value pair matching with the given key string 441 * and stores the integer value to @valp. If no matching key is found, 442 * return a negative error code. Otherwise it returns zero. 443 */ 444 int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) 445 { 446 const char *p; 447 unsigned long val; 448 449 guard(mutex)(&codec->user_mutex); 450 p = snd_hda_get_hint(codec, key); 451 if (!p) 452 return -ENOENT; 453 else if (kstrtoul(p, 0, &val)) 454 return -EINVAL; 455 else { 456 *valp = val; 457 return 0; 458 } 459 } 460 EXPORT_SYMBOL_GPL(snd_hda_get_int_hint); 461 #endif /* CONFIG_SND_HDA_RECONFIG */ 462 463 /* 464 * common sysfs attributes 465 */ 466 #ifdef CONFIG_SND_HDA_RECONFIG 467 #define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RW(name) 468 #else 469 #define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RO(name) 470 #endif 471 static RECONFIG_DEVICE_ATTR(vendor_id); 472 static RECONFIG_DEVICE_ATTR(subsystem_id); 473 static RECONFIG_DEVICE_ATTR(revision_id); 474 static DEVICE_ATTR_RO(afg); 475 static DEVICE_ATTR_RO(mfg); 476 static RECONFIG_DEVICE_ATTR(vendor_name); 477 static RECONFIG_DEVICE_ATTR(chip_name); 478 static RECONFIG_DEVICE_ATTR(modelname); 479 static DEVICE_ATTR_RO(init_pin_configs); 480 static DEVICE_ATTR_RO(driver_pin_configs); 481 482 483 #ifdef CONFIG_SND_HDA_PATCH_LOADER 484 485 /* parser mode */ 486 enum { 487 LINE_MODE_NONE, 488 LINE_MODE_CODEC, 489 LINE_MODE_MODEL, 490 LINE_MODE_PINCFG, 491 LINE_MODE_VERB, 492 LINE_MODE_HINT, 493 LINE_MODE_VENDOR_ID, 494 LINE_MODE_SUBSYSTEM_ID, 495 LINE_MODE_REVISION_ID, 496 LINE_MODE_CHIP_NAME, 497 NUM_LINE_MODES, 498 }; 499 500 static inline int strmatch(const char *a, const char *b) 501 { 502 return strncasecmp(a, b, strlen(b)) == 0; 503 } 504 505 /* parse the contents after the line "[codec]" 506 * accept only the line with three numbers, and assign the current codec 507 */ 508 static void parse_codec_mode(char *buf, struct hda_bus *bus, 509 struct hda_codec **codecp) 510 { 511 int vendorid, subid, caddr; 512 struct hda_codec *codec; 513 514 *codecp = NULL; 515 if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { 516 list_for_each_codec(codec, bus) { 517 if ((vendorid <= 0 || codec->core.vendor_id == vendorid) && 518 (subid <= 0 || codec->core.subsystem_id == subid) && 519 codec->core.addr == caddr) { 520 *codecp = codec; 521 break; 522 } 523 } 524 } 525 } 526 527 /* parse the contents after the other command tags, [pincfg], [verb], 528 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model] 529 * just pass to the sysfs helper (only when any codec was specified) 530 */ 531 static void parse_pincfg_mode(char *buf, struct hda_bus *bus, 532 struct hda_codec **codecp) 533 { 534 parse_user_pin_configs(*codecp, buf); 535 } 536 537 static void parse_verb_mode(char *buf, struct hda_bus *bus, 538 struct hda_codec **codecp) 539 { 540 parse_init_verbs(*codecp, buf); 541 } 542 543 static void parse_hint_mode(char *buf, struct hda_bus *bus, 544 struct hda_codec **codecp) 545 { 546 parse_hints(*codecp, buf); 547 } 548 549 static void parse_model_mode(char *buf, struct hda_bus *bus, 550 struct hda_codec **codecp) 551 { 552 kfree((*codecp)->modelname); 553 (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); 554 } 555 556 static void parse_chip_name_mode(char *buf, struct hda_bus *bus, 557 struct hda_codec **codecp) 558 { 559 snd_hda_codec_set_name(*codecp, buf); 560 } 561 562 #define DEFINE_PARSE_ID_MODE(name) \ 563 static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ 564 struct hda_codec **codecp) \ 565 { \ 566 unsigned long val; \ 567 if (!kstrtoul(buf, 0, &val)) \ 568 (*codecp)->core.name = val; \ 569 } 570 571 DEFINE_PARSE_ID_MODE(vendor_id); 572 DEFINE_PARSE_ID_MODE(subsystem_id); 573 DEFINE_PARSE_ID_MODE(revision_id); 574 575 576 struct hda_patch_item { 577 const char *tag; 578 const char *alias; 579 void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); 580 }; 581 582 static const struct hda_patch_item patch_items[NUM_LINE_MODES] = { 583 [LINE_MODE_CODEC] = { 584 .tag = "[codec]", 585 .parser = parse_codec_mode, 586 }, 587 [LINE_MODE_MODEL] = { 588 .tag = "[model]", 589 .parser = parse_model_mode, 590 }, 591 [LINE_MODE_VERB] = { 592 .tag = "[verb]", 593 .alias = "[init_verbs]", 594 .parser = parse_verb_mode, 595 }, 596 [LINE_MODE_PINCFG] = { 597 .tag = "[pincfg]", 598 .alias = "[user_pin_configs]", 599 .parser = parse_pincfg_mode, 600 }, 601 [LINE_MODE_HINT] = { 602 .tag = "[hint]", 603 .alias = "[hints]", 604 .parser = parse_hint_mode 605 }, 606 [LINE_MODE_VENDOR_ID] = { 607 .tag = "[vendor_id]", 608 .parser = parse_vendor_id_mode, 609 }, 610 [LINE_MODE_SUBSYSTEM_ID] = { 611 .tag = "[subsystem_id]", 612 .parser = parse_subsystem_id_mode, 613 }, 614 [LINE_MODE_REVISION_ID] = { 615 .tag = "[revision_id]", 616 .parser = parse_revision_id_mode, 617 }, 618 [LINE_MODE_CHIP_NAME] = { 619 .tag = "[chip_name]", 620 .parser = parse_chip_name_mode, 621 }, 622 }; 623 624 /* check the line starting with '[' -- change the parser mode accordingly */ 625 static int parse_line_mode(char *buf, struct hda_bus *bus) 626 { 627 int i; 628 for (i = 0; i < ARRAY_SIZE(patch_items); i++) { 629 if (!patch_items[i].tag) 630 continue; 631 if (strmatch(buf, patch_items[i].tag)) 632 return i; 633 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias)) 634 return i; 635 } 636 return LINE_MODE_NONE; 637 } 638 639 /* copy one line from the buffer in fw, and update the fields in fw 640 * return zero if it reaches to the end of the buffer, or non-zero 641 * if successfully copied a line 642 * 643 * the spaces at the beginning and the end of the line are stripped 644 */ 645 static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, 646 const void **fw_data_p) 647 { 648 int len; 649 size_t fw_size = *fw_size_p; 650 const char *p = *fw_data_p; 651 652 while (isspace(*p) && fw_size) { 653 p++; 654 fw_size--; 655 } 656 if (!fw_size) 657 return 0; 658 659 for (len = 0; len < fw_size; len++) { 660 if (!*p) 661 break; 662 if (*p == '\n') { 663 p++; 664 len++; 665 break; 666 } 667 if (len < size) 668 *buf++ = *p++; 669 } 670 *buf = 0; 671 *fw_size_p = fw_size - len; 672 *fw_data_p = p; 673 remove_trail_spaces(buf); 674 return 1; 675 } 676 677 /** 678 * snd_hda_load_patch - load a "patch" firmware file and parse it 679 * @bus: HD-audio bus 680 * @fw_size: the firmware byte size 681 * @fw_buf: the firmware data 682 */ 683 int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) 684 { 685 char buf[128]; 686 struct hda_codec *codec; 687 int line_mode; 688 689 line_mode = LINE_MODE_NONE; 690 codec = NULL; 691 while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) { 692 if (!*buf || *buf == '#' || *buf == '\n') 693 continue; 694 if (*buf == '[') 695 line_mode = parse_line_mode(buf, bus); 696 else if (patch_items[line_mode].parser && 697 (codec || line_mode <= LINE_MODE_CODEC)) 698 patch_items[line_mode].parser(buf, bus, &codec); 699 } 700 return 0; 701 } 702 EXPORT_SYMBOL_GPL(snd_hda_load_patch); 703 #endif /* CONFIG_SND_HDA_PATCH_LOADER */ 704 705 /* 706 * sysfs entries 707 */ 708 static struct attribute *hda_dev_attrs[] = { 709 &dev_attr_vendor_id.attr, 710 &dev_attr_subsystem_id.attr, 711 &dev_attr_revision_id.attr, 712 &dev_attr_afg.attr, 713 &dev_attr_mfg.attr, 714 &dev_attr_vendor_name.attr, 715 &dev_attr_chip_name.attr, 716 &dev_attr_modelname.attr, 717 &dev_attr_init_pin_configs.attr, 718 &dev_attr_driver_pin_configs.attr, 719 &dev_attr_power_on_acct.attr, 720 &dev_attr_power_off_acct.attr, 721 #ifdef CONFIG_SND_HDA_RECONFIG 722 &dev_attr_init_verbs.attr, 723 &dev_attr_hints.attr, 724 &dev_attr_user_pin_configs.attr, 725 &dev_attr_reconfig.attr, 726 &dev_attr_clear.attr, 727 #endif 728 NULL 729 }; 730 731 static const struct attribute_group hda_dev_attr_group = { 732 .attrs = hda_dev_attrs, 733 }; 734 735 const struct attribute_group *snd_hda_dev_attr_groups[] = { 736 &hda_dev_attr_group, 737 NULL 738 }; 739 740 void snd_hda_sysfs_init(struct hda_codec *codec) 741 { 742 mutex_init(&codec->user_mutex); 743 #ifdef CONFIG_SND_HDA_RECONFIG 744 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); 745 snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); 746 snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); 747 #endif 748 } 749 750 void snd_hda_sysfs_clear(struct hda_codec *codec) 751 { 752 #ifdef CONFIG_SND_HDA_RECONFIG 753 struct hda_hint *hint; 754 int i; 755 756 /* clear init verbs */ 757 snd_array_free(&codec->init_verbs); 758 /* clear hints */ 759 snd_array_for_each(&codec->hints, i, hint) { 760 kfree(hint->key); /* we don't need to free hint->val */ 761 } 762 snd_array_free(&codec->hints); 763 snd_array_free(&codec->user_pins); 764 #endif 765 } 766