]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/base/core.c
Merge tag 'for-3.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb...
[karo-tx-linux.git] / drivers / base / core.c
index d8b3d89db043e7e9ead44cb8b4a00946f4980fa6..74dda4f697f92d772355f37c0a82553e7827119d 100644 (file)
@@ -118,6 +118,56 @@ static const struct sysfs_ops dev_sysfs_ops = {
        .store  = dev_attr_store,
 };
 
+#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr)
+
+ssize_t device_store_ulong(struct device *dev,
+                          struct device_attribute *attr,
+                          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;
+       *(unsigned long *)(ea->var) = new;
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+EXPORT_SYMBOL_GPL(device_store_ulong);
+
+ssize_t device_show_ulong(struct device *dev,
+                         struct device_attribute *attr,
+                         char *buf)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+       return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(device_show_ulong);
+
+ssize_t device_store_int(struct device *dev,
+                        struct device_attribute *attr,
+                        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)
+               return -EINVAL;
+       *(int *)(ea->var) = new;
+       /* Always return full write size even if we didn't consume all */
+       return size;
+}
+EXPORT_SYMBOL_GPL(device_store_int);
+
+ssize_t device_show_int(struct device *dev,
+                       struct device_attribute *attr,
+                       char *buf)
+{
+       struct dev_ext_attribute *ea = to_ext_attr(attr);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(device_show_int);
 
 /**
  *     device_release - free device structure.
@@ -198,7 +248,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        if (MAJOR(dev->devt)) {
                const char *tmp;
                const char *name;
-               mode_t mode = 0;
+               umode_t mode = 0;
 
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
@@ -464,7 +514,7 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
 static struct device_attribute devt_attr =
        __ATTR(dev, S_IRUGO, show_dev, NULL);
 
-/* kset to create /sys/devices/  */
+/* /sys/devices/ */
 struct kset *devices_kset;
 
 /**
@@ -582,6 +632,11 @@ static void klist_children_put(struct klist_node *n)
  * may be used for reference counting of @dev after calling this
  * function.
  *
+ * All fields in @dev must be initialized by the caller to 0, except
+ * for those explicitly set to some other value.  The simplest
+ * approach is to use kzalloc() to allocate the structure containing
+ * @dev.
+ *
  * NOTE: Use put_device() to give up your reference instead of freeing
  * @dev directly once you have called this function.
  */
@@ -711,6 +766,10 @@ static struct kobject *get_device_parent(struct device *dev,
                return k;
        }
 
+       /* subsystems can specify a default root directory for their devices */
+       if (!parent && dev->bus && dev->bus->dev_root)
+               return &dev->bus->dev_root->kobj;
+
        if (parent)
                return &parent->kobj;
        return NULL;
@@ -731,14 +790,6 @@ static void cleanup_device_parent(struct device *dev)
        cleanup_glue_dir(dev, dev->kobj.parent);
 }
 
