ALSA: hda - Add init_verbs entries

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>
This commit is contained in:
Takashi Iwai 2008-07-30 15:01:46 +02:00
parent d7ffba19ce
commit 11aeff082a
3 changed files with 53 additions and 0 deletions

View 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);

View 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

View 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),
};