Skip to contentSkip to conversation

New bind/unbingd uevents

PATCH In review Dmitry Torokhov 5 participants 20 messages Jul 20, 2017 – Sep 30, 2017

Subsystems (4)
lore
Share & tools
lore

Dmitry Torokhov

author maintainer
#0 lore raw

v2 cover New bind/unbingd uevents

Hi Greg,

Here is the v2 of bind/unbind uevent patch series. The new bind/unbind will allow triggering firmware update through udev, and the new device sysfs API will cut down on some boilerplate code in drivers.

As you requested, I moved the new functions to device.h, in the process I exported existing device_add_groups() and device_remove_groups() and called the new functions devm_device_{add|remove}_group[s]() to get away from the sysfs "rawness".

Below is also a patch to systemd to stop dropping the new attributes (why they think they need to inspect and discard the data they do not understand is beyond me).

Thanks,
Dmitry

V2:
- made device_{add|remove}_groups() public
- added device_{add|remove}_group() helpers
- the new devm APIs are moved into device.h and "sysfs" suffix dropped
- added 3 patches showing use in the drivers

V1: initial [re]post

Dmitry Torokhov (7):
driver core: emit uevents when device is bound to a driver driver core: make device_{add|remove}_groups() public
driver core: add device_{add|remove}_group() helpers
driver core: add devm_device_add_group() and friends
Input: gpio_keys - use devm_device_add_group() for attributes
Input: synaptics_rmi4 - use devm_device_add_group() for attributes in F01
Input: axp20x-pek - switch to using devm_device_add_group()

 drivers/base/base.h                |   5 --
 drivers/base/core.c                | 132 +++++++++++++++++++++++++++++++++++++
 drivers/base/dd.c                  |   4 ++
 drivers/input/keyboard/gpio_keys.c |  16 +----
 drivers/input/misc/axp20x-pek.c    |  18 +----
 drivers/input/rmi4/rmi_f01.c       |  11 +---
 include/linux/device.h             |  30 +++++++++
 include/linux/kobject.h            |   2 +
 lib/kobject_uevent.c               |   2 +
 9 files changed, 176 insertions(+), 44 deletions(-)

-- >8 --

Quoted 1 line

From 6d10e621578dffcca0ad785e4a73196aa25350f6 Mon Sep 17 00:00:00 2001

From: Dmitry Torokhov <[email protected]>
Date: Mon, 17 Jul 2017 20:10:17 -0700
Subject: [PATCH] Add handling for bind/unbind actions

Newer kernels will emit uevents with "bind" and "unbind" actions. These uevents will be issued when driver is bound to or unbound from a device. "Bind" events are helpful when device requires a firmware to operate properly, and driver is unable to create a child device before firmware is properly loaded.

For some reason systemd validates actions and drops the ones it does not know, instead of passing them on through as old udev did, so we need to explicitly teach it about them.

---
 src/libsystemd/sd-device/device-internal.h | 2 ++
 src/libsystemd/sd-device/device-private.c  | 2 ++
 2 files changed, 4 insertions(+)
src/libsystemd/sd-device/device-internal.h +2 -0
index f4783deef..0505a2730 100644
@@ -104,6 +104,8 @@ typedef enum DeviceAction {
         DEVICE_ACTION_MOVE,
         DEVICE_ACTION_ONLINE,
         DEVICE_ACTION_OFFLINE,
+        DEVICE_ACTION_BIND,
+        DEVICE_ACTION_UNBIND,
         _DEVICE_ACTION_MAX,
         _DEVICE_ACTION_INVALID = -1,
 } DeviceAction;
src/libsystemd/sd-device/device-private.c +2 -0
index b4cd676c1..8839c3266 100644
@@ -466,6 +466,8 @@ static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
         [DEVICE_ACTION_MOVE] = "move",
         [DEVICE_ACTION_ONLINE] = "online",
         [DEVICE_ACTION_OFFLINE] = "offline",
+        [DEVICE_ACTION_BIND] = "bind",
+        [DEVICE_ACTION_UNBIND] = "unbind",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
author maintainer
#1 lore raw

PATCH v2 1/7 driver core: emit uevents when device is bound to a driver

There are certain touch controllers that may come up in either normal (application) or boot mode, depending on whether firmware/configuration is corrupted when they are powered on. In boot mode the kernel does not create input device instance (because it does not necessarily know the characteristics of the input device in question).

Another number of controllers does not store firmware in a non-volatile memory, and they similarly need to have firmware loaded before input device instance is created. There are also other types of devices with similar behavior.

There is a desire to be able to trigger firmware loading via udev, but it has to happen only when driver is bound to a physical device (i2c or spi). These udev actions can not use ADD events, as those happen too early, so we are introducing BIND and UNBIND events that are emitted at the right moment.

Also, many drivers create additional driver-specific device attributes when binding to the device, to provide userspace with additional controls. The new events allow userspace to adjust these driver-specific attributes without worrying that they are not there yet.

---
 drivers/base/dd.c       | 4 ++++
 include/linux/kobject.h | 2 ++
 lib/kobject_uevent.c    | 2 ++
 3 files changed, 8 insertions(+)
drivers/base/dd.c +4 -0
index 4882f06d12df..c17fefc77345 100644
@@ -259,6 +259,8 @@ static void driver_bound(struct device *dev)
 	if (dev->bus)
 		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_BOUND_DRIVER, dev);
+
+	kobject_uevent(&dev->kobj, KOBJ_BIND);
 }
 
 static int driver_sysfs_add(struct device *dev)
@@ -848,6 +850,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
 			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 						     BUS_NOTIFY_UNBOUND_DRIVER,
 						     dev);
