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