aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_codec.c151
-rw-r--r--sound/pci/hda/hda_codec.h15
-rw-r--r--sound/pci/hda/hda_hwdep.c66
3 files changed, 223 insertions, 9 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 98884bc8f35f..6fa871f66a72 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -682,11 +682,132 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
682 return 0; 682 return 0;
683} 683}
684 684
685/* read all pin default configurations and save codec->init_pins */
686static int read_pin_defaults(struct hda_codec *codec)
687{
688 int i;
689 hda_nid_t nid = codec->start_nid;
690
691 for (i = 0; i < codec->num_nodes; i++, nid++) {
692 struct hda_pincfg *pin;
693 unsigned int wcaps = get_wcaps(codec, nid);
694 unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
695 AC_WCAP_TYPE_SHIFT;
696 if (wid_type != AC_WID_PIN)
697 continue;
698 pin = snd_array_new(&codec->init_pins);
699 if (!pin)
700 return -ENOMEM;
701 pin->nid = nid;
702 pin->cfg = snd_hda_codec_read(codec, nid, 0,
703 AC_VERB_GET_CONFIG_DEFAULT, 0);
704 }
705 return 0;
706}
707
708/* look up the given pin config list and return the item matching with NID */
709static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec,
710 struct snd_array *array,
711 hda_nid_t nid)
712{
713 int i;
714 for (i = 0; i < array->used; i++) {
715 struct hda_pincfg *pin = snd_array_elem(array, i);
716 if (pin->nid == nid)
717 return pin;
718 }
719 return NULL;
720}
721
722/* write a config value for the given NID */
723static void set_pincfg(struct hda_codec *codec, hda_nid_t nid,
724 unsigned int cfg)
725{
726 int i;
727 for (i = 0; i < 4; i++) {
728 snd_hda_codec_write(codec, nid, 0,
729 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
730 cfg & 0xff);
731 cfg >>= 8;
732 }
733}
734
735/* set the current pin config value for the given NID.
736 * the value is cached, and read via snd_hda_codec_get_pincfg()
737 */
738int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
739 hda_nid_t nid, unsigned int cfg)
740{
741 struct hda_pincfg *pin;
742
743 pin = look_up_pincfg(codec, list, nid);
744 if (!pin) {
745 pin = snd_array_new(list);
746 if (!pin)
747 return -ENOMEM;
748 pin->nid = nid;
749 }
750 pin->cfg = cfg;
751 set_pincfg(codec, nid, cfg);
752 return 0;
753}
754
755int snd_hda_codec_set_pincfg(struct hda_codec *codec,
756 hda_nid_t nid, unsigned int cfg)
757{
758 return snd_hda_add_pincfg(codec, &codec->cur_pins, nid, cfg);
759}
760EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg);
761
762/* get the current pin config value of the given pin NID */
763unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
764{
765 struct hda_pincfg *pin;
766
767 pin = look_up_pincfg(codec, &codec->cur_pins, nid);
768 if (pin)
769 return pin->cfg;
770#ifdef CONFIG_SND_HDA_HWDEP
771 pin = look_up_pincfg(codec, &codec->override_pins, nid);
772 if (pin)
773 return pin->cfg;
774#endif
775 pin = look_up_pincfg(codec, &codec->init_pins, nid);
776 if (pin)
777 return pin->cfg;
778 return 0;
779}
780EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
781
782/* restore all current pin configs */
783static void restore_pincfgs(struct hda_codec *codec)
784{
785 int i;
786 for (i = 0; i < codec->init_pins.used; i++) {
787 struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
788 set_pincfg(codec, pin->nid,
789 snd_hda_codec_get_pincfg(codec, pin->nid));
790 }
791}
685 792
686static void init_hda_cache(struct hda_cache_rec *cache, 793static void init_hda_cache(struct hda_cache_rec *cache,
687 unsigned int record_size); 794 unsigned int record_size);
688static void free_hda_cache(struct hda_cache_rec *cache); 795static void free_hda_cache(struct hda_cache_rec *cache);
689 796
797/* restore the initial pin cfgs and release all pincfg lists */
798static void restore_init_pincfgs(struct hda_codec *codec)
799{
800 /* first free cur_pins and override_pins, then call restore_pincfg
801 * so that only the values in init_pins are restored
802 */
803 snd_array_free(&codec->cur_pins);
804#ifdef CONFIG_SND_HDA_HWDEP
805 snd_array_free(&codec->override_pins);
806#endif
807 restore_pincfgs(codec);
808 snd_array_free(&codec->init_pins);
809}
810
690/* 811/*
691 * codec destructor 812 * codec destructor
692 */ 813 */
@@ -694,6 +815,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
694{ 815{
695 if (!codec) 816 if (!codec)
696 return; 817 return;
818 restore_init_pincfgs(codec);
697#ifdef CONFIG_SND_HDA_POWER_SAVE 819#ifdef CONFIG_SND_HDA_POWER_SAVE
698 cancel_delayed_work(&codec->power_work); 820 cancel_delayed_work(&codec->power_work);
699 flush_workqueue(codec->bus->workq); 821 flush_workqueue(codec->bus->workq);
@@ -751,6 +873,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
751 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 873 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
752 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 874 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
753 snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); 875 snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
876 snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
877 snd_array_init(&codec->cur_pins, sizeof(struct hda_pincfg), 16);
754 if (codec->bus->modelname) { 878 if (codec->bus->modelname) {
755 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); 879 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
756 if (!codec->modelname) { 880 if (!codec->modelname) {
@@ -787,15 +911,18 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
787 setup_fg_nodes(codec); 911 setup_fg_nodes(codec);
788 if (!codec->afg && !codec->mfg) { 912 if (!codec->afg && !codec->mfg) {
789 snd_printdd("hda_codec: no AFG or MFG node found\n"); 913 snd_printdd("hda_codec: no AFG or MFG node found\n");
790 snd_hda_codec_free(codec); 914 err = -ENODEV;
791 return -ENODEV; 915 goto error;
792 } 916 }
793 917
794 if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) { 918 err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
919 if (err < 0) {
795 snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); 920 snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
796 snd_hda_codec_free(codec); 921 goto error;
797 return -ENOMEM;
798 } 922 }
923 err = read_pin_defaults(codec);
924 if (err < 0)
925 goto error;
799 926
800 if (!codec->subsystem_id) { 927 if (!codec->subsystem_id) {
801 hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; 928 hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
@@ -808,10 +935,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
808 935
809 if (do_init) { 936 if (do_init) {
810 err = snd_hda_codec_configure(codec); 937 err = snd_hda_codec_configure(codec);
811 if (err < 0) { 938 if (err < 0)
812 snd_hda_codec_free(codec); 939 goto error;
813 return err;
814 }
815 } 940 }
816 snd_hda_codec_proc_new(codec); 941 snd_hda_codec_proc_new(codec);
817 942
@@ -824,6 +949,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
824 if (codecp) 949 if (codecp)
825 *codecp = codec; 950 *codecp = codec;
826 return 0; 951 return 0;
952
953 error:
954 snd_hda_codec_free(codec);
955 return err;
827} 956}
828EXPORT_SYMBOL_HDA(snd_hda_codec_new); 957EXPORT_SYMBOL_HDA(snd_hda_codec_new);
829 958
@@ -1334,6 +1463,9 @@ void snd_hda_codec_reset(struct hda_codec *codec)
1334 free_hda_cache(&codec->cmd_cache); 1463 free_hda_cache(&codec->cmd_cache);
1335 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 1464 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
1336 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 1465 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
1466 /* free only cur_pins so that init_pins + override_pins are restored */
1467 snd_array_free(&codec->cur_pins);
1468 restore_pincfgs(codec);
1337 codec->num_pcms = 0; 1469 codec->num_pcms = 0;
1338 codec->pcm_info = NULL; 1470 codec->pcm_info = NULL;
1339 codec->preset = NULL; 1471 codec->preset = NULL;
@@ -2175,6 +2307,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
2175 hda_set_power_state(codec, 2307 hda_set_power_state(codec,
2176 codec->afg ? codec->afg : codec->mfg, 2308 codec->afg ? codec->afg : codec->mfg,
2177 AC_PWRST_D0); 2309 AC_PWRST_D0);
2310 restore_pincfgs(codec); /* restore all current pin configs */
2178 hda_exec_init_verbs(codec); 2311 hda_exec_init_verbs(codec);
2179 if (codec->patch_ops.resume) 2312 if (codec->patch_ops.resume)
2180 codec->patch_ops.resume(codec); 2313 codec->patch_ops.resume(codec);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 09a332ada0c6..6d01a8058f0a 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -778,11 +778,14 @@ struct hda_codec {
778 unsigned short spdif_ctls; /* SPDIF control bits */ 778 unsigned short spdif_ctls; /* SPDIF control bits */
779 unsigned int spdif_in_enable; /* SPDIF input enable? */ 779 unsigned int spdif_in_enable; /* SPDIF input enable? */
780 hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ 780 hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
781 struct snd_array init_pins; /* initial (BIOS) pin configurations */
782 struct snd_array cur_pins; /* current pin configurations */
781 783
782#ifdef CONFIG_SND_HDA_HWDEP 784#ifdef CONFIG_SND_HDA_HWDEP
783 struct snd_hwdep *hwdep; /* assigned hwdep device */ 785 struct snd_hwdep *hwdep; /* assigned hwdep device */
784 struct snd_array init_verbs; /* additional init verbs */ 786 struct snd_array init_verbs; /* additional init verbs */
785 struct snd_array hints; /* additional hints */ 787 struct snd_array hints; /* additional hints */
788 struct snd_array override_pins; /* default pin configs to override */
786#endif 789#endif
787 790
788 /* misc flags */ 791 /* misc flags */
@@ -855,6 +858,18 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
855#define snd_hda_sequence_write_cache snd_hda_sequence_write 858#define snd_hda_sequence_write_cache snd_hda_sequence_write
856#endif 859#endif
857 860
861/* the struct for codec->pin_configs */
862struct hda_pincfg {
863 hda_nid_t nid;
864 unsigned int cfg;
865};
866
867unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid);
868int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
869 unsigned int cfg);
870int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
871 hda_nid_t nid, unsigned int cfg); /* for hwdep */
872
858/* 873/*
859 * Mixer 874 * Mixer
860 */ 875 */
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 4ae51dcb81af..71039a6dec28 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -109,6 +109,7 @@ static void clear_hwdep_elements(struct hda_codec *codec)
109 for (i = 0; i < codec->hints.used; i++, head++) 109 for (i = 0; i < codec->hints.used; i++, head++)
110 kfree(*head); 110 kfree(*head);
111 snd_array_free(&codec->hints); 111 snd_array_free(&codec->hints);
112 snd_array_free(&codec->override_pins);
112} 113}
113 114
114static void hwdep_free(struct snd_hwdep *hwdep) 115static void hwdep_free(struct snd_hwdep *hwdep)
@@ -141,6 +142,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
141 142
142 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); 143 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
143 snd_array_init(&codec->hints, sizeof(char *), 32); 144 snd_array_init(&codec->hints, sizeof(char *), 32);
145 snd_array_init(&codec->override_pins, sizeof(struct hda_pincfg), 16);
144 146
145 return 0; 147 return 0;
146} 148}
@@ -316,6 +318,67 @@ static ssize_t hints_store(struct device *dev,
316 return count; 318 return count;
317} 319}
318 320
321static ssize_t pin_configs_show(struct hda_codec *codec,
322 struct snd_array *list,
323 char *buf)
324{
325 int i, len = 0;
326 for (i = 0; i < list->used; i++) {
327 struct hda_pincfg *pin = snd_array_elem(list, i);
328 len += sprintf(buf + len, "0x%02x 0x%08x\n",
329 pin->nid, pin->cfg);
330 }
331 return len;
332}
333
334static ssize_t init_pin_configs_show(struct device *dev,
335 struct device_attribute *attr,
336 char *buf)
337{
338 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
339 struct hda_codec *codec = hwdep->private_data;
340 return pin_configs_show(codec, &codec->init_pins, buf);
341}
342
343static ssize_t override_pin_configs_show(struct device *dev,
344 struct device_attribute *attr,
345 char *buf)
346{
347 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
348 struct hda_codec *codec = hwdep->private_data;
349 return pin_configs_show(codec, &codec->override_pins, buf);
350}
351
352static ssize_t cur_pin_configs_show(struct device *dev,
353 struct device_attribute *attr,
354 char *buf)
355{
356 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
357 struct hda_codec *codec = hwdep->private_data;
358 return pin_configs_show(codec, &codec->cur_pins, buf);
359}
360
361#define MAX_PIN_CONFIGS 32
362
363static ssize_t override_pin_configs_store(struct device *dev,
364 struct device_attribute *attr,
365 const char *buf, size_t count)
366{
367 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
368 struct hda_codec *codec = hwdep->private_data;
369 int nid, cfg;
370 int err;
371
372 if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
373 return -EINVAL;
374 if (!nid)
375 return -EINVAL;
376 err = snd_hda_add_pincfg(codec, &codec->override_pins, nid, cfg);
377 if (err < 0)
378 return err;
379 return count;
380}
381
319#define CODEC_ATTR_RW(type) \ 382#define CODEC_ATTR_RW(type) \
320 __ATTR(type, 0644, type##_show, type##_store) 383 __ATTR(type, 0644, type##_show, type##_store)
321#define CODEC_ATTR_RO(type) \ 384#define CODEC_ATTR_RO(type) \
@@ -333,6 +396,9 @@ static struct device_attribute codec_attrs[] = {
333 CODEC_ATTR_RW(modelname), 396 CODEC_ATTR_RW(modelname),
334 CODEC_ATTR_WO(init_verbs), 397 CODEC_ATTR_WO(init_verbs),
335 CODEC_ATTR_WO(hints), 398 CODEC_ATTR_WO(hints),
399 CODEC_ATTR_RO(init_pin_configs),
400 CODEC_ATTR_RW(override_pin_configs),
401 CODEC_ATTR_RO(cur_pin_configs),
336 CODEC_ATTR_WO(reconfig), 402 CODEC_ATTR_WO(reconfig),
337 CODEC_ATTR_WO(clear), 403 CODEC_ATTR_WO(clear),
338}; 404};