ALSA: hda - Add sysfs entries to hwdep devices
Added the sysfs entries to hwdep devices so that the new features like reconfiguration can be done via sysfs. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Родитель
6c1f45ea89
Коммит
d7ffba19ce
|
@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device)
|
|||
return snd_hda_bus_free(bus);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
static int snd_hda_bus_dev_register(struct snd_device *device)
|
||||
{
|
||||
struct hda_bus *bus = device->device_data;
|
||||
struct hda_codec *codec;
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
snd_hda_hwdep_add_sysfs(codec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define snd_hda_bus_dev_register NULL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snd_hda_bus_new - create a HDA bus
|
||||
* @card: the card entry
|
||||
|
@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
|
|||
struct hda_bus *bus;
|
||||
int err;
|
||||
static struct snd_device_ops dev_ops = {
|
||||
.dev_register = snd_hda_bus_dev_register,
|
||||
.dev_free = snd_hda_bus_dev_free,
|
||||
};
|
||||
|
||||
|
@ -686,9 +701,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
|||
}
|
||||
snd_hda_codec_proc_new(codec);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
snd_hda_create_hwdep(codec);
|
||||
#endif
|
||||
|
||||
sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
|
||||
codec->subsystem_id, codec->revision_id);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
||||
/*
|
||||
* write/read an out-of-bound verb
|
||||
|
@ -119,3 +120,159 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs interface
|
||||
*/
|
||||
|
||||
static int clear_codec(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_codec_reset(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reconfig_codec(struct hda_codec *codec)
|
||||
{
|
||||
int err;
|
||||
|
||||
snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
|
||||
snd_hda_codec_reset(codec);
|
||||
err = snd_hda_codec_configure(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* rebuild PCMs */
|
||||
err = snd_hda_build_pcms(codec->bus);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* rebuild mixers */
|
||||
err = snd_hda_codec_build_controls(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a string at most len chars, and remove the trailing EOL
|
||||
*/
|
||||
static char *kstrndup_noeol(const char *src, size_t len)
|
||||
{
|
||||
char *s = kstrndup(src, len, GFP_KERNEL);
|
||||
char *p;
|
||||
if (!s)
|
||||
return NULL;
|
||||
p = strchr(s, '\n');
|
||||
if (p)
|
||||
*p = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
#define CODEC_INFO_SHOW(type) \
|
||||
static ssize_t type##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
|
||||
struct hda_codec *codec = hwdep->private_data; \
|
||||
return sprintf(buf, "0x%x\n", codec->type); \
|
||||
}
|
||||
|
||||
#define CODEC_INFO_STR_SHOW(type) \
|
||||
static ssize_t type##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
|
||||
struct hda_codec *codec = hwdep->private_data; \
|
||||
return sprintf(buf, "%s\n", \
|
||||
codec->type ? codec->type : ""); \
|
||||
}
|
||||
|
||||
CODEC_INFO_SHOW(vendor_id);
|
||||
CODEC_INFO_SHOW(subsystem_id);
|
||||
CODEC_INFO_SHOW(revision_id);
|
||||
CODEC_INFO_SHOW(afg);
|
||||
CODEC_INFO_SHOW(mfg);
|
||||
CODEC_INFO_STR_SHOW(name);
|
||||
CODEC_INFO_STR_SHOW(modelname);
|
||||
|
||||
#define CODEC_INFO_STORE(type) \
|
||||
static ssize_t type##_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 *after; \
|
||||
codec->type = simple_strtoul(buf, &after, 0); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
#define CODEC_INFO_STR_STORE(type) \
|
||||
static ssize_t type##_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 *s = kstrndup_noeol(buf, 64); \
|
||||
if (!s) \
|
||||
return -ENOMEM; \
|
||||
kfree(codec->type); \
|
||||
codec->type = s; \
|
||||
return count; \
|
||||
}
|
||||
|
||||
CODEC_INFO_STORE(vendor_id);
|
||||
CODEC_INFO_STORE(subsystem_id);
|
||||
CODEC_INFO_STORE(revision_id);
|
||||
CODEC_INFO_STR_STORE(name);
|
||||
CODEC_INFO_STR_STORE(modelname);
|
||||
|
||||
#define CODEC_ACTION_STORE(type) \
|
||||
static ssize_t type##_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; \
|
||||
int err = 0; \
|
||||
if (*buf) \
|
||||
err = type##_codec(codec); \
|
||||
return err < 0 ? err : count; \
|
||||
}
|
||||
|
||||
CODEC_ACTION_STORE(reconfig);
|
||||
CODEC_ACTION_STORE(clear);
|
||||
|
||||
#define CODEC_ATTR_RW(type) \
|
||||
__ATTR(type, 0644, type##_show, type##_store)
|
||||
#define CODEC_ATTR_RO(type) \
|
||||
__ATTR_RO(type)
|
||||
#define CODEC_ATTR_WO(type) \
|
||||
__ATTR(type, 0200, NULL, type##_store)
|
||||
|
||||
static struct device_attribute codec_attrs[] = {
|
||||
CODEC_ATTR_RW(vendor_id),
|
||||
CODEC_ATTR_RW(subsystem_id),
|
||||
CODEC_ATTR_RW(revision_id),
|
||||
CODEC_ATTR_RO(afg),
|
||||
CODEC_ATTR_RO(mfg),
|
||||
CODEC_ATTR_RW(name),
|
||||
CODEC_ATTR_RW(modelname),
|
||||
CODEC_ATTR_WO(reconfig),
|
||||
CODEC_ATTR_WO(clear),
|
||||
};
|
||||
|
||||
/*
|
||||
* create sysfs files on hwdep directory
|
||||
*/
|
||||
int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
|
||||
{
|
||||
struct snd_hwdep *hwdep = codec->hwdep;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
|
||||
snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
|
||||
hwdep->device, &codec_attrs[i]);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -401,7 +401,12 @@ void snd_hda_ctls_clear(struct hda_codec *codec);
|
|||
/*
|
||||
* hwdep interface
|
||||
*/
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
int snd_hda_create_hwdep(struct hda_codec *codec);
|
||||
int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
|
||||
#else
|
||||
static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* power-management
|
||||
|
|
Загрузка…
Ссылка в новой задаче