Merge branch 'bind_unbind' into driver-core-next

This merges the bind_unbind driver core feature into the
driver-core-next branch.  bind_unbind is a branch so that others can
pull and work off of it safely.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2017-07-22 12:00:15 +02:00
commit 1af824f085
9 changed files with 176 additions and 44 deletions

View File

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

View File

@ -1023,12 +1023,144 @@ 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);
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)
{

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -1200,6 +1200,36 @@ 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);
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);
}
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

View File

@ -57,6 +57,8 @@ enum kobject_action {
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_BIND,
KOBJ_UNBIND,
KOBJ_MAX
};

View File

@ -52,6 +52,8 @@ static const char *kobject_actions[] = {
[KOBJ_MOVE] = "move",
[KOBJ_ONLINE] = "online",
[KOBJ_OFFLINE] = "offline",
[KOBJ_BIND] = "bind",
[KOBJ_UNBIND] = "unbind",
};
static int kobject_action_type(const char *buf, size_t count,