From 9cd52d595d85e187c0bf13b15d507e9a34ac9ff2 Mon Sep 17 00:00:00 2001
From: Patrick Mochel <mochel@osdl.org>
Date: Wed, 30 Oct 2002 15:31:26 -0800
Subject: [PATCH] driver model: convert device classes to use struct kobject
 and sysfs.

---
 drivers/base/class.c    | 107 ++++++++++++++++++++++++++
 drivers/base/fs/class.c | 162 ----------------------------------------
 include/linux/device.h  |   3 +
 3 files changed, 110 insertions(+), 162 deletions(-)

diff --git a/drivers/base/class.c b/drivers/base/class.c
index e1e6081cf110..df7215a408e9 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -4,10 +4,98 @@
 
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include "base.h"
 
 static LIST_HEAD(class_list);
 
+#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
+#define to_class(obj) container_of(obj,struct device_class,subsys.kobj)
+
+static ssize_t
+devclass_attr_show(struct kobject * kobj, struct attribute * attr,
+	      char * buf, size_t count, loff_t off)
+{
+	struct devclass_attribute * class_attr = to_class_attr(attr);
+	struct device_class * dc = to_class(kobj);
+	ssize_t ret = 0;
+
+	if (class_attr->show)
+		ret = class_attr->show(dc,buf,count,off);
+	return ret;
+}
+
+static ssize_t
+devclass_attr_store(struct kobject * kobj, struct attribute * attr,
+	       const char * buf, size_t count, loff_t off)
+{
+	struct devclass_attribute * class_attr = to_class_attr(attr);
+	struct device_class * dc = to_class(kobj);
+	ssize_t ret = 0;
+
+	if (class_attr->store)
+		ret = class_attr->store(dc,buf,count,off);
+	return ret;
+}
+
+static struct sysfs_ops class_sysfs_ops = {
+	show:	devclass_attr_show,
+	store:	devclass_attr_store,
+};
+
+static struct subsystem class_subsys = {
+	.kobj	= { .name = "class", },
+	.sysfs_ops	= &class_sysfs_ops,
+};
+
+
+int devclass_dev_link(struct device_class * cls, struct device * dev)
+{
+	char	linkname[16];
+	snprintf(linkname,16,"%u",dev->class_num);
+	return sysfs_create_link(&cls->devsubsys.kobj,&dev->kobj,linkname);
+}
+
+void devclass_dev_unlink(struct device_class * cls, struct device * dev)
+{
+	char	linkname[16];
+	snprintf(linkname,16,"%u",dev->class_num);
+	sysfs_remove_link(&cls->devsubsys.kobj,linkname);
+}
+
+int devclass_drv_link(struct device_driver * drv)
+{
+	char	name[KOBJ_NAME_LEN * 3];
+	snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
+	return sysfs_create_link(&drv->devclass->drvsubsys.kobj,&drv->kobj,name);
+}
+
+void devclass_drv_unlink(struct device_driver * drv)
+{
+	char	name[KOBJ_NAME_LEN * 3];
+	snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name);
+	return sysfs_remove_link(&drv->devclass->drvsubsys.kobj,name);
+}
+
+
+int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr)
+{
+	int error;
+	if (cls) {
+		error = sysfs_create_file(&cls->subsys.kobj,&attr->attr);
+	} else
+		error = -EINVAL;
+	return error;
+}
+
+void devclass_remove_file(struct device_class * cls, struct devclass_attribute * attr)
+{
+	if (cls)
+		sysfs_remove_file(&cls->subsys.kobj,&attr->attr);
+}
+
+
+
 int devclass_add_driver(struct device_driver * drv)
 {
 	struct device_class * cls = get_devclass(drv->devclass);
@@ -150,6 +238,18 @@ int devclass_register(struct device_class * cls)
 	cls->present = 1;
 	pr_debug("device class '%s': registering\n",cls->name);
 
+	strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN);
+	cls->subsys.parent = &class_subsys;
+	subsystem_register(&cls->subsys);
+
+	snprintf(cls->devsubsys.kobj.name,"devices",KOBJ_NAME_LEN);
+	cls->devsubsys.parent = &cls->subsys;
+	subsystem_register(&cls->devsubsys);
+
+	snprintf(cls->drvsubsys.kobj.name,"drivers",KOBJ_NAME_LEN);
+	cls->drvsubsys.parent = &cls->subsys;
+	subsystem_register(&cls->drvsubsys);
+
 	spin_lock(&device_lock);
 	list_add_tail(&cls->node,&class_list);
 	spin_unlock(&device_lock);
@@ -167,6 +267,13 @@ void devclass_unregister(struct device_class * cls)
 	put_devclass(cls);
 }
 
+static int __init class_subsys_init(void)
+{
+	return subsystem_register(&class_subsys);
+}
+
+core_initcall(class_subsys_init);
+
 EXPORT_SYMBOL(devclass_register);
 EXPORT_SYMBOL(devclass_unregister);
 EXPORT_SYMBOL(get_devclass);
diff --git a/drivers/base/fs/class.c b/drivers/base/fs/class.c
index 1713000f0c37..0be2d2986931 100644
--- a/drivers/base/fs/class.c
+++ b/drivers/base/fs/class.c
@@ -11,167 +11,6 @@
 
 static struct driver_dir_entry class_dir;
 
