Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1af824f0 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parents d8bcf4db 072a7852
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -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);
+132 −0
Original line number Diff line number Diff line
@@ -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)
{
+4 −0
Original line number Diff line number Diff line
@@ -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);
	}
}

+2 −14
Original line number Diff line number Diff line
@@ -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,21 +838,10 @@ 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;
	}

	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);
	device_init_wakeup(dev, wakeup);

	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,
+1 −17
Original line number Diff line number Diff line
@@ -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;
Loading