-static void setup_parent(struct device *dev, struct device *parent)
-{
-       struct kobject *kobj;
-       kobj = get_device_parent(dev, parent);
-       if (kobj)
-               dev->kobj.parent = kobj;
-}
-
 static int device_add_class_symlinks(struct device *dev)
 {
        int error;
@@ -884,6 +935,13 @@ int device_private_init(struct device *dev)
  * to the global and sibling lists for the device, then
  * adds it to the other relevant subsystems of the driver model.
  *
+ * Do not call this routine or device_register() more than once for
+ * any device structure.  The driver model core is not designed to work
+ * with devices that get unregistered and then spring back to life.
+ * (Among other things, it's very hard to guarantee that all references
+ * to the previous incarnation of @dev have been dropped.)  Allocate
+ * and register a fresh new struct device instead.
+ *
  * NOTE: _Never_ directly free @dev after calling this function, even
  * if it returned an error! Always use put_device() to give up your
  * reference instead.
@@ -891,6 +949,7 @@ int device_private_init(struct device *dev)
 int device_add(struct device *dev)
 {
        struct device *parent = NULL;
+       struct kobject *kobj;
        struct class_interface *class_intf;
        int error = -EINVAL;
 
@@ -914,6 +973,10 @@ int device_add(struct device *dev)
                dev->init_name = NULL;
        }
 
+       /* subsystems can specify simple device enumeration */
+       if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
+               dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
+
        if (!dev_name(dev)) {
                error = -EINVAL;
                goto name_error;
@@ -922,7 +985,9 @@ int device_add(struct device *dev)
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 
        parent = get_device(dev->parent);
-       setup_parent(dev, parent);
+       kobj = get_device_parent(dev, parent);
+       if (kobj)
+               dev->kobj.parent = kobj;
 
        /* use parent numa_node */
        if (parent)
@@ -969,7 +1034,7 @@ int device_add(struct device *dev)
        device_pm_add(dev);
 
        /* Notify clients of device addition.  This call must come
-        * after dpm_sysf_add() and before kobject_uevent().
+        * after dpm_sysfs_add() and before kobject_uevent().
         */
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
@@ -982,17 +1047,17 @@ int device_add(struct device *dev)
                               &parent->p->klist_children);
 
        if (dev->class) {
-               mutex_lock(&dev->class->p->class_mutex);
+               mutex_lock(&dev->class->p->mutex);
                /* tie the class to the device */
                klist_add_tail(&dev->knode_class,
                               &dev->class->p->klist_devices);
 
                /* notify any interfaces that the device is here */
                list_for_each_entry(class_intf,
-                                   &dev->class->p->class_interfaces, node)
+                                   &dev->class->p->interfaces, node)
                        if (class_intf->add_dev)
                                class_intf->add_dev(dev, class_intf);
-               mutex_unlock(&dev->class->p->class_mutex);
+               mutex_unlock(&dev->class->p->mutex);
        }
 done:
        put_device(dev);
@@ -1037,6 +1102,9 @@ name_error:
  * have a clearly defined need to use and refcount the device
  * before it is added to the hierarchy.
  *
+ * For more information, see the kerneldoc for device_initialize()
+ * and device_add().
+ *
  * NOTE: _Never_ directly free @dev after calling this function, even
  * if it returned an error! Always use put_device() to give up the
  * reference initialized in this function instead.
@@ -1107,15 +1175,15 @@ void device_del(struct device *dev)
        if (dev->class) {
                device_remove_class_symlinks(dev);
 
-               mutex_lock(&dev->class->p->class_mutex);
+               mutex_lock(&dev->class->p->mutex);
                /* notify any interfaces that the device is now gone */
                list_for_each_entry(class_intf,
-                                   &dev->class->p->class_interfaces, node)
+                                   &dev->class->p->interfaces, node)
                        if (class_intf->remove_dev)
                                class_intf->remove_dev(dev, class_intf);
                /* remove the device from the class list */
                klist_del(&dev->knode_class);
-               mutex_unlock(&dev->class->p->class_mutex);
+               mutex_unlock(&dev->class->p->mutex);
        }
        device_remove_file(dev, &uevent_attr);
        device_remove_attrs(dev);
@@ -1182,7 +1250,7 @@ static struct device *next_device(struct klist_iter *i)
  * freed by the caller.
  */
 const char *device_get_devnode(struct device *dev,
-                              mode_t *mode, const char **tmp)
+                              umode_t *mode, const char **tmp)
 {
        char *s;
 
@@ -1743,8 +1811,10 @@ void device_shutdown(void)
                 */
                list_del_init(&dev->kobj.entry);
                spin_unlock(&devices_kset->list_lock);
-               /* Disable all device's runtime power management */
-               pm_runtime_disable(dev);
+
+               /* Don't allow any more runtime suspends */
+               pm_runtime_get_noresume(dev);
+               pm_runtime_barrier(dev);
 
                if (dev->bus && dev->bus->shutdown) {
                        dev_dbg(dev, "shutdown\n");