Commit 3256be65 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Add widget sysfs tree

This patch changes the sysfs files assigned to the codec device on the
bus which were formerly identical with hwdep sysfs files.  Now it
shows only a few core parameter, vendor_id, subsystem_id, revision_id,
afg, mfg, vendor_name and chip_name.

In addition, now a widget tree is added to the bus device sysfs
directory for showing the widget topology and attributes.  It's just a
flat tree consisting of subdirectories named as the widget NID
including various attributes like widget capability bits.  The AFG
(usually NID 0x01) is always found there, and it contains always
amp_in_caps, amp_out_caps and power_caps files.  Each of these
attributes show a single value.  The rest are the widget nodes
belonging to that AFG.  Note that the child node might not start from
0x02 but from another value like 0x0a.

Each child node may contain caps, pin_caps, amp_in_caps, amp_out_caps,
power_caps and connections files.  The caps (representing the widget
capability bits) always contain a value.  The rest may contain
value(s) if the attribute exists on the node.  Only connections file
show multiple values while other attributes have zero or one single
value.

An example of ls -R output is like below:
% ls -R /sys/bus/hdaudio/devices/hdaudioC0D0/
/sys/bus/hdaudio/devices/hdaudioC0D0/widgets/:
01/  04/  07/  0a/  0d/  10/  13/  16/  19/  1c/  1f/  22/
02/  05/  08/  0b/  0e/  11/  14/  17/  1a/  1d/  20/  23/
03/  06/  09/  0c/  0f/  12/  15/  18/  1b/  1e/  21/

/sys/bus/hdaudio/devices/hdaudioC0D0/widgets/01:
amp_in_caps  amp_out_caps  power_caps

/sys/bus/hdaudio/devices/hdaudioC0D0/widgets/02:
amp_in_caps  amp_out_caps  caps  connections  pin_caps  pin_cfg
power_caps

/sys/bus/hdaudio/devices/hdaudioC0D0/widgets/03:
.....
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7639a06c
...@@ -14,6 +14,7 @@ typedef u16 hda_nid_t; ...@@ -14,6 +14,7 @@ typedef u16 hda_nid_t;
struct hdac_bus; struct hdac_bus;
struct hdac_device; struct hdac_device;
struct hdac_driver; struct hdac_driver;
struct hdac_widget_tree;
/* /*
* exported bus type * exported bus type
...@@ -53,6 +54,9 @@ struct hdac_device { ...@@ -53,6 +54,9 @@ struct hdac_device {
/* misc flags */ /* misc flags */
atomic_t in_pm; /* suspend/resume being performed */ atomic_t in_pm; /* suspend/resume being performed */
/* sysfs */
struct hdac_widget_tree *widgets;
}; };
/* device/driver type used for matching */ /* device/driver type used for matching */
...@@ -71,6 +75,8 @@ enum { ...@@ -71,6 +75,8 @@ enum {
int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus, int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
const char *name, unsigned int addr); const char *name, unsigned int addr);
void snd_hdac_device_exit(struct hdac_device *dev); void snd_hdac_device_exit(struct hdac_device *dev);
int snd_hdac_device_register(struct hdac_device *codec);
void snd_hdac_device_unregister(struct hdac_device *codec);
int snd_hdac_refresh_widgets(struct hdac_device *codec); int snd_hdac_refresh_widgets(struct hdac_device *codec);
......
snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
...@@ -45,6 +45,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, ...@@ -45,6 +45,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
dev->parent = bus->dev; dev->parent = bus->dev;
dev->bus = &snd_hda_bus_type; dev->bus = &snd_hda_bus_type;
dev->release = default_release; dev->release = default_release;
dev->groups = hdac_dev_attr_groups;
dev_set_name(dev, "%s", name); dev_set_name(dev, "%s", name);
device_enable_async_suspend(dev); device_enable_async_suspend(dev);
...@@ -127,6 +128,40 @@ void snd_hdac_device_exit(struct hdac_device *codec) ...@@ -127,6 +128,40 @@ void snd_hdac_device_exit(struct hdac_device *codec)
} }
EXPORT_SYMBOL_GPL(snd_hdac_device_exit); EXPORT_SYMBOL_GPL(snd_hdac_device_exit);
/**
* snd_hdac_device_register - register the hd-audio codec base device
* codec: the device to register
*/
int snd_hdac_device_register(struct hdac_device *codec)
{
int err;
err = device_add(&codec->dev);
if (err < 0)
return err;
err = hda_widget_sysfs_init(codec);
if (err < 0) {
device_del(&codec->dev);
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_device_register);
/**
* snd_hdac_device_unregister - unregister the hd-audio codec base device
* codec: the device to unregister
*/
void snd_hdac_device_unregister(struct hdac_device *codec)
{
if (device_is_registered(&codec->dev)) {
hda_widget_sysfs_exit(codec);
device_del(&codec->dev);
}
}
EXPORT_SYMBOL_GPL(snd_hdac_device_unregister);
/** /**
* snd_hdac_make_cmd - compose a 32bit command word to be sent to the * snd_hdac_make_cmd - compose a 32bit command word to be sent to the
* HD-audio controller * HD-audio controller
......
This diff is collapsed.
...@@ -16,4 +16,8 @@ static inline int get_wcaps_type(unsigned int wcaps) ...@@ -16,4 +16,8 @@ static inline int get_wcaps_type(unsigned int wcaps)
return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
} }
extern const struct attribute_group *hdac_dev_attr_groups[];
int hda_widget_sysfs_init(struct hdac_device *codec);
void hda_widget_sysfs_exit(struct hdac_device *codec);
#endif /* __HDAC_LOCAL_H */ #endif /* __HDAC_LOCAL_H */
...@@ -240,7 +240,7 @@ int snd_hda_codec_configure(struct hda_codec *codec) ...@@ -240,7 +240,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
else else
codec->probe_id = 0; codec->probe_id = 0;
err = device_add(hda_codec_dev(codec)); err = snd_hdac_device_register(&codec->core);
if (err < 0) if (err < 0)
return err; return err;
...@@ -262,7 +262,7 @@ int snd_hda_codec_configure(struct hda_codec *codec) ...@@ -262,7 +262,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
return 0; return 0;
error: error:
device_del(hda_codec_dev(codec)); snd_hdac_device_unregister(&codec->core);
return err; return err;
} }
EXPORT_SYMBOL_GPL(snd_hda_codec_configure); EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
...@@ -967,8 +967,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) ...@@ -967,8 +967,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
struct hda_codec *codec = device->device_data; struct hda_codec *codec = device->device_data;
codec->in_freeing = 1; codec->in_freeing = 1;
if (device_is_registered(hda_codec_dev(codec))) snd_hdac_device_unregister(&codec->core);
device_del(hda_codec_dev(codec));
put_device(hda_codec_dev(codec)); put_device(hda_codec_dev(codec));
return 0; return 0;
} }
...@@ -2182,8 +2181,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) ...@@ -2182,8 +2181,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
return -EBUSY; return -EBUSY;
/* OK, let it free */ /* OK, let it free */
if (device_is_registered(hda_codec_dev(codec))) snd_hdac_device_unregister(&codec->core);
device_del(hda_codec_dev(codec));
/* allow device access again */ /* allow device access again */
snd_hda_unlock_devices(bus); snd_hda_unlock_devices(bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment