summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c43
-rw-r--r--drivers/base/driver.c9
-rw-r--r--drivers/base/power/main.c6
3 files changed, 41 insertions, 17 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f191afe..d7fcf82 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -28,20 +28,6 @@ int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL;
/*
- * Detect the LANANA-assigned LOCAL/EXPERIMENTAL majors
- */
-bool is_lanana_major(unsigned int major)
-{
- if (major >= 60 && major <= 63)
- return 1;
- if (major >= 120 && major <= 127)
- return 1;
- if (major >= 240 && major <= 254)
- return 1;
- return 0;
-}
-
-/*
* sysfs bindings for devices.
*/
@@ -407,6 +393,35 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
}
EXPORT_SYMBOL_GPL(device_remove_bin_file);
+/**
+ * device_schedule_callback - helper to schedule a callback for a device
+ * @dev: device.
+ * @func: callback function to invoke later.
+ *
+ * Attribute methods must not unregister themselves or their parent device
+ * (which would amount to the same thing). Attempts to do so will deadlock,
+ * since unregistration is mutually exclusive with driver callbacks.
+ *
+ * Instead methods can call this routine, which will attempt to allocate
+ * and schedule a workqueue request to call back @func with @dev as its
+ * argument in the workqueue's process context. @dev will be pinned until
+ * @func returns.
+ *
+ * Returns 0 if the request was submitted, -ENOMEM if storage could not
+ * be allocated.
+ *
+ * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
+ * underlying sysfs routine (since it is intended for use by attribute
+ * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
+ */
+int device_schedule_callback(struct device *dev,
+ void (*func)(struct device *))
+{
+ return sysfs_schedule_callback(&dev->kobj,
+ (void (*)(void *)) func, dev);
+}
+EXPORT_SYMBOL_GPL(device_schedule_callback);
+
static void klist_children_get(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_parent);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1214cbd..082bfde 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -183,7 +183,14 @@ int driver_register(struct device_driver * drv)
void driver_unregister(struct device_driver * drv)
{
bus_remove_driver(drv);
- wait_for_completion(&drv->unloaded);
+ /*
+ * If the driver is a module, we are probably in
+ * the module unload path, and we want to wait
+ * for everything to unload before we can actually
+ * finish the unload.
+ */
+ if (drv->owner)
+ wait_for_completion(&drv->unloaded);
}
/**
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index fdfa3d0..bbbb973 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -54,7 +54,8 @@ int device_pm_add(struct device * dev)
int error;
pr_debug("PM: Adding info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
down(&dpm_list_sem);
list_add_tail(&dev->power.entry, &dpm_active);
device_pm_set_parent(dev, dev->parent);
@@ -67,7 +68,8 @@ int device_pm_add(struct device * dev)
void device_pm_remove(struct device * dev)
{
pr_debug("PM: Removing info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
down(&dpm_list_sem);
dpm_sysfs_remove(dev);
put_device(dev->power.pm_parent);
OpenPOWER on IntegriCloud