+
+		kobject_uevent(&dev->kobj, KOBJ_UNBIND);
 	}
 }
 
include/linux/kobject.h +2 -0
index ca85cb80e99a..12f5ddccb97c 100644
@@ -57,6 +57,8 @@ enum kobject_action {
 	KOBJ_MOVE,
 	KOBJ_ONLINE,
 	KOBJ_OFFLINE,
+	KOBJ_BIND,
+	KOBJ_UNBIND,
 	KOBJ_MAX
 };
 
lib/kobject_uevent.c +2 -0
index 9a2b811966eb..4682e8545b5c 100644
@@ -50,6 +50,8 @@ static const char *kobject_actions[] = {
 	[KOBJ_MOVE] =		"move",
 	[KOBJ_ONLINE] =		"online",
 	[KOBJ_OFFLINE] =	"offline",
+	[KOBJ_BIND] =		"bind",
+	[KOBJ_UNBIND] =		"unbind",
 };
 
 /**
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
#2 lore raw

Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 17 lines · Dmitry Torokhov

There are certain touch controllers that may come up in either normal (application) or boot mode, depending on whether firmware/configuration is corrupted when they are powered on. In boot mode the kernel does not create input device instance (because it does not necessarily know the characteristics of the input device in question).

Another number of controllers does not store firmware in a non-volatile memory, and they similarly need to have firmware loaded before input device instance is created. There are also other types of devices with similar behavior.

There is a desire to be able to trigger firmware loading via udev, but it has to happen only when driver is bound to a physical device (i2c or spi). These udev actions can not use ADD events, as those happen too early, so we are introducing BIND and UNBIND events that are emitted at the right moment.

Quoted 6 lines

Also, many drivers create additional driver-specific device attributes when binding to the device, to provide userspace with additional controls. The new events allow userspace to adjust these driver-specific attributes without worrying that they are not there yet.

Hi Dmitry,

Mike (cc'd) reports a regression with this change:

---

Previously, if I did:

# rmmod hfi1

The driver would be removed.

With 4.14.0-rc2+, when I remove the driver, the PCI bus is automatically re-probed and the driver re-loaded.

---

A bisect points to commit 1455cf8dbfd0 "driver core: emit uevents when device is bound to a driver". I'm sending this because I have this mail in my archive, but I'll let Mike follow up with any other details.

#3 lore raw

RE: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 57 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Dan Williams
Sent: Friday, September 29, 2017 3:37 PM
To: Dmitry Torokhov <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>; Tejun Heo <[email protected]>; Linux Kernel Mailing List <linux- [email protected]>; Guenter Roeck <[email protected]>; Ruhl, Michael J <[email protected]>
Subject: Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 2 lines · Dmitry Torokhov

There are certain touch controllers that may come up in either normal (application) or boot mode, depending on whether firmware/configuration

is

Quoted 1 line

corrupted when they are powered on. In boot mode the kernel does not

create

Quoted 5 lines

input device instance (because it does not necessarily know the characteristics of the input device in question).

Another number of controllers does not store firmware in a non-volatile memory, and they similarly need to have firmware loaded before input

device

Quoted 6 lines

instance is created. There are also other types of devices with similar behavior.

There is a desire to be able to trigger firmware loading via udev, but it has to happen only when driver is bound to a physical device (i2c or spi). These udev actions can not use ADD events, as those happen too early, so

we

Quoted 9 lines

are introducing BIND and UNBIND events that are emitted at the right moment.

Also, many drivers create additional driver-specific device attributes when binding to the device, to provide userspace with additional controls. The new events allow userspace to adjust these driver-specific attributes without worrying that they are not there yet.

Hi Dmitry,

Mike (cc'd) reports a regression with this change:

---

Previously, if I did:

# rmmod hfi1

The driver would be removed.

With 4.14.0-rc2+, when I remove the driver, the PCI bus is automatically re-probed and the driver re-loaded.

Quoted 6 lines

---

A bisect points to commit 1455cf8dbfd0 "driver core: emit uevents when device is bound to a driver". I'm sending this because I have this mail in my archive, but I'll let Mike follow up with any other details.

My test environment is RedHat 7.3 GA + 4.14.0-rc2 kernel.

Blacklisting the driver keeps it from being autoloaded, but this didn't seem correct.

With the 4.13.x branch this did not occur

Thanks,

Mike

author maintainer
#4 lore raw

Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 64 lines · Michael J
Quoted 57 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Dan Williams
Sent: Friday, September 29, 2017 3:37 PM
To: Dmitry Torokhov <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>; Tejun Heo <[email protected]>; Linux Kernel Mailing List <linux- [email protected]>; Guenter Roeck <[email protected]>; Ruhl, Michael J <[email protected]>
Subject: Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 2 lines · Dmitry Torokhov

There are certain touch controllers that may come up in either normal (application) or boot mode, depending on whether firmware/configuration

is

Quoted 1 line

corrupted when they are powered on. In boot mode the kernel does not

create

Quoted 5 lines

input device instance (because it does not necessarily know the characteristics of the input device in question).

Another number of controllers does not store firmware in a non-volatile memory, and they similarly need to have firmware loaded before input

device

Quoted 6 lines

instance is created. There are also other types of devices with similar behavior.

There is a desire to be able to trigger firmware loading via udev, but it has to happen only when driver is bound to a physical device (i2c or spi). These udev actions can not use ADD events, as those happen too early, so

we

Quoted 9 lines

are introducing BIND and UNBIND events that are emitted at the right moment.

Also, many drivers create additional driver-specific device attributes when binding to the device, to provide userspace with additional controls. The new events allow userspace to adjust these driver-specific attributes without worrying that they are not there yet.

Hi Dmitry,

Mike (cc'd) reports a regression with this change:

---

Previously, if I did:

# rmmod hfi1

The driver would be removed.

With 4.14.0-rc2+, when I remove the driver, the PCI bus is automatically re-probed and the driver re-loaded.

Quoted 6 lines

---

A bisect points to commit 1455cf8dbfd0 "driver core: emit uevents when device is bound to a driver". I'm sending this because I have this mail in my archive, but I'll let Mike follow up with any other details.

Quoted 5 lines

My test environment is RedHat 7.3 GA + 4.14.0-rc2 kernel.

Blacklisting the driver keeps it from being autoloaded, but this didn't seem correct.

With the 4.13.x branch this did not occur

Yeah, udev is being stupid. Either change ACTION=="remove" to ACTION!="add" in /lib/udev/rules.d/80-drivers.rules or pick this patch:

https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git/commit/?h=driver-core-linus&id=6878e7de6af726de47f9f3bec649c3f49e786586

Thanks.

Signature · 1 line
Dmitry
#5 lore raw

Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 67 lines · Dmitry Torokhov
Quoted 66 lines · Michael J
Quoted 57 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Dan Williams
Sent: Friday, September 29, 2017 3:37 PM
To: Dmitry Torokhov <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>; Tejun Heo <[email protected]>; Linux Kernel Mailing List <linux- [email protected]>; Guenter Roeck <[email protected]>; Ruhl, Michael J <[email protected]>
Subject: Re: [PATCH v2 1/7] driver core: emit uevents when device is bound to a driver

Quoted 2 lines · Dmitry Torokhov

There are certain touch controllers that may come up in either normal (application) or boot mode, depending on whether firmware/configuration

is

Quoted 1 line

corrupted when they are powered on. In boot mode the kernel does not

create

Quoted 5 lines

input device instance (because it does not necessarily know the characteristics of the input device in question).

Another number of controllers does not store firmware in a non-volatile memory, and they similarly need to have firmware loaded before input

device

Quoted 6 lines

instance is created. There are also other types of devices with similar behavior.

There is a desire to be able to trigger firmware loading via udev, but it has to happen only when driver is bound to a physical device (i2c or spi). These udev actions can not use ADD events, as those happen too early, so

we

Quoted 9 lines

are introducing BIND and UNBIND events that are emitted at the right moment.

Also, many drivers create additional driver-specific device attributes when binding to the device, to provide userspace with additional controls. The new events allow userspace to adjust these driver-specific attributes without worrying that they are not there yet.

Hi Dmitry,

Mike (cc'd) reports a regression with this change:

---

Previously, if I did:

# rmmod hfi1

The driver would be removed.

With 4.14.0-rc2+, when I remove the driver, the PCI bus is automatically re-probed and the driver re-loaded.

Quoted 6 lines

---

A bisect points to commit 1455cf8dbfd0 "driver core: emit uevents when device is bound to a driver". I'm sending this because I have this mail in my archive, but I'll let Mike follow up with any other details.

My test environment is RedHat 7.3 GA + 4.14.0-rc2 kernel.

Quoted 8 lines
Quoted 3 lines

Blacklisting the driver keeps it from being autoloaded, but this didn't seem correct.

With the 4.13.x branch this did not occur

Yeah, udev is being stupid. Either change ACTION=="remove" to ACTION!="add" in /lib/udev/rules.d/80-drivers.rules or pick this patch:

https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git/commit/?h=driver-core-linus&id=6878e7de6af726de47f9f3bec649c3f49e786586

I have this fix queued up for Linus, sorry for the delay in getting it to him, hope to do that today...

thanks,

greg k-h

author maintainer
#6 lore raw

PATCH v2 2/7 driver core: make device_{add|remove}_groups() public

In reply to Dmitry Torokhov

Many drivers create additional driver-specific device attributes when binding to the device. To avoid them calling SYSFS API directly, let's export these helpers.

---
 drivers/base/base.h    | 5 -----
 drivers/base/core.c    | 2 ++
 include/linux/device.h | 5 +++++
 3 files changed, 7 insertions(+), 5 deletions(-)
drivers/base/base.h +0 -5
index e19b1008e5fb..539432a14b5c 100644
@@ -126,11 +126,6 @@ extern int driver_add_groups(struct device_driver *drv,
 extern void driver_remove_groups(struct device_driver *drv,
 				 const struct attribute_group **groups);
 
-extern int device_add_groups(struct device *dev,
-			     const struct attribute_group **groups);
-extern void device_remove_groups(struct device *dev,
-				 const struct attribute_group **groups);
-
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
drivers/base/core.c +2 -0
index bbecaf9293be..14f8cf5c8b05 100644
@@ -1026,12 +1026,14 @@ int device_add_groups(struct device *dev, const struct attribute_group **groups)
 {
 	return sysfs_create_groups(&dev->kobj, groups);
 }
+EXPORT_SYMBOL_GPL(device_add_groups);
 
 void device_remove_groups(struct device *dev,
 			  const struct attribute_group **groups)
 {
 	sysfs_remove_groups(&dev->kobj, groups);
 }
+EXPORT_SYMBOL_GPL(device_remove_groups);
 
 static int device_add_attrs(struct device *dev)
 {
include/linux/device.h +5 -0
index 9ef518af5515..10cf209a4e82 100644
@@ -1200,6 +1200,11 @@ struct device *device_create_with_groups(struct class *cls,
 			     const char *fmt, ...);
 extern void device_destroy(struct class *cls, dev_t devt);
 
+extern int __must_check device_add_groups(struct device *dev,
+					const struct attribute_group **groups);
+extern void device_remove_groups(struct device *dev,
+				 const struct attribute_group **groups);
+
 /*
  * Platform "fixup" functions - allow the platform to have their say
  * about devices and actions that the general device layer doesn't
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
author maintainer
#7 lore raw

PATCH v2 3/7 driver core: add device_{add|remove}_group() helpers

In reply to Dmitry Torokhov

We have helpers that work with NULL terminated array of groups, but many drivers only create a single supplemental group, and do not want to declare a group array. Let's provide them with helpers working with a single group.

---
 include/linux/device.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/device.h +16 -0
index 10cf209a4e82..7698a513b35e 100644
@@ -1205,6 +1205,22 @@ extern int __must_check device_add_groups(struct device *dev,
 extern void device_remove_groups(struct device *dev,
 				 const struct attribute_group **groups);
 
+static inline int __must_check device_add_group(struct device *dev,
+					const struct attribute_group *grp)
+{
+	const struct attribute_group *groups[] = { grp, NULL };
+
+	return device_add_groups(dev, groups);
+}
+
+static inline void device_remove_group(struct device *dev,
+				       const struct attribute_group *grp)
+{
+	const struct attribute_group *groups[] = { grp, NULL };
+
+	return device_remove_groups(dev, groups);
+}
+
 /*
  * Platform "fixup" functions - allow the platform to have their say
  * about devices and actions that the general device layer doesn't
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
author maintainer
#8 lore raw

PATCH v2 4/7 driver core: add devm_device_add_group() and friends

In reply to Dmitry Torokhov

Many drivers create additional driver-specific device attributes when binding to the device, and providing managed version of device_create_group() will simplify unbinding and error handling in probe path for such drivers.

Without managed version driver writers either have to mix manual and managed resources, which is prone to errors, or open-code this function by providing a wrapper to device_add_group() and use it with devm_add_action() or devm_add_action_or_reset().

---
 drivers/base/core.c    | 130 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |   9 ++++
 2 files changed, 139 insertions(+)
drivers/base/core.c +130 -0
index 14f8cf5c8b05..09723532725d 100644
@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(device_remove_groups);
 
+union device_attr_group_devres {
+	const struct attribute_group *group;
+	const struct attribute_group **groups;
+};
+
+static int devm_attr_group_match(struct device *dev, void *res, void *data)
+{
+	return ((union device_attr_group_devres *)res)->group == data;
+}
+
+static void devm_attr_group_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static void devm_attr_groups_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group **groups = devres->groups;
+
+	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
+	sysfs_remove_groups(&dev->kobj, groups);
+}
+
+/**
+ * devm_device_add_group - given a device, create a managed attribute group
+ * @dev:	The device to create the group for
+ * @grp:	The attribute group to create
+ *
+ * This function creates a group for the first time.  It will explicitly
+ * warn and error if any of the attribute files being created already exist.
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_device_add_group(struct device *dev, const struct attribute_group *grp)
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_group_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_group(&dev->kobj, grp);
+	if (error) {
+		devres_free(devres);
+		return error;
+	}
+
+	devres->group = grp;
+	devres_add(dev, devres);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_device_add_group);
+
+/**
+ * devm_device_remove_group: remove a managed group from a device
+ * @dev:	device to remove the group from
+ * @grp:	group to remove
+ *
+ * This function removes a group of attributes from a device. The attributes
+ * previously have to have been created for this group, otherwise it will fail.
+ */
+void devm_device_remove_group(struct device *dev,
+			      const struct attribute_group *grp)
+{
+	WARN_ON(devres_release(dev, devm_attr_group_remove,
+			       devm_attr_group_match,
+			       /* cast away const */ (void *)grp));
+}
+EXPORT_SYMBOL_GPL(devm_device_remove_group);
+
+/**
+ * devm_device_add_groups - create a bunch of managed attribute groups
+ * @dev:	The device to create the group for
+ * @groups:	The attribute groups to create, NULL terminated
+ *
+ * This function creates a bunch of managed attribute groups.  If an error
+ * occurs when creating a group, all previously created groups will be
+ * removed, unwinding everything back to the original state when this
+ * function was called.  It will explicitly warn and error if any of the
+ * attribute files being created already exist.
+ *
+ * Returns 0 on success or error code from sysfs_create_group on failure.
+ */
+int devm_device_add_groups(struct device *dev,
+			   const struct attribute_group **groups)
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_groups_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_groups(&dev->kobj, groups);
+	if (error) {
+		devres_free(devres);
+		return error;
+	}
+
+	devres->groups = groups;
+	devres_add(dev, devres);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_device_add_groups);
+
+/**
+ * devm_device_remove_groups - remove a list of managed groups
+ *
+ * @dev:	The device for the groups to be removed from
+ * @groups:	NULL terminated list of groups to be removed
+ *
+ * If groups is not NULL, remove the specified groups from the device.
+ */
+void devm_device_remove_groups(struct device *dev,
+			       const struct attribute_group **groups)
+{
+	WARN_ON(devres_release(dev, devm_attr_groups_remove,
+			       devm_attr_group_match,
+			       /* cast away const */ (void *)groups));
+}
+EXPORT_SYMBOL_GPL(devm_device_remove_groups);
+
 static int device_add_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
