summaryrefslogtreecommitdiff
path: root/sound/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-11-13 15:43:04 +0100
committerTakashi Iwai <tiwai@suse.de>2017-11-13 15:43:13 +0100
commitc429bda21ffafb28f02fb2eb4055b4ab6879ed58 (patch)
tree80715bf534bfa3bcb69ef77cf1dc5f9d98919b44 /sound/hda
parent75ee94b20b46459e3d29f5ac2c3af3cebdeef777 (diff)
parent9718a29d40b7e5ae4692796eb23c54f25559d35e (diff)
Merge branch 'for-next' into for-linus
Pull 4.15 updates to take over the previous urgent fixes. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/hdac_controller.c3
-rw-r--r--sound/hda/hdac_device.c43
-rw-r--r--sound/hda/hdac_sysfs.c47
-rw-r--r--sound/hda/local.h2
4 files changed, 61 insertions, 34 deletions
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index f6d2985b2520..560ec0986e1a 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -319,7 +319,8 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
break;
default:
- dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
+ dev_err(bus->dev, "Unknown capability %d\n", cur_cap);
+ cur_cap = 0;
break;
}
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 19deb306facb..06f845e293cb 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -87,7 +87,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
fg = codec->afg ? codec->afg : codec->mfg;
- err = snd_hdac_refresh_widgets(codec);
+ err = snd_hdac_refresh_widgets(codec, false);
if (err < 0)
goto error;
@@ -388,11 +388,12 @@ static void setup_fg_nodes(struct hdac_device *codec)
/**
* snd_hdac_refresh_widgets - Reset the widget start/end nodes
* @codec: the codec object
+ * @sysfs: re-initialize sysfs tree, too
*/
-int snd_hdac_refresh_widgets(struct hdac_device *codec)
+int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs)
{
hda_nid_t start_nid;
- int nums;
+ int nums, err;
nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
if (!start_nid || nums <= 0 || nums >= 0xff) {
@@ -401,6 +402,12 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec)
return -EINVAL;
}
+ if (sysfs) {
+ err = hda_widget_sysfs_reinit(codec, start_nid, nums);
+ if (err < 0)
+ return err;
+ }
+
codec->num_nodes = nums;
codec->start_nid = start_nid;
codec->end_nid = start_nid + nums;
@@ -408,36 +415,6 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec)
}
EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
-/**
- * snd_hdac_refresh_widget_sysfs - Reset the codec widgets and reinit the
- * codec sysfs
- * @codec: the codec object
- *
- * first we need to remove sysfs, then refresh widgets and lastly
- * recreate it
- */
-int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec)
-{
- int ret;
-
- if (device_is_registered(&codec->dev))
- hda_widget_sysfs_exit(codec);
- ret = snd_hdac_refresh_widgets(codec);
- if (ret) {
- dev_err(&codec->dev, "failed to refresh widget: %d\n", ret);
- return ret;
- }
- if (device_is_registered(&codec->dev)) {
- ret = hda_widget_sysfs_init(codec);
- if (ret) {
- dev_err(&codec->dev, "failed to init sysfs: %d\n", ret);
- return ret;
- }
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs);
-
/* return CONNLIST_LEN parameter of the given widget */
static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid)
{
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
index 42d61bf41969..e123ba6b2e81 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/hdac_sysfs.c
@@ -414,3 +414,50 @@ void hda_widget_sysfs_exit(struct hdac_device *codec)
{
widget_tree_free(codec);
}
+
+int hda_widget_sysfs_reinit(struct hdac_device *codec,
+ hda_nid_t start_nid, int num_nodes)
+{
+ struct hdac_widget_tree *tree;
+ hda_nid_t end_nid = start_nid + num_nodes;
+ hda_nid_t nid;
+ int i;
+
+ if (!codec->widgets)
+ return hda_widget_sysfs_init(codec);
+
+ tree = kmemdup(codec->widgets, sizeof(*tree), GFP_KERNEL);
+ if (!tree)
+ return -ENOMEM;
+
+ tree->nodes = kcalloc(num_nodes + 1, sizeof(*tree->nodes), GFP_KERNEL);
+ if (!tree->nodes) {
+ kfree(tree);
+ return -ENOMEM;
+ }
+
+ /* prune non-existing nodes */
+ for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) {
+ if (nid < start_nid || nid >= end_nid)
+ free_widget_node(codec->widgets->nodes[i],
+ &widget_node_group);
+ }
+
+ /* add new nodes */
+ for (i = 0, nid = start_nid; i < num_nodes; i++, nid++) {
+ if (nid < codec->start_nid || nid >= codec->end_nid)
+ add_widget_node(tree->root, nid, &widget_node_group,
+ &tree->nodes[i]);
+ else
+ tree->nodes[i] =
+ codec->widgets->nodes[nid - codec->start_nid];
+ }
+
+ /* replace with the new tree */
+ kfree(codec->widgets->nodes);
+ kfree(codec->widgets);
+ codec->widgets = tree;
+
+ kobject_uevent(tree->root, KOBJ_CHANGE);
+ return 0;
+}
diff --git a/sound/hda/local.h b/sound/hda/local.h
index 0d5bb159d538..c586ea62d49e 100644
--- a/sound/hda/local.h
+++ b/sound/hda/local.h
@@ -28,6 +28,8 @@ static inline unsigned int get_wcaps_channels(u32 wcaps)
extern const struct attribute_group *hdac_dev_attr_groups[];
int hda_widget_sysfs_init(struct hdac_device *codec);
+int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid,
+ int num_nodes);
void hda_widget_sysfs_exit(struct hdac_device *codec);
#endif /* __HDAC_LOCAL_H */