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:
Коммит
1af824f085
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -57,6 +57,8 @@ enum kobject_action {
|
|||
KOBJ_MOVE,
|
||||
KOBJ_ONLINE,
|
||||
KOBJ_OFFLINE,
|
||||
KOBJ_BIND,
|
||||
KOBJ_UNBIND,
|
||||
KOBJ_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче