diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-06-30 09:29:38 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-06-30 09:29:38 -0400 |
commit | b9791ca013cfe344052455e9c8336e39d133c654 (patch) | |
tree | 530091e9c2ea488c1ddf4f81575917ca5b3f1446 | |
parent | 546861f1d3372d69d22e6624f51227d7d10c83f4 (diff) | |
parent | 1e7b8c87cb53d9a14f1a9ef35eed739f68851f5c (diff) |
Merge branch 'topic/hda-patch' into topic/hda
-rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 4 | ||||
-rw-r--r-- | Documentation/sound/alsa/HD-Audio.txt | 60 | ||||
-rw-r--r-- | sound/pci/hda/Kconfig | 14 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 10 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 236 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 42 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 1 |
8 files changed, 342 insertions, 33 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4252697a95d6..f9d11140af91 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -768,6 +768,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
768 | bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. | 768 | bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. |
769 | Passing -1 will make the driver to choose the appropriate | 769 | Passing -1 will make the driver to choose the appropriate |
770 | value based on the controller chip. | 770 | value based on the controller chip. |
771 | patch - Specifies the early "patch" files to modify the HD-audio | ||
772 | setup before initializing the codecs. This option is | ||
773 | available only when CONFIG_SND_HDA_PATCH_LOADER=y is set. | ||
774 | See HD-Audio.txt for details. | ||
771 | 775 | ||
772 | [Single (global) options] | 776 | [Single (global) options] |
773 | single_cmd - Use single immediate commands to communicate with | 777 | single_cmd - Use single immediate commands to communicate with |
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 71ac995b1915..0b5b480708f8 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt | |||
@@ -403,6 +403,66 @@ re-configure based on that state, run like below: | |||
403 | ------------------------------------------------------------------------ | 403 | ------------------------------------------------------------------------ |
404 | 404 | ||
405 | 405 | ||
406 | Early Patching | ||
407 | ~~~~~~~~~~~~~~ | ||
408 | When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a | ||
409 | firmware file for modifying the HD-audio setup before initializing the | ||
410 | codec. This can work basically like the reconfiguration via sysfs in | ||
411 | the above, but it does it before the first codec configuration. | ||
412 | |||
413 | A patch file is a plain text file which looks like below: | ||
414 | |||
415 | ------------------------------------------------------------------------ | ||
416 | [codec] | ||
417 | 0x12345678 0xabcd1234 2 | ||
418 | |||
419 | [model] | ||
420 | auto | ||
421 | |||
422 | [pincfg] | ||
423 | 0x12 0x411111f0 | ||
424 | |||
425 | [verb] | ||
426 | 0x20 0x500 0x03 | ||
427 | 0x20 0x400 0xff | ||
428 | |||
429 | [hint] | ||
430 | hp_detect = yes | ||
431 | ------------------------------------------------------------------------ | ||
432 | |||
433 | The file needs to have a line `[codec]`. The next line should contain | ||
434 | three numbers indicating the codec vendor-id (0x12345678 in the | ||
435 | example), the codec subsystem-id (0xabcd1234) and the address (2) of | ||
436 | the codec. The rest patch entries are applied to this specified codec | ||
437 | until another codec entry is given. | ||
438 | |||
439 | The `[model]` line allows to change the model name of the each codec. | ||
440 | In the example above, it will be changed to model=auto. | ||
441 | Note that this overrides the module option. | ||
442 | |||
443 | After the `[pincfg]` line, the contents are parsed as the initial | ||
444 | default pin-configurations just like `user_pin_configs` sysfs above. | ||
445 | The values can be shown in user_pin_configs sysfs file, too. | ||
446 | |||
447 | Similarly, the lines after `[verb]` are parsed as `init_verbs` | ||
448 | sysfs entries, and the lines after `[hint]` are parsed as `hints` | ||
449 | sysfs entries, respectively. | ||
450 | |||
451 | The hd-audio driver reads the file via request_firmware(). Thus, | ||
452 | a patch file has to be located on the appropriate firmware path, | ||
453 | typically, /lib/firmware. For example, when you pass the option | ||
454 | `patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be | ||
455 | present. | ||
456 | |||
457 | The patch module option is specific to each card instance, and you | ||
458 | need to give one file name for each instance, separated by commas. | ||
459 | For example, if you have two cards, one for an on-board analog and one | ||
460 | for an HDMI video board, you may pass patch option like below: | ||
461 | ------------------------------------------------------------------------ | ||
462 | options snd-hda-intel patch=on-board-patch,hdmi-patch | ||
463 | ------------------------------------------------------------------------ | ||
464 | |||
465 | |||
406 | Power-Saving | 466 | Power-Saving |
407 | ~~~~~~~~~~~~ | 467 | ~~~~~~~~~~~~ |
408 | The power-saving is a kind of auto-suspend of the device. When the | 468 | The power-saving is a kind of auto-suspend of the device. When the |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 04438f1d682d..b8a77f9b0827 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK | |||
46 | Say Y here to enable the jack plugging notification via | 46 | Say Y here to enable the jack plugging notification via |
47 | input layer. | 47 | input layer. |
48 | 48 | ||
49 | config SND_HDA_PATCH_LOADER | ||
50 | bool "Support initialization patch loading for HD-audio" | ||
51 | depends on EXPERIMENTAL | ||
52 | select FW_LOADER | ||
53 | select SND_HDA_HWDEP | ||
54 | select SND_HDA_RECONFIG | ||
55 | help | ||
56 | Say Y here to allow the HD-audio driver to load a pseudo | ||
57 | firmware file ("patch") for overriding the BIOS setup at | ||
58 | start up. The "patch" file can be specified via patch module | ||
59 | option, such as patch=hda-init. | ||
60 | |||
61 | This option turns on hwdep and reconfig features automatically. | ||
62 | |||
49 | config SND_HDA_CODEC_REALTEK | 63 | config SND_HDA_CODEC_REALTEK |
50 | bool "Build Realtek HD-audio codec support" | 64 | bool "Build Realtek HD-audio codec support" |
51 | default y | 65 | default y |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 462e2cedaa6a..506f46ef0304 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -885,7 +885,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
885 | * Returns 0 if successful, or a negative error code. | 885 | * Returns 0 if successful, or a negative error code. |
886 | */ | 886 | */ |
887 | int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | 887 | int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, |
888 | int do_init, struct hda_codec **codecp) | 888 | struct hda_codec **codecp) |
889 | { | 889 | { |
890 | struct hda_codec *codec; | 890 | struct hda_codec *codec; |
891 | char component[31]; | 891 | char component[31]; |
@@ -978,11 +978,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
978 | codec->afg ? codec->afg : codec->mfg, | 978 | codec->afg ? codec->afg : codec->mfg, |
979 | AC_PWRST_D0); | 979 | AC_PWRST_D0); |
980 | 980 | ||
981 | if (do_init) { | ||
982 | err = snd_hda_codec_configure(codec); | ||
983 | if (err < 0) | ||
984 | goto error; | ||
985 | } | ||
986 | snd_hda_codec_proc_new(codec); | 981 | snd_hda_codec_proc_new(codec); |
987 | 982 | ||
988 | snd_hda_create_hwdep(codec); | 983 | snd_hda_create_hwdep(codec); |
@@ -1036,6 +1031,7 @@ int snd_hda_codec_configure(struct hda_codec *codec) | |||
1036 | err = init_unsol_queue(codec->bus); | 1031 | err = init_unsol_queue(codec->bus); |
1037 | return err; | 1032 | return err; |
1038 | } | 1033 | } |
1034 | EXPORT_SYMBOL_HDA(snd_hda_codec_configure); | ||
1039 | 1035 | ||
1040 | /** | 1036 | /** |
1041 | * snd_hda_codec_setup_stream - set up the codec for streaming | 1037 | * snd_hda_codec_setup_stream - set up the codec for streaming |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index cad79efaabc9..72c997592eed 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -830,7 +830,8 @@ enum { | |||
830 | int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, | 830 | int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, |
831 | struct hda_bus **busp); | 831 | struct hda_bus **busp); |
832 | int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | 832 | int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, |
833 | int do_init, struct hda_codec **codecp); | 833 | struct hda_codec **codecp); |
834 | int snd_hda_codec_configure(struct hda_codec *codec); | ||
834 | 835 | ||
835 | /* | 836 | /* |
836 | * low level functions | 837 | * low level functions |
@@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} | |||
938 | #define snd_hda_codec_needs_resume(codec) 1 | 939 | #define snd_hda_codec_needs_resume(codec) 1 |
939 | #endif | 940 | #endif |
940 | 941 | ||
942 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | ||
943 | /* | ||
944 | * patch firmware | ||
945 | */ | ||
946 | int snd_hda_load_patch(struct hda_bus *bus, const char *patch); | ||
947 | #endif | ||
948 | |||
941 | /* | 949 | /* |
942 | * Codec modularization | 950 | * Codec modularization |
943 | */ | 951 | */ |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6812fbe80fa4..cc24e6721d74 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/compat.h> | 24 | #include <linux/compat.h> |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/ctype.h> | 26 | #include <linux/ctype.h> |
27 | #include <linux/firmware.h> | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include "hda_codec.h" | 29 | #include "hda_codec.h" |
29 | #include "hda_local.h" | 30 | #include "hda_local.h" |
@@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev, | |||
312 | return len; | 313 | return len; |
313 | } | 314 | } |
314 | 315 | ||
315 | static ssize_t init_verbs_store(struct device *dev, | 316 | static int parse_init_verbs(struct hda_codec *codec, const char *buf) |
316 | struct device_attribute *attr, | ||
317 | const char *buf, size_t count) | ||
318 | { | 317 | { |
319 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
320 | struct hda_codec *codec = hwdep->private_data; | ||
321 | struct hda_verb *v; | 318 | struct hda_verb *v; |
322 | int nid, verb, param; | 319 | int nid, verb, param; |
323 | 320 | ||
@@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev, | |||
331 | v->nid = nid; | 328 | v->nid = nid; |
332 | v->verb = verb; | 329 | v->verb = verb; |
333 | v->param = param; | 330 | v->param = param; |
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static ssize_t init_verbs_store(struct device *dev, | ||
335 | struct device_attribute *attr, | ||
336 | const char *buf, size_t count) | ||
337 | { | ||
338 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
339 | struct hda_codec *codec = hwdep->private_data; | ||
340 | int err = parse_init_verbs(codec, buf); | ||
341 | if (err < 0) | ||
342 | return err; | ||
334 | return count; | 343 | return count; |
335 | } | 344 | } |
336 | 345 | ||
@@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str) | |||
376 | 385 | ||
377 | #define MAX_HINTS 1024 | 386 | #define MAX_HINTS 1024 |
378 | 387 | ||
379 | static ssize_t hints_store(struct device *dev, | 388 | static int parse_hints(struct hda_codec *codec, const char *buf) |
380 | struct device_attribute *attr, | ||
381 | const char *buf, size_t count) | ||
382 | { | 389 | { |
383 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
384 | struct hda_codec *codec = hwdep->private_data; | ||
385 | char *key, *val; | 390 | char *key, *val; |
386 | struct hda_hint *hint; | 391 | struct hda_hint *hint; |
387 | 392 | ||
388 | while (isspace(*buf)) | 393 | while (isspace(*buf)) |
389 | buf++; | 394 | buf++; |
390 | if (!*buf || *buf == '#' || *buf == '\n') | 395 | if (!*buf || *buf == '#' || *buf == '\n') |
391 | return count; | 396 | return 0; |
392 | if (*buf == '=') | 397 | if (*buf == '=') |
393 | return -EINVAL; | 398 | return -EINVAL; |
394 | key = kstrndup_noeol(buf, 1024); | 399 | key = kstrndup_noeol(buf, 1024); |
@@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev, | |||
411 | kfree(hint->key); | 416 | kfree(hint->key); |
412 | hint->key = key; | 417 | hint->key = key; |
413 | hint->val = val; | 418 | hint->val = val; |
414 | return count; | 419 | return 0; |
415 | } | 420 | } |
416 | /* allocate a new hint entry */ | 421 | /* allocate a new hint entry */ |
417 | if (codec->hints.used >= MAX_HINTS) | 422 | if (codec->hints.used >= MAX_HINTS) |
@@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev, | |||
424 | } | 429 | } |
425 | hint->key = key; | 430 | hint->key = key; |
426 | hint->val = val; | 431 | hint->val = val; |
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static ssize_t hints_store(struct device *dev, | ||
436 | struct device_attribute *attr, | ||
437 | const char *buf, size_t count) | ||
438 | { | ||
439 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
440 | struct hda_codec *codec = hwdep->private_data; | ||
441 | int err = parse_hints(codec, buf); | ||
442 | if (err < 0) | ||
443 | return err; | ||
427 | return count; | 444 | return count; |
428 | } | 445 | } |
429 | 446 | ||
@@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev, | |||
469 | 486 | ||
470 | #define MAX_PIN_CONFIGS 32 | 487 | #define MAX_PIN_CONFIGS 32 |
471 | 488 | ||
472 | static ssize_t user_pin_configs_store(struct device *dev, | 489 | static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) |
473 | struct device_attribute *attr, | ||
474 | const char *buf, size_t count) | ||
475 | { | 490 | { |
476 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
477 | struct hda_codec *codec = hwdep->private_data; | ||
478 | int nid, cfg; | 491 | int nid, cfg; |
479 | int err; | ||
480 | 492 | ||
481 | if (sscanf(buf, "%i %i", &nid, &cfg) != 2) | 493 | if (sscanf(buf, "%i %i", &nid, &cfg) != 2) |
482 | return -EINVAL; | 494 | return -EINVAL; |
483 | if (!nid) | 495 | if (!nid) |
484 | return -EINVAL; | 496 | return -EINVAL; |
485 | err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); | 497 | return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); |
498 | } | ||
499 | |||
500 | static ssize_t user_pin_configs_store(struct device *dev, | ||
501 | struct device_attribute *attr, | ||
502 | const char *buf, size_t count) | ||
503 | { | ||
504 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
505 | struct hda_codec *codec = hwdep->private_data; | ||
506 | int err = parse_user_pin_configs(codec, buf); | ||
486 | if (err < 0) | 507 | if (err < 0) |
487 | return err; | 508 | return err; |
488 | return count; | 509 | return count; |
@@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) | |||
553 | EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); | 574 | EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); |
554 | 575 | ||
555 | #endif /* CONFIG_SND_HDA_RECONFIG */ | 576 | #endif /* CONFIG_SND_HDA_RECONFIG */ |
577 | |||
578 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | ||
579 | |||
580 | /* parser mode */ | ||
581 | enum { | ||
582 | LINE_MODE_NONE, | ||
583 | LINE_MODE_CODEC, | ||
584 | LINE_MODE_MODEL, | ||
585 | LINE_MODE_PINCFG, | ||
586 | LINE_MODE_VERB, | ||
587 | LINE_MODE_HINT, | ||
588 | NUM_LINE_MODES, | ||
589 | }; | ||
590 | |||
591 | static inline int strmatch(const char *a, const char *b) | ||
592 | { | ||
593 | return strnicmp(a, b, strlen(b)) == 0; | ||
594 | } | ||
595 | |||
596 | /* parse the contents after the line "[codec]" | ||
597 | * accept only the line with three numbers, and assign the current codec | ||
598 | */ | ||
599 | static void parse_codec_mode(char *buf, struct hda_bus *bus, | ||
600 | struct hda_codec **codecp) | ||
601 | { | ||
602 | unsigned int vendorid, subid, caddr; | ||
603 | struct hda_codec *codec; | ||
604 | |||
605 | *codecp = NULL; | ||
606 | if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { | ||
607 | list_for_each_entry(codec, &bus->codec_list, list) { | ||
608 | if (codec->addr == caddr) { | ||
609 | *codecp = codec; | ||
610 | break; | ||
611 | } | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | |||
616 | /* parse the contents after the other command tags, [pincfg], [verb], | ||
617 | * [hint] and [model] | ||
618 | * just pass to the sysfs helper (only when any codec was specified) | ||
619 | */ | ||
620 | static void parse_pincfg_mode(char *buf, struct hda_bus *bus, | ||
621 | struct hda_codec **codecp) | ||
622 | { | ||
623 | if (!*codecp) | ||
624 | return; | ||
625 | parse_user_pin_configs(*codecp, buf); | ||
626 | } | ||
627 | |||
628 | static void parse_verb_mode(char *buf, struct hda_bus *bus, | ||
629 | struct hda_codec **codecp) | ||
630 | { | ||
631 | if (!*codecp) | ||
632 | return; | ||
633 | parse_init_verbs(*codecp, buf); | ||
634 | } | ||
635 | |||
636 | static void parse_hint_mode(char *buf, struct hda_bus *bus, | ||
637 | struct hda_codec **codecp) | ||
638 | { | ||
639 | if (!*codecp) | ||
640 | return; | ||
641 | parse_hints(*codecp, buf); | ||
642 | } | ||
643 | |||
644 | static void parse_model_mode(char *buf, struct hda_bus *bus, | ||
645 | struct hda_codec **codecp) | ||
646 | { | ||
647 | if (!*codecp) | ||
648 | return; | ||
649 | kfree((*codecp)->modelname); | ||
650 | (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); | ||
651 | } | ||
652 | |||
653 | struct hda_patch_item { | ||
654 | const char *tag; | ||
655 | void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); | ||
656 | }; | ||
657 | |||
658 | static struct hda_patch_item patch_items[NUM_LINE_MODES] = { | ||
659 | [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode }, | ||
660 | [LINE_MODE_MODEL] = { "[model]", parse_model_mode }, | ||
661 | [LINE_MODE_VERB] = { "[verb]", parse_verb_mode }, | ||
662 | [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode }, | ||
663 | [LINE_MODE_HINT] = { "[hint]", parse_hint_mode }, | ||
664 | }; | ||
665 | |||
666 | /* check the line starting with '[' -- change the parser mode accodingly */ | ||
667 | static int parse_line_mode(char *buf, struct hda_bus *bus) | ||
668 | { | ||
669 | int i; | ||
670 | for (i = 0; i < ARRAY_SIZE(patch_items); i++) { | ||
671 | if (!patch_items[i].tag) | ||
672 | continue; | ||
673 | if (strmatch(buf, patch_items[i].tag)) | ||
674 | return i; | ||
675 | } | ||
676 | return LINE_MODE_NONE; | ||
677 | } | ||
678 | |||
679 | /* copy one line from the buffer in fw, and update the fields in fw | ||
680 | * return zero if it reaches to the end of the buffer, or non-zero | ||
681 | * if successfully copied a line | ||
682 | * | ||
683 | * the spaces at the beginning and the end of the line are stripped | ||
684 | */ | ||
685 | static int get_line_from_fw(char *buf, int size, struct firmware *fw) | ||
686 | { | ||
687 | int len; | ||
688 | const char *p = fw->data; | ||
689 | while (isspace(*p) && fw->size) { | ||
690 | p++; | ||
691 | fw->size--; | ||
692 | } | ||
693 | if (!fw->size) | ||
694 | return 0; | ||
695 | if (size < fw->size) | ||
696 | size = fw->size; | ||
697 | |||
698 | for (len = 0; len < fw->size; len++) { | ||
699 | if (!*p) | ||
700 | break; | ||
701 | if (*p == '\n') { | ||
702 | p++; | ||
703 | len++; | ||
704 | break; | ||
705 | } | ||
706 | if (len < size) | ||
707 | *buf++ = *p++; | ||
708 | } | ||
709 | *buf = 0; | ||
710 | fw->size -= len; | ||
711 | fw->data = p; | ||
712 | remove_trail_spaces(buf); | ||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | /* | ||
717 | * load a "patch" firmware file and parse it | ||
718 | */ | ||
719 | int snd_hda_load_patch(struct hda_bus *bus, const char *patch) | ||
720 | { | ||
721 | int err; | ||
722 | const struct firmware *fw; | ||
723 | struct firmware tmp; | ||
724 | char buf[128]; | ||
725 | struct hda_codec *codec; | ||
726 | int line_mode; | ||
727 | struct device *dev = bus->card->dev; | ||
728 | |||
729 | if (snd_BUG_ON(!dev)) | ||
730 | return -ENODEV; | ||
731 | err = request_firmware(&fw, patch, dev); | ||
732 | if (err < 0) { | ||
733 | printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n", | ||
734 | patch); | ||
735 | return err; | ||
736 | } | ||
737 | |||
738 | tmp = *fw; | ||
739 | line_mode = LINE_MODE_NONE; | ||
740 | codec = NULL; | ||
741 | while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) { | ||
742 | if (!*buf || *buf == '#' || *buf == '\n') | ||
743 | continue; | ||
744 | if (*buf == '[') | ||
745 | line_mode = parse_line_mode(buf, bus); | ||
746 | else if (patch_items[line_mode].parser) | ||
747 | patch_items[line_mode].parser(buf, bus, &codec); | ||
748 | } | ||
749 | release_firmware(fw); | ||
750 | return 0; | ||
751 | } | ||
752 | EXPORT_SYMBOL_HDA(snd_hda_load_patch); | ||
753 | #endif /* CONFIG_SND_HDA_PATCH_LOADER */ | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4e9ea7080270..a2f4a116f872 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -61,6 +61,9 @@ static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | |||
61 | static int probe_only[SNDRV_CARDS]; | 61 | static int probe_only[SNDRV_CARDS]; |
62 | static int single_cmd; | 62 | static int single_cmd; |
63 | static int enable_msi; | 63 | static int enable_msi; |
64 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | ||
65 | static char *patch[SNDRV_CARDS]; | ||
66 | #endif | ||
64 | 67 | ||
65 | module_param_array(index, int, NULL, 0444); | 68 | module_param_array(index, int, NULL, 0444); |
66 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 69 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
@@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " | |||
84 | "(for debugging only)."); | 87 | "(for debugging only)."); |
85 | module_param(enable_msi, int, 0444); | 88 | module_param(enable_msi, int, 0444); |
86 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); | 89 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); |
90 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | ||
91 | module_param_array(patch, charp, NULL, 0444); | ||
92 | MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface."); | ||
93 | #endif | ||
87 | 94 | ||
88 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 95 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
89 | static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; | 96 | static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; |
@@ -1286,8 +1293,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { | |||
1286 | [AZX_DRIVER_TERA] = 1, | 1293 | [AZX_DRIVER_TERA] = 1, |
1287 | }; | 1294 | }; |
1288 | 1295 | ||
1289 | static int __devinit azx_codec_create(struct azx *chip, const char *model, | 1296 | static int __devinit azx_codec_create(struct azx *chip, const char *model) |
1290 | int no_init) | ||
1291 | { | 1297 | { |
1292 | struct hda_bus_template bus_temp; | 1298 | struct hda_bus_template bus_temp; |
1293 | int c, codecs, err; | 1299 | int c, codecs, err; |
@@ -1346,7 +1352,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1346 | for (c = 0; c < max_slots; c++) { | 1352 | for (c = 0; c < max_slots; c++) { |
1347 | if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { | 1353 | if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { |
1348 | struct hda_codec *codec; | 1354 | struct hda_codec *codec; |
1349 | err = snd_hda_codec_new(chip->bus, c, !no_init, &codec); | 1355 | err = snd_hda_codec_new(chip->bus, c, &codec); |
1350 | if (err < 0) | 1356 | if (err < 0) |
1351 | continue; | 1357 | continue; |
1352 | codecs++; | 1358 | codecs++; |
@@ -1356,7 +1362,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1356 | snd_printk(KERN_ERR SFX "no codecs initialized\n"); | 1362 | snd_printk(KERN_ERR SFX "no codecs initialized\n"); |
1357 | return -ENXIO; | 1363 | return -ENXIO; |
1358 | } | 1364 | } |
1365 | return 0; | ||
1366 | } | ||
1359 | 1367 | ||
1368 | /* configure each codec instance */ | ||
1369 | static int __devinit azx_codec_configure(struct azx *chip) | ||
1370 | { | ||
1371 | struct hda_codec *codec; | ||
1372 | list_for_each_entry(codec, &chip->bus->codec_list, list) { | ||
1373 | snd_hda_codec_configure(codec); | ||
1374 | } | ||
1360 | return 0; | 1375 | return 0; |
1361 | } | 1376 | } |
1362 | 1377 | ||
@@ -2460,15 +2475,32 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
2460 | return err; | 2475 | return err; |
2461 | } | 2476 | } |
2462 | 2477 | ||
2478 | /* set this here since it's referred in snd_hda_load_patch() */ | ||
2479 | snd_card_set_dev(card, &pci->dev); | ||
2480 | |||
2463 | err = azx_create(card, pci, dev, pci_id->driver_data, &chip); | 2481 | err = azx_create(card, pci, dev, pci_id->driver_data, &chip); |
2464 | if (err < 0) | 2482 | if (err < 0) |
2465 | goto out_free; | 2483 | goto out_free; |
2466 | card->private_data = chip; | 2484 | card->private_data = chip; |
2467 | 2485 | ||
2468 | /* create codec instances */ | 2486 | /* create codec instances */ |
2469 | err = azx_codec_create(chip, model[dev], probe_only[dev]); | 2487 | err = azx_codec_create(chip, model[dev]); |
2470 | if (err < 0) | 2488 | if (err < 0) |
2471 | goto out_free; | 2489 | goto out_free; |
2490 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | ||
2491 | if (patch[dev]) { | ||
2492 | snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", | ||
2493 | patch[dev]); | ||
2494 | err = snd_hda_load_patch(chip->bus, patch[dev]); | ||
2495 | if (err < 0) | ||
2496 | goto out_free; | ||
2497 | } | ||
2498 | #endif | ||
2499 | if (!probe_only[dev]) { | ||
2500 | err = azx_codec_configure(chip); | ||
2501 | if (err < 0) | ||
2502 | goto out_free; | ||
2503 | } | ||
2472 | 2504 | ||
2473 | /* create PCM streams */ | 2505 | /* create PCM streams */ |
2474 | err = snd_hda_build_pcms(chip->bus); | 2506 | err = snd_hda_build_pcms(chip->bus); |
@@ -2480,8 +2512,6 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
2480 | if (err < 0) | 2512 | if (err < 0) |
2481 | goto out_free; | 2513 | goto out_free; |
2482 | 2514 | ||
2483 | snd_card_set_dev(card, &pci->dev); | ||
2484 | |||
2485 | err = snd_card_register(card); | 2515 | err = snd_card_register(card); |
2486 | if (err < 0) | 2516 | if (err < 0) |
2487 | goto out_free; | 2517 | goto out_free; |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 83349013b4df..75aa3785212f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
99 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | 99 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, |
100 | unsigned int *tlv, const char **slaves); | 100 | unsigned int *tlv, const char **slaves); |
101 | int snd_hda_codec_reset(struct hda_codec *codec); | 101 | int snd_hda_codec_reset(struct hda_codec *codec); |
102 | int snd_hda_codec_configure(struct hda_codec *codec); | ||
103 | 102 | ||
104 | /* amp value bits */ | 103 | /* amp value bits */ |
105 | #define HDA_AMP_MUTE 0x80 | 104 | #define HDA_AMP_MUTE 0x80 |