* add themselves as children of the system bus.
*/
-#include <linux/config.h>
#include <linux/sysdev.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/pm.h>
-#include <asm/semaphore.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
-extern struct subsystem devices_subsys;
+#include "base.h"
#define to_sysdev(k) container_of(k, struct sys_device, kobj)
#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
EXPORT_SYMBOL_GPL(sysdev_create_file);
EXPORT_SYMBOL_GPL(sysdev_remove_file);
-/*
- * declare system_subsys
- */
-static decl_subsys(system, &ktype_sysdev, NULL);
+#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj)
+#define to_sysdev_class_attr(a) container_of(a, \
+ struct sysdev_class_attribute, attr)
+
+static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct sysdev_class * class = to_sysdev_class(kobj);
+ struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
+
+ if (class_attr->show)
+ return class_attr->show(class, buffer);
+ return -EIO;
+}
+
+static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct sysdev_class * class = to_sysdev_class(kobj);
+ struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr);
+
+ if (class_attr->store)
+ return class_attr->store(class, buffer, count);
+ return -EIO;
+}
+
+static struct sysfs_ops sysfs_class_ops = {
+ .show = sysdev_class_show,
+ .store = sysdev_class_store,
+};
+
+static struct kobj_type ktype_sysdev_class = {
+ .sysfs_ops = &sysfs_class_ops,
+};
+
+int sysdev_class_create_file(struct sysdev_class *c,
+ struct sysdev_class_attribute *a)
+{
+ return sysfs_create_file(&c->kset.kobj, &a->attr);
+}
+EXPORT_SYMBOL_GPL(sysdev_class_create_file);
+
+void sysdev_class_remove_file(struct sysdev_class *c,
+ struct sysdev_class_attribute *a)
+{
+ sysfs_remove_file(&c->kset.kobj, &a->attr);
+}
+EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
+
+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));
INIT_LIST_HEAD(&cls->drivers);
- cls->kset.subsys = &system_subsys;
- kset_set_kset_s(cls, system_subsys);
+ cls->kset.kobj.parent = &system_kset->kobj;
+ cls->kset.kobj.ktype = &ktype_sysdev_class;
+ cls->kset.kobj.kset = system_kset;
return kset_register(&cls->kset);
}
EXPORT_SYMBOL_GPL(sysdev_class_register);
EXPORT_SYMBOL_GPL(sysdev_class_unregister);
-
-static LIST_HEAD(sysdev_drivers);
-static DECLARE_MUTEX(sysdev_drivers_lock);
+static DEFINE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
- * @cls: Device class driver belongs to.
+ * @cls: Device class driver belongs to.
* @drv: Driver.
*
- * If @cls is valid, then @drv is inserted into @cls->drivers to be
+ * @drv is inserted into @cls->drivers to be
* called on each operation on devices of that class. The refcount
* of @cls is incremented.
- * Otherwise, @drv is inserted into sysdev_drivers, and called for
- * each device.
*/
-int sysdev_driver_register(struct sysdev_class * cls,
- struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
{
- down(&sysdev_drivers_lock);
+ int err = 0;
+
+ mutex_lock(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->add(dev);
}
- } else
- list_add_tail(&drv->entry, &sysdev_drivers);
- up(&sysdev_drivers_lock);
- return 0;
+ } else {
+ err = -EINVAL;
+ printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+ WARN_ON(1);
+ }
+ mutex_unlock(&sysdev_drivers_lock);
+ return err;
}
void sysdev_driver_unregister(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
list_del_init(&drv->entry);
if (cls) {
if (drv->remove) {
}
kset_put(&cls->kset);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
EXPORT_SYMBOL_GPL(sysdev_driver_register);
if (!cls)
return -EINVAL;
+ pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
+
/* Make sure the kset is set */
sysdev->kobj.kset = &cls->kset;
- /* 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;
-
- pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
-
/* 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;
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
/* Generic notification is implicit, because it's that
* code that should have called us.
*/
- /* Notify global drivers */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->add)
- drv->add(sysdev);
- }
-
/* Notify class auxillary drivers */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->add)
drv->add(sysdev);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
+ kobject_uevent(&sysdev->kobj, KOBJ_ADD);
return error;
}
{
struct sysdev_driver * drv;
- down(&sysdev_drivers_lock);
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->remove)
- drv->remove(sysdev);
- }
-
+ mutex_lock(&sysdev_drivers_lock);
list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
- kobject_unregister(&sysdev->kobj);
+ kobject_put(&sysdev->kobj);
}
*
* Loop over each class of system devices, and the devices in each
* of those classes. For each device, we call the shutdown method for
- * each driver registered for the device - the globals, the auxillaries,
+ * each driver registered for the device - the auxillaries,
* and the class driver.
*
* Note: The list is iterated in reverse order, so that we shut down
pr_debug("Shutting Down System Devices\n");
- down(&sysdev_drivers_lock);
- list_for_each_entry_reverse(cls, &system_subsys.kset.list,
- kset.kobj.entry) {
+ mutex_lock(&sysdev_drivers_lock);
+ list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Shutting down type '%s':\n",
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->shutdown)
- drv->shutdown(sysdev);
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
cls->shutdown(sysdev);
}
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
static void __sysdev_resume(struct sys_device *dev)
if (drv->resume)
drv->resume(dev);
}
-
- /* Call global drivers. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->resume)
- drv->resume(dev);
- }
}
/**
pr_debug("Suspending System Devices\n");
- list_for_each_entry_reverse(cls, &system_subsys.kset.list,
- kset.kobj.entry) {
-
+ list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
pr_debug("Suspending type '%s':\n",
kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->suspend) {
- ret = drv->suspend(sysdev, state);
- if (ret)
- goto gbl_driver;
- }
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->suspend) {
ret = drv->suspend(sysdev, state);
if (err_drv->resume)
err_drv->resume(sysdev);
}
- drv = NULL;
-gbl_driver:
- if (drv)
- printk(KERN_ERR "sysdev driver suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
- list_for_each_entry(err_drv, &sysdev_drivers, entry) {
- if (err_drv == drv)
- break;
- if (err_drv->resume)
- err_drv->resume(sysdev);
- }
/* resume other sysdevs in current class */
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
if (err_dev == sysdev)
}
/* resume other classes */
- list_for_each_entry_continue(cls, &system_subsys.kset.list,
- kset.kobj.entry) {
+ list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) {
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&err_dev->kobj));
__sysdev_resume(err_dev);
pr_debug("Resuming System Devices\n");
- list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
+ list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Resuming type '%s':\n",
int __init system_bus_init(void)
{
- system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
- return subsystem_register(&system_subsys);
+ system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
+ if (!system_kset)
+ return -ENOMEM;
+ return 0;
}
EXPORT_SYMBOL_GPL(sysdev_register);