ALSA: hda - Add init_verbs entries
authorTakashi Iwai <tiwai@suse.de>
Wed, 30 Jul 2008 13:01:46 +0000 (15:01 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 13 Oct 2008 00:43:03 +0000 (02:43 +0200)
This patch enables the additional init verbs for each codec.  The verbs
can be entered via hwdep sysfs file.  These verbs are executed at
reconfiguring the codec for non-standard setups like overriding
the pin-defcfg.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_hwdep.c

index 0741eda78a5ebcc44a287f15127b09b72722f8b4..9a8adc600a57505e7504b3a1ad8e19416cc06351 100644 (file)
@@ -1941,6 +1941,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        }
 }
 
+#ifdef CONFIG_SND_HDA_HWDEP
+/* execute additional init verbs */
+static void hda_exec_init_verbs(struct hda_codec *codec)
+{
+       if (codec->init_verbs.list)
+               snd_hda_sequence_write(codec, codec->init_verbs.list);
+}
+#else
+static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
+#endif
+
 #ifdef SND_HDA_NEEDS_RESUME
 /*
  * call suspend and power-down; used both from PM and power-save
@@ -1967,6 +1978,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
        hda_set_power_state(codec,
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D0);
+       hda_exec_init_verbs(codec);
        if (codec->patch_ops.resume)
                codec->patch_ops.resume(codec);
        else {
@@ -2008,6 +2020,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
        hda_set_power_state(codec,
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D0);
+       hda_exec_init_verbs(codec);
        /* continue to initialize... */
        if (codec->patch_ops.init)
                err = codec->patch_ops.init(codec);
index ce9f69bde3285c05b7d17f8e6381da9c7f9a144e..38a9bb6bafb0f8db9c0d284c853a4c8b55d97fd9 100644 (file)
@@ -751,7 +751,10 @@ struct hda_codec {
        unsigned int spdif_in_enable;   /* SPDIF input enable? */
        hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 
+#ifdef CONFIG_SND_HDA_HWDEP
        struct snd_hwdep *hwdep;        /* assigned hwdep device */
+       struct snd_array init_verbs;    /* additional init verbs */
+#endif
 
        /* misc flags */
        unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
index 214772c8b556566db820a922cb5dbffeea5bf017..f3400d75eba4b57ffc47e31c15cfb96ce77e6322 100644 (file)
@@ -96,6 +96,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
        return 0;
 }
 
+static void clear_hwdep_elements(struct hda_codec *codec)
+{
+       /* clear init verbs */
+       snd_array_free(&codec->init_verbs);
+}
+
+static void hwdep_free(struct snd_hwdep *hwdep)
+{
+       clear_hwdep_elements(hwdep->private_data);
+}
+
 int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
 {
        char hwname[16];
@@ -110,6 +121,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
        sprintf(hwdep->name, "HDA Codec %d", codec->addr);
        hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
        hwdep->private_data = codec;
+       hwdep->private_free = hwdep_free;
        hwdep->exclusive = 1;
 
        hwdep->ops.open = hda_hwdep_open;
@@ -118,6 +130,8 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
        hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
+       snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+
        return 0;
 }
 
@@ -128,6 +142,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
 static int clear_codec(struct hda_codec *codec)
 {
        snd_hda_codec_reset(codec);
+       clear_hwdep_elements(codec);
        return 0;
 }
 
@@ -244,6 +259,27 @@ static ssize_t type##_store(struct device *dev,                    \
 CODEC_ACTION_STORE(reconfig);
 CODEC_ACTION_STORE(clear);
 
+static ssize_t init_verbs_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       char *p;
+       struct hda_verb verb, *v;
+
+       verb.nid = simple_strtoul(buf, &p, 0);
+       verb.verb = simple_strtoul(p, &p, 0);
+       verb.param = simple_strtoul(p, &p, 0);
+       if (!verb.nid || !verb.verb || !verb.param)
+               return -EINVAL;
+       v = snd_array_new(&codec->init_verbs);
+       if (!v)
+               return -ENOMEM;
+       *v = verb;
+       return count;
+}
+
 #define CODEC_ATTR_RW(type) \
        __ATTR(type, 0644, type##_show, type##_store)
 #define CODEC_ATTR_RO(type) \
@@ -259,6 +295,7 @@ static struct device_attribute codec_attrs[] = {
        CODEC_ATTR_RO(mfg),
        CODEC_ATTR_RW(name),
        CODEC_ATTR_RW(modelname),
+       CODEC_ATTR_WO(init_verbs),
        CODEC_ATTR_WO(reconfig),
        CODEC_ATTR_WO(clear),
 };
This page took 0.02997 seconds and 5 git commands to generate.