-
-#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
-
-#define to_class(d) container_of(d,struct device_class,dir)
-
-
-static ssize_t
-devclass_attr_show(struct driver_dir_entry * dir, struct attribute * attr,
-	      char * buf, size_t count, loff_t off)
-{
-	struct devclass_attribute * class_attr = to_class_attr(attr);
-	struct device_class * dc = to_class(dir);
-	ssize_t ret = 0;
-
-	if (class_attr->show)
-		ret = class_attr->show(dc,buf,count,off);
-	return ret;
-}
-
-static ssize_t
-devclass_attr_store(struct driver_dir_entry * dir, struct attribute * attr,
-	       const char * buf, size_t count, loff_t off)
-{
-	struct devclass_attribute * class_attr = to_class_attr(attr);
-	struct device_class * dc = to_class(dir);
-	ssize_t ret = 0;
-
-	if (class_attr->store)
-		ret = class_attr->store(dc,buf,count,off);
-	return ret;
-}
-
-static struct driverfs_ops devclass_attr_ops = {
-	show:	devclass_attr_show,
-	store:	devclass_attr_store,
-};
-
-int devclass_create_file(struct device_class * dc, struct devclass_attribute * attr)
-{
-	int error;
-	if (dc) {
-		error = driverfs_create_file(&attr->attr,&dc->dir);
-	} else
-		error = -EINVAL;
-	return error;
-}
-
-void devclass_remove_file(struct device_class * dc, struct devclass_attribute * attr)
-{
-	if (dc)
-		driverfs_remove_file(&dc->dir,attr->attr.name);
-}
-
-/**
- *	devclass_dev_link - create symlink to device's directory
- *	@cls - device class we're a part of 
- *	@dev - device we're linking to 
- *
- *	Create a symlink in the class's devices/ directory to @dev's 
- *	directory in the physical hierarchy. The name is the device's 
- *	class-enumerated value (struct device::class_num). We're 
- *	creating:
- *		class/<class name>/devices/<link name> ->
- *		root/<path to device>/<device's dir>
- *	So, the link looks like:
- *		../../../root/<path to device>/
- */
-int devclass_dev_link(struct device_class * cls, struct device * dev)
-{
-	char	linkname[16];
-	char	* path;
-	int	length;
-	int	error;
-
-	length = get_devpath_length(dev);
-	length += strlen("../../../root");
-
-	if (length > PATH_MAX)
-		return -ENAMETOOLONG;
-
-	if (!(path = kmalloc(length,GFP_KERNEL)))
-		return -ENOMEM;
-	memset(path,0,length);
-	strcpy(path,"../../../root");
-	fill_devpath(dev,path,length);
-	
-	snprintf(linkname,16,"%u",dev->class_num);
-	error = driverfs_create_symlink(&cls->device_dir,linkname,path);
-	kfree(path);
-	return error;
-}
-
-void devclass_dev_unlink(struct device_class * cls, struct device * dev)
-{
-	char	linkname[16];
-
-	snprintf(linkname,16,"%u",dev->class_num);
-	driverfs_remove_file(&cls->device_dir,linkname);
-}
-
-/**
- *	devclass_drv_link - create symlink to driver's directory
- *	@drv:	driver we're linking up
- *
- *	Create a symlink in the class's drivers/ directory to @drv's
- *	directory (in the bus's directory). It's name is <bus>:<driver>
- *	to prevent naming conflicts.
- *
- *	We're creating 
- *		class/<class name>/drivers/<link name> -> 
- *		bus/<bus name>/drivers/<driver name>/
- *	So, the link looks like: 
- *		../../../bus/<bus name>/drivers/<driver name>
- */
-int devclass_drv_link(struct device_driver * drv)
-{
-	char	* name;
-	char	* path;
-	int	namelen;
-	int	pathlen;
-	int	error = 0;
-
-	namelen = strlen(drv->name) + strlen(drv->bus->name) + 2;
-	name = kmalloc(namelen,GFP_KERNEL);
-	if (!name)
-		return -ENOMEM;
-	snprintf(name,namelen,"%s:%s",drv->bus->name,drv->name);
-
-	pathlen = strlen("../../../bus/") + 
-		strlen(drv->bus->name) + 
-		strlen("/drivers/") + 
-		strlen(drv->name) + 1;
-	if (!(path = kmalloc(pathlen,GFP_KERNEL))) {
-		error = -ENOMEM;
-		goto Done;
-	}
-	snprintf(path,pathlen,"%s%s%s%s",
-		 "../../../bus/",
-		 drv->bus->name,
-		 "/drivers/",
-		 drv->name);
-
-	error = driverfs_create_symlink(&drv->devclass->driver_dir,name,path);
- Done:
-	kfree(name);
-	kfree(path);
-	return error;
-}
-
-void devclass_drv_unlink(struct device_driver * drv)
-{
-	char	* name;
-	int	length;
-
-	length = strlen(drv->name) + strlen(drv->bus->name) + 2;
-	if ((name = kmalloc(length,GFP_KERNEL))) {
-		driverfs_remove_file(&drv->devclass->driver_dir,name);
-		kfree(name);
-	}
-}
-
 void devclass_remove_dir(struct device_class * dc)
 {
 	driverfs_remove_dir(&dc->device_dir);
@@ -184,7 +23,6 @@ int devclass_make_dir(struct device_class * dc)
 	int error;
 
 	dc->dir.name = dc->name;
-	dc->dir.ops = &devclass_attr_ops;
 	error = device_create_dir(&dc->dir,&class_dir);
 	if (!error) {
 		dc->driver_dir.name = "drivers";
diff --git a/include/linux/device.h b/include/linux/device.h
index 5ce759266658..9013a4c88a53 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -182,6 +182,9 @@ struct device_class {
 
 	u32			devnum;
 
+	struct subsystem	subsys;
+	struct subsystem	devsubsys;
+	struct subsystem	drvsubsys;
 	struct list_head	node;
 	struct list_head	drivers;
 	struct list_head	intf_list;
-- 
2.30.9