diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0741eda78a5ebcc44a287f15127b09b72722f8b4..9a8adc600a57505e7504b3a1ad8e19416cc06351 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ce9f69bde3285c05b7d17f8e6381da9c7f9a144e..38a9bb6bafb0f8db9c0d284c853a4c8b55d97fd9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -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 diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 214772c8b556566db820a922cb5dbffeea5bf017..f3400d75eba4b57ffc47e31c15cfb96ce77e6322 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -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), };