driver core: move klist_children into private structure
[safe/jmp/linux-2.6] / drivers / base / sys.c
index 29eadc6..c98c31e 100644 (file)
@@ -36,7 +36,7 @@ sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
        struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
 
        if (sysdev_attr->show)
-               return sysdev_attr->show(sysdev, buffer);
+               return sysdev_attr->show(sysdev, sysdev_attr, buffer);
        return -EIO;
 }
 
@@ -49,7 +49,7 @@ sysdev_store(struct kobject * kobj, struct attribute * attr,
        struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
 
        if (sysdev_attr->store)
-               return sysdev_attr->store(sysdev, buffer, count);
+               return sysdev_attr->store(sysdev, sysdev_attr, buffer, count);
        return -EIO;
 }
 
@@ -130,12 +130,14 @@ static struct kset *system_kset;
 
 int sysdev_class_register(struct sysdev_class * cls)
 {
-       pr_debug("Registering sysdev class '%s'\n",
-                kobject_name(&cls->kset.kobj));
+       pr_debug("Registering sysdev class '%s'\n", cls->name);
+
        INIT_LIST_HEAD(&cls->drivers);
+       memset(&cls->kset.kobj, 0x00, sizeof(struct kobject));
        cls->kset.kobj.parent = &system_kset->kobj;
        cls->kset.kobj.ktype = &ktype_sysdev_class;
        cls->kset.kobj.kset = system_kset;
+       kobject_set_name(&cls->kset.kobj, cls->name);
        return kset_register(&cls->kset);
 }
 
@@ -165,6 +167,18 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
 {
        int err = 0;
 
+       if (!cls) {
+               WARN(1, KERN_WARNING "sysdev: invalid class passed to "
+                       "sysdev_driver_register!\n");
+               return -EINVAL;
+       }
+
+       /* Check whether this driver has already been added to a class. */
+       if (drv->entry.next && !list_empty(&drv->entry))
+               WARN(1, KERN_WARNING "sysdev: class %s: driver (%p) has already"
+                       " been registered to a class, something is wrong, but "
+                       "will forge on!\n", cls->name, drv);
+
        mutex_lock(&sysdev_drivers_lock);
        if (cls && kset_get(&cls->kset)) {
                list_add_tail(&drv->entry, &cls->drivers);
@@ -177,8 +191,7 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
                }
        } else {
                err = -EINVAL;
-               printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
-               WARN_ON(1);
+               WARN(1, KERN_ERR "%s: invalid device class\n", __func__);
        }
        mutex_unlock(&sysdev_drivers_lock);
        return err;
@@ -224,24 +237,26 @@ int sysdev_register(struct sys_device * sysdev)
        if (!cls)
                return -EINVAL;
 
-       /* Make sure the kset is set */
-       sysdev->kobj.kset = &cls->kset;
+       pr_debug("Registering sys device of class '%s'\n",
+                kobject_name(&cls->kset.kobj));
 
-       /* But make sure we point to the right type for sysfs translation */
-       sysdev->kobj.ktype = &ktype_sysdev;
-       error = kobject_set_name(&sysdev->kobj, "%s%d",
-                        kobject_name(&cls->kset.kobj), sysdev->id);
-       if (error)
-               return error;
+       /* initialize the kobject to 0, in case it had previously been used */
+       memset(&sysdev->kobj, 0x00, sizeof(struct kobject));
 
-       pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
+       /* Make sure the kset is set */
+       sysdev->kobj.kset = &cls->kset;
 
        /* Register the object */
-       error = kobject_register(&sysdev->kobj);
+       error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL,
+                                    "%s%d", kobject_name(&cls->kset.kobj),
+                                    sysdev->id);
 
        if (!error) {
                struct sysdev_driver * drv;
 
+               pr_debug("Registering sys device '%s'\n",
+                        kobject_name(&sysdev->kobj));
+
                mutex_lock(&sysdev_drivers_lock);
                /* Generic notification is implicit, because it's that
                 * code that should have called us.
@@ -254,6 +269,8 @@ int sysdev_register(struct sys_device * sysdev)
                }
                mutex_unlock(&sysdev_drivers_lock);
        }
+
+       kobject_uevent(&sysdev->kobj, KOBJ_ADD);
        return error;
 }
 
@@ -268,7 +285,7 @@ void sysdev_unregister(struct sys_device * sysdev)
        }
        mutex_unlock(&sysdev_drivers_lock);
 
-       kobject_unregister(&sysdev->kobj);
+       kobject_put(&sysdev->kobj);
 }
 
 
@@ -338,7 +355,7 @@ static void __sysdev_resume(struct sys_device *dev)
  *     sysdev_suspend - Suspend all system devices.
  *     @state:         Power state to enter.
  *
- *     We perform an almost identical operation as sys_device_shutdown()
+ *     We perform an almost identical operation as sysdev_shutdown()
  *     above, though calling ->suspend() instead. Interrupts are disabled
  *     when this called. Devices are responsible for both saving state and
  *     quiescing or powering down the device.
@@ -420,7 +437,7 @@ aux_driver:
 /**
  *     sysdev_resume - Bring system devices back to life.
  *
- *     Similar to sys_device_suspend(), but we iterate the list forwards
+ *     Similar to sysdev_suspend(), but we iterate the list forwards
  *     to guarantee that parent devices are resumed before their children.
  *
  *     Note: Interrupts are disabled when called.
@@ -458,3 +475,54 @@ int __init system_bus_init(void)
 
 EXPORT_SYMBOL_GPL(sysdev_register);
 EXPORT_SYMBOL_GPL(sysdev_unregister);
+
+#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr)
+
+ssize_t sysdev_store_ulong(struct sys_device *sysdev,
+                          struct sysdev_attribute *attr,
+                          const char *buf, size_t size)
+{
+       struct sysdev_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(sysdev_store_ulong);
+
+ssize_t sysdev_show_ulong(struct sys_device *sysdev,
+                         struct sysdev_attribute *attr,
+                         char *buf)
+{
+       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(sysdev_show_ulong);
+
+ssize_t sysdev_store_int(struct sys_device *sysdev,
+                          struct sysdev_attribute *attr,
+                          const char *buf, size_t size)
+{
+       struct sysdev_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(sysdev_store_int);
+
+ssize_t sysdev_show_int(struct sys_device *sysdev,
+                         struct sysdev_attribute *attr,
+                         char *buf)
+{
+       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
+}
+EXPORT_SYMBOL_GPL(sysdev_show_int);
+