include/linux/device.h +9 -0
index 7698a513b35e..f52288c24734 100644
@@ -1221,6 +1221,15 @@ static inline void device_remove_group(struct device *dev,
 	return device_remove_groups(dev, groups);
 }
 
+extern int __must_check devm_device_add_groups(struct device *dev,
+					const struct attribute_group **groups);
+extern void devm_device_remove_groups(struct device *dev,
+				      const struct attribute_group **groups);
+extern int __must_check devm_device_add_group(struct device *dev,
+					const struct attribute_group *grp);
+extern void devm_device_remove_group(struct device *dev,
+				     const struct attribute_group *grp);
+
 /*
  * Platform "fixup" functions - allow the platform to have their say
  * about devices and actions that the general device layer doesn't
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
#9 lore raw

Re: [PATCH v2 4/7] driver core: add devm_device_add_group() and friends

Quoted 63 lines · Dmitry Torokhov

Many drivers create additional driver-specific device attributes when binding to the device, and providing managed version of device_create_group() will simplify unbinding and error handling in probe path for such drivers.

Without managed version driver writers either have to mix manual and managed resources, which is prone to errors, or open-code this function by providing a wrapper to device_add_group() and use it with devm_add_action() or devm_add_action_or_reset().

---
 drivers/base/core.c    | 130 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |   9 ++++
 2 files changed, 139 insertions(+)
drivers/base/core.c +39 -0
index 14f8cf5c8b05..09723532725d 100644
@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(device_remove_groups);
 
+union device_attr_group_devres {
+	const struct attribute_group *group;
+	const struct attribute_group **groups;
+};
+
+static int devm_attr_group_match(struct device *dev, void *res, void *data)
+{
+	return ((union device_attr_group_devres *)res)->group == data;
+}
+
+static void devm_attr_group_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static void devm_attr_groups_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group **groups = devres->groups;
+
+	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
+	sysfs_remove_groups(&dev->kobj, groups);
+}
+
+/**
+ * devm_device_add_group - given a device, create a managed attribute group
+ * @dev:	The device to create the group for
+ * @grp:	The attribute group to create
+ *
+ * This function creates a group for the first time.  It will explicitly
+ * warn and error if any of the attribute files being created already exist.
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_device_add_group(struct device *dev, const struct attribute_group *grp)

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1086

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_group_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_group(&dev->kobj, grp);

Minor nit, this can now call device_create_group(), right?

Same with below I think as well.

It's fine, these look great, I'll queue them up this afternoon...

Thanks for persisting with these, and sorry it took so long to convince me I was wrong :)

greg k-h

author maintainer
#10 lore raw

Re: [PATCH v2 4/7] driver core: add devm_device_add_group() and friends

Quoted 86 lines · Greg Kroah-Hartman
Quoted 3 lines · Dmitry Torokhov

Many drivers create additional driver-specific device attributes when binding to the device, and providing managed version of device_create_group() will simplify unbinding and error handling in

probe

Quoted 4 lines

path for such drivers.

Without managed version driver writers either have to mix manual and managed resources, which is prone to errors, or open-code this

function by

Quoted 1 line

providing a wrapper to device_add_group() and use it with

devm_add_action()

Quoted 5 lines

or devm_add_action_or_reset().

---
 drivers/base/core.c    | 130

+++++++++++++++++++++++++++++++++++++++++++++++++

Quoted 8 lines
 include/linux/device.h |   9 ++++
 2 files changed, 139 insertions(+)
drivers/base/core.c +0 -0
index 14f8cf5c8b05..09723532725d 100644

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1043

Quoted 9 lines
drivers/base/core.c +6 -0
@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(device_remove_groups);
 
+union device_attr_group_devres {
+	const struct attribute_group *group;
+	const struct attribute_group **groups;
+};
+
+static int devm_attr_group_match(struct device *dev, void *res, void

*data)

Quoted 14 lines
drivers/base/core.c +14 -0
+{
+	return ((union device_attr_group_devres *)res)->group == data;
+}
+
+static void devm_attr_group_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static void devm_attr_groups_remove(struct device *dev, void *res)

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group **groups = devres->groups;
+
+	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
+	sysfs_remove_groups(&dev->kobj, groups);
+}
+
+/**
+ * devm_device_add_group - given a device, create a managed

attribute group

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ * @dev:	The device to create the group for
+ * @grp:	The attribute group to create
+ *
+ * This function creates a group for the first time.  It will

explicitly

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1072

Quoted 1 line
drivers/base/core.c +1 -0
+ * warn and error if any of the attribute files being created

already exist.

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_device_add_group(struct device *dev, const struct

attribute_group *grp)

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1086

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_group_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_group(&dev->kobj, grp);

Minor nit, this can now call device_create_group(), right?

Quoted 1 line

Same with below I think as well.

Right.

Quoted 5 lines

It's fine, these look great, I'll queue them up this afternoon...

Thanks for persisting with these, and sorry it took so long to convince me I was wrong :)

:)

Any chance you could create an unmutable branch off 4.12 so I can start using it in input drivers?

Thanks.

Signature · 1 line
Dmitry
#11 lore raw

Re: [PATCH v2 4/7] driver core: add devm_device_add_group() and friends

Quoted 92 lines · Dmitry Torokhov
Quoted 86 lines · Greg Kroah-Hartman
Quoted 3 lines · Dmitry Torokhov

Many drivers create additional driver-specific device attributes when binding to the device, and providing managed version of device_create_group() will simplify unbinding and error handling in

probe

Quoted 4 lines

path for such drivers.

Without managed version driver writers either have to mix manual and managed resources, which is prone to errors, or open-code this

function by

Quoted 1 line

providing a wrapper to device_add_group() and use it with

devm_add_action()

Quoted 5 lines

or devm_add_action_or_reset().

---
 drivers/base/core.c    | 130

+++++++++++++++++++++++++++++++++++++++++++++++++

Quoted 8 lines
 include/linux/device.h |   9 ++++
 2 files changed, 139 insertions(+)
drivers/base/core.c +0 -0
index 14f8cf5c8b05..09723532725d 100644

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1043

Quoted 9 lines
drivers/base/core.c +6 -0
@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(device_remove_groups);
 
+union device_attr_group_devres {
+	const struct attribute_group *group;
+	const struct attribute_group **groups;
+};
+
+static int devm_attr_group_match(struct device *dev, void *res, void

*data)

Quoted 14 lines
drivers/base/core.c +14 -0
+{
+	return ((union device_attr_group_devres *)res)->group == data;
+}
+
+static void devm_attr_group_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static void devm_attr_groups_remove(struct device *dev, void *res)

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group **groups = devres->groups;
+
+	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
+	sysfs_remove_groups(&dev->kobj, groups);
+}
+
+/**
+ * devm_device_add_group - given a device, create a managed

attribute group

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ * @dev:	The device to create the group for
+ * @grp:	The attribute group to create
+ *
+ * This function creates a group for the first time.  It will

explicitly

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1072

Quoted 1 line
drivers/base/core.c +1 -0
+ * warn and error if any of the attribute files being created

already exist.

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_device_add_group(struct device *dev, const struct

attribute_group *grp)

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1086

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_group_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_group(&dev->kobj, grp);

Minor nit, this can now call device_create_group(), right?

Quoted 1 line

Same with below I think as well.

Right.

Quoted 1 line
Quoted 8 lines
Quoted 4 lines

It's fine, these look great, I'll queue them up this afternoon...

Thanks for persisting with these, and sorry it took so long to convince me I was wrong :)

:)

Any chance you could create an unmutable branch off 4.12 so I can start using it in input drivers?

I'll be glad to, can it be off of 4.13-rc1? Or do you need it off of 4.12?

thanks,

greg k-h

author maintainer
#12 lore raw

Re: [PATCH v2 4/7] driver core: add devm_device_add_group() and friends

Quoted 106 lines · Greg Kroah-Hartman
Quoted 1 line · Dmitry Torokhov

On July 19, 2017 10:10:18 PM PDT, Greg Kroah-Hartman

Quoted 2 lines · <[email protected]> wrote:
Quoted 2 lines · Dmitry Torokhov
Quoted 1 line

Many drivers create additional driver-specific device attributes

when

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

binding to the device, and providing managed version of device_create_group() will simplify unbinding and error handling

in

Quoted 4 lines
Quoted 4 lines

probe

Quoted 3 lines

path for such drivers.

Without managed version driver writers either have to mix manual

and

Quoted 10 lines
Quoted 10 lines
Quoted 1 line

managed resources, which is prone to errors, or open-code this

function by

Quoted 1 line

providing a wrapper to device_add_group() and use it with

devm_add_action()

Quoted 5 lines

or devm_add_action_or_reset().

---
 drivers/base/core.c    | 130

+++++++++++++++++++++++++++++++++++++++++++++++++

Quoted 8 lines
Quoted 8 lines

drivers/base/core.c void device_remove_groups(struct device

Quoted 8 lines
 include/linux/device.h |   9 ++++
 2 files changed, 139 insertions(+)
drivers/base/core.c +0 -0
index 14f8cf5c8b05..09723532725d 100644
@@ -1035,6 +1035,136 @@ void device_remove_groups(struct device

*dev,

Quoted 9 lines
Quoted 9 lines

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 9 lines
drivers/base/core.c +6 -0
 }
 EXPORT_SYMBOL_GPL(device_remove_groups);
 
+union device_attr_group_devres {
+	const struct attribute_group *group;
+	const struct attribute_group **groups;
+};
+
+static int devm_attr_group_match(struct device *dev, void *res,

void

Quoted 15 lines
Quoted 15 lines

*data)

Quoted 4 lines
drivers/base/core.c +4 -0
+{
+	return ((union device_attr_group_devres *)res)->group == data;
+}
+

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 10 lines
drivers/base/core.c +10 -0
+static void devm_attr_group_remove(struct device *dev, void *res)
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static void devm_attr_groups_remove(struct device *dev, void

*res)

Quoted 36 lines
Quoted 36 lines

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres = res;
+	const struct attribute_group **groups = devres->groups;
+
+	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
+	sysfs_remove_groups(&dev->kobj, groups);
+}
+
+/**
+ * devm_device_add_group - given a device, create a managed

attribute group

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ * @dev:	The device to create the group for
+ * @grp:	The attribute group to create
+ *
+ * This function creates a group for the first time.  It will

explicitly

drivers/base/core.c void device_remove_groups(struct device · line 1072

Quoted 1 line
drivers/base/core.c +1 -0
+ * warn and error if any of the attribute files being created

already exist.

drivers/base/core.c void device_remove_groups(struct device *dev,

Quoted 4 lines
drivers/base/core.c +4 -0
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_device_add_group(struct device *dev, const struct

attribute_group *grp)

drivers/base/core.c void device_remove_groups(struct device *dev, · line 1086

Quoted 10 lines
drivers/base/core.c +10 -0
+{
+	union device_attr_group_devres *devres;
+	int error;
+
+	devres = devres_alloc(devm_attr_group_remove,
+			      sizeof(*devres), GFP_KERNEL);
+	if (!devres)
+		return -ENOMEM;
+
+	error = sysfs_create_group(&dev->kobj, grp);

Minor nit, this can now call device_create_group(), right?

Quoted 8 lines
Quoted 1 line

Same with below I think as well.

Right.

Quoted 4 lines

It's fine, these look great, I'll queue them up this afternoon...

Thanks for persisting with these, and sorry it took so long to

convince

Quoted 2 lines
Quoted 1 line

me I was wrong :)

Quoted 7 lines
Quoted 3 lines

:)

Any chance you could create an unmutable branch off 4.12 so I can

start using it in input drivers?

I'll be glad to, can it be off of 4.13-rc1? Or do you need it off of 4.12?

It's just my preference for topic branches to be off a stable[r] releases, unless patches do not apply cleanly or will lead to merge conflicts down the road.

Thanks!

Signature · 1 line
Dmitry
#13 lore raw

Re: [PATCH v2 4/7] driver core: add devm_device_add_group() and friends

Quoted 11 lines · Dmitry Torokhov
Quoted 6 lines · Greg Kroah-Hartman
Quoted 1 line · Dmitry Torokhov

Any chance you could create an unmutable branch off 4.12 so I can

start using it in input drivers?

I'll be glad to, can it be off of 4.13-rc1? Or do you need it off of 4.12?

It's just my preference for topic branches to be off a stable[r] releases, unless patches do not apply cleanly or will lead to merge conflicts down the road.

I've now created this, it's based off of 4.12 and can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git/ bind_unbind

If there are any problems with it, please let me know.

I've also pulled this branch into my driver_core-next branch so that I can base stuff off of it as well. Heck, I might go fix up some USB drivers now too, so it might end up there...

thanks,

greg k-h

author maintainer
#14 lore raw

PATCH v2 5/7 Input: gpio_keys - use devm_device_add_group() for attributes

In reply to Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's start using it instead of the manual unwinding.

---
 drivers/input/keyboard/gpio_keys.c | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)
drivers/input/keyboard/gpio_keys.c +2 -14
index f52812db91bc..e9f0ebf3267a 100644
@@ -827,7 +827,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
 
 	fwnode_handle_put(child);
 
-	error = sysfs_create_group(&dev->kobj, &gpio_keys_attr_group);
+	error = devm_device_add_group(dev, &gpio_keys_attr_group);
 	if (error) {
 		dev_err(dev, "Unable to export keys/switches, error: %d\n",
 			error);
@@ -838,22 +838,11 @@ static int gpio_keys_probe(struct platform_device *pdev)
 	if (error) {
 		dev_err(dev, "Unable to register input device, error: %d\n",
 			error);
-		goto err_remove_group;
+		return error;
 	}
 
 	device_init_wakeup(dev, wakeup);
 
-	return 0;
-
-err_remove_group:
-	sysfs_remove_group(&dev->kobj, &gpio_keys_attr_group);
-	return error;
-}
-
-static int gpio_keys_remove(struct platform_device *pdev)
-{
-	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
-
 	return 0;
 }
 
@@ -912,7 +901,6 @@ static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
 static struct platform_driver gpio_keys_device_driver = {
 	.probe		= gpio_keys_probe,
-	.remove		= gpio_keys_remove,
 	.driver		= {
 		.name	= "gpio-keys",
 		.pm	= &gpio_keys_pm_ops,
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
Reviewed-by on v2 5/7
#15 lore raw

Re: [PATCH v2 5/7] Input: gpio_keys - use devm_device_add_group() for attributes

Quoted 4 lines · Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's start using it instead of the manual unwinding.

Quoted 50 lines
---
  drivers/input/keyboard/gpio_keys.c | 16 ++--------------
  1 file changed, 2 insertions(+), 14 deletions(-)
drivers/input/keyboard/gpio_keys.c +2 -14
index f52812db91bc..e9f0ebf3267a 100644
@@ -827,7 +827,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
 
  	fwnode_handle_put(child);
 
-	error = sysfs_create_group(&dev->kobj, &gpio_keys_attr_group);
+	error = devm_device_add_group(dev, &gpio_keys_attr_group);
  	if (error) {
  		dev_err(dev, "Unable to export keys/switches, error: %d\n",
  			error);
@@ -838,22 +838,11 @@ static int gpio_keys_probe(struct platform_device *pdev)
  	if (error) {
  		dev_err(dev, "Unable to register input device, error: %d\n",
  			error);
-		goto err_remove_group;
+		return error;
  	}
 
  	device_init_wakeup(dev, wakeup);
 
-	return 0;
-
-err_remove_group:
-	sysfs_remove_group(&dev->kobj, &gpio_keys_attr_group);
-	return error;
-}
-
-static int gpio_keys_remove(struct platform_device *pdev)
-{
-	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
-
  	return 0;
  }
 
@@ -912,7 +901,6 @@ static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
  static struct platform_driver gpio_keys_device_driver = {
  	.probe		= gpio_keys_probe,
-	.remove		= gpio_keys_remove,
  	.driver		= {
  		.name	= "gpio-keys",
  		.pm	= &gpio_keys_pm_ops,
author maintainer
#16 lore raw

PATCH v2 6/7 Input: synaptics_rmi4 - use devm_device_add_group() for attributes in F01

In reply to Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's start using it instead of the manual unwinding.

---
 drivers/input/rmi4/rmi_f01.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)
drivers/input/rmi4/rmi_f01.c +3 -8
index aa1aabfdbe7c..ae966e333a2f 100644
@@ -570,18 +570,14 @@ static int rmi_f01_probe(struct rmi_function *fn)
 
 	dev_set_drvdata(&fn->dev, f01);
 
-	error = sysfs_create_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
+	error = devm_device_add_group(&fn->rmi_dev->dev, &rmi_f01_attr_group);
 	if (error)
-		dev_warn(&fn->dev, "Failed to create sysfs group: %d\n", error);
+		dev_warn(&fn->dev,
+			 "Failed to create attribute group: %d\n", error);
 
 	return 0;
 }
 
-static void rmi_f01_remove(struct rmi_function *fn)
-{
-	sysfs_remove_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
-}
-
 static int rmi_f01_config(struct rmi_function *fn)
 {
 	struct f01_data *f01 = dev_get_drvdata(&fn->dev);
@@ -721,7 +717,6 @@ struct rmi_function_handler rmi_f01_handler = {
 	},
 	.func		= 0x01,
 	.probe		= rmi_f01_probe,
-	.remove		= rmi_f01_remove,
 	.config		= rmi_f01_config,
 	.attention	= rmi_f01_attention,
 	.suspend	= rmi_f01_suspend,
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
Reviewed-by on v2 6/7
#17 lore raw

Re: [PATCH v2 6/7] Input: synaptics_rmi4 - use devm_device_add_group() for attributes in F01

Quoted 4 lines · Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's start using it instead of the manual unwinding.

Quoted 39 lines
---
  drivers/input/rmi4/rmi_f01.c | 11 +++--------
  1 file changed, 3 insertions(+), 8 deletions(-)
drivers/input/rmi4/rmi_f01.c +3 -8
index aa1aabfdbe7c..ae966e333a2f 100644
@@ -570,18 +570,14 @@ static int rmi_f01_probe(struct rmi_function *fn)
 
  	dev_set_drvdata(&fn->dev, f01);
 
-	error = sysfs_create_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
+	error = devm_device_add_group(&fn->rmi_dev->dev, &rmi_f01_attr_group);
  	if (error)
-		dev_warn(&fn->dev, "Failed to create sysfs group: %d\n", error);
+		dev_warn(&fn->dev,
+			 "Failed to create attribute group: %d\n", error);
 
  	return 0;
  }
 
-static void rmi_f01_remove(struct rmi_function *fn)
-{
-	sysfs_remove_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
-}
-
  static int rmi_f01_config(struct rmi_function *fn)
  {
  	struct f01_data *f01 = dev_get_drvdata(&fn->dev);
@@ -721,7 +717,6 @@ struct rmi_function_handler rmi_f01_handler = {
  	},
  	.func		= 0x01,
  	.probe		= rmi_f01_probe,
-	.remove		= rmi_f01_remove,
  	.config		= rmi_f01_config,
  	.attention	= rmi_f01_attention,
  	.suspend	= rmi_f01_suspend,
author maintainer
#18 lore raw

PATCH v2 7/7 Input: axp20x-pek - switch to using devm_device_add_group()

In reply to Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's use it instead of installing a custom devm action.

---
 drivers/input/misc/axp20x-pek.c | 18 +-----------------
 1 file changed, 1 insertion(+), 17 deletions(-)
drivers/input/misc/axp20x-pek.c +1 -17
index 38c79ebff033..cfeb0e943de6 100644
@@ -182,13 +182,6 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
 	return IRQ_HANDLED;
 }
 
-static void axp20x_remove_sysfs_group(void *_data)
-{
-	struct device *dev = _data;
-
-	sysfs_remove_group(&dev->kobj, &axp20x_attribute_group);
-}
-
 static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
 					 struct platform_device *pdev)
 {
@@ -313,22 +306,13 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 			return error;
 	}
 
-	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
+	error = devm_device_add_group(&pdev->dev, &axp20x_attribute_group);
 	if (error) {
 		dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n",
 			error);
 		return error;
 	}
 
-	error = devm_add_action(&pdev->dev,
-				axp20x_remove_sysfs_group, &pdev->dev);
-	if (error) {
-		axp20x_remove_sysfs_group(&pdev->dev);
-		dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n",
-			error);
-		return error;
-	}
-
 	platform_set_drvdata(pdev, axp20x_pek);
 
 	return 0;
Signature · 1 line
2.14.0.rc0.284.gd933b75aa4-goog
Reviewed-by on v2 7/7
#19 lore raw

Re: [PATCH v2 7/7] Input: axp20x-pek - switch to using devm_device_add_group()

Quoted 4 lines · Dmitry Torokhov

Now that we have proper managed API to create device attributes, let's use it instead of installing a custom devm action.

Quoted 47 lines
---
  drivers/input/misc/axp20x-pek.c | 18 +-----------------
  1 file changed, 1 insertion(+), 17 deletions(-)
drivers/input/misc/axp20x-pek.c +1 -17
index 38c79ebff033..cfeb0e943de6 100644
@@ -182,13 +182,6 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
  	return IRQ_HANDLED;
  }
 
-static void axp20x_remove_sysfs_group(void *_data)
-{
-	struct device *dev = _data;
-
-	sysfs_remove_group(&dev->kobj, &axp20x_attribute_group);
-}
-
  static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
  					 struct platform_device *pdev)
  {
@@ -313,22 +306,13 @@ static int axp20x_pek_probe(struct platform_device *pdev)
  			return error;
  	}
 
-	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
+	error = devm_device_add_group(&pdev->dev, &axp20x_attribute_group);
  	if (error) {
  		dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n",
  			error);
  		return error;
  	}
 
-	error = devm_add_action(&pdev->dev,
-				axp20x_remove_sysfs_group, &pdev->dev);
-	if (error) {
-		axp20x_remove_sysfs_group(&pdev->dev);
-		dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n",
-			error);
-		return error;
-	}
-
  	platform_set_drvdata(pdev, axp20x_pek);
 
  	return 0;