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, ¶m) != 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.