diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 04bbcd779e11..0073b09bb99f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -8,6 +8,7 @@ * Copyright (c) 2006 Novell, Inc. */ +#include <linux/acpi.h> #include <linux/device.h> #include <linux/err.h> #include <linux/fwnode.h> @@ -728,6 +729,26 @@ static inline int device_is_not_partition(struct device *dev) } #endif +static int +device_platform_notify(struct device *dev, enum kobject_action action) +{ + int ret; + + ret = acpi_platform_notify(dev, action); + if (ret) + return ret; + + ret = software_node_notify(dev, action); + if (ret) + return ret; + + if (platform_notify && action == KOBJ_ADD) + platform_notify(dev); + else if (platform_notify_remove && action == KOBJ_REMOVE) + platform_notify_remove(dev); + return 0; +} + /** * dev_driver_string - Return a device's driver name, if at all possible * @dev: struct device to get the name of @@ -794,10 +815,12 @@ ssize_t device_store_ulong(struct device *dev, const char *buf, size_t size) { struct dev_ext_attribute *ea = to_ext_attr(attr); - char *end; - unsigned long new = simple_strtoul(buf, &end, 0); - if (end == buf) - return -EINVAL; + int ret; + unsigned long new; + + ret = kstrtoul(buf, 0, &new); + if (ret) + return ret; *(unsigned long *)(ea->var) = new; /* Always return full write size even if we didn't consume all */ return size; @@ -818,9 +841,14 @@ ssize_t device_store_int(struct device *dev, const char *buf, size_t size) { struct dev_ext_attribute *ea = to_ext_attr(attr); - char *end; - long new = simple_strtol(buf, &end, 0); - if (end == buf || new > INT_MAX || new < INT_MIN) + int ret; + long new; + + ret = kstrtol(buf, 0, &new); + if (ret) + return ret; + + if (new > INT_MAX || new < INT_MIN) return -EINVAL; *(int *)(ea->var) = new; /* Always return full write size even if we didn't consume all */ @@ -890,8 +918,7 @@ static void device_release(struct kobject *kobj) else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else - WARN(1, KERN_ERR "Device '%s' does not have a release() " - "function, it is broken and must be fixed.\n", + WARN(1, KERN_ERR "Device '%s' does not have a release() function, it is broken and must be fixed. See Documentation/kobject.txt.\n", dev_name(dev)); kfree(p); } @@ -1067,8 +1094,14 @@ out: static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (kobject_synth_uevent(&dev->kobj, buf, count)) + int rc; + + rc = kobject_synth_uevent(&dev->kobj, buf, count); + + if (rc) { dev_err(dev, "uevent: failed to send synthetic uevent\n"); + return rc; + } return count; } @@ -1883,8 +1916,9 @@ int device_add(struct device *dev) } /* notify platform of device entry */ - if (platform_notify) - platform_notify(dev); + error = device_platform_notify(dev, KOBJ_ADD); + if (error) + goto platform_error; error = device_create_file(dev, &dev_attr_uevent); if (error) @@ -1960,6 +1994,8 @@ done: SymlinkError: device_remove_file(dev, &dev_attr_uevent); attrError: + device_platform_notify(dev, KOBJ_REMOVE); +platform_error: kobject_uevent(&dev->kobj, KOBJ_REMOVE); glue_dir = get_glue_dir(dev); kobject_del(&dev->kobj); @@ -2077,14 +2113,10 @@ void device_del(struct device *dev) bus_remove_device(dev); device_pm_remove(dev); driver_deferred_probe_del(dev); + device_platform_notify(dev, KOBJ_REMOVE); device_remove_properties(dev); device_links_purge(dev); - /* Notify the platform of the removal, in case they - * need to do anything... - */ - if (platform_notify_remove) - platform_notify_remove(dev); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_REMOVED_DEVICE, dev); |