ChangeSet 1.1157, 2003/04/28 23:05:37-07:00, greg@kroah.com

driver core: rework driver class structures and logic

Removes the device_class, devclass_attribute, and device_interface structures
and replaces them with class, class_device, and class_interface structures.

This allows us to have multiple class_device structures per device structures
which mirrors the ways things really are within the kernel.  It also allows 
class_device structures to be created later than struct devices as they
are naturally created much later in the initialization process of a device.


 drivers/base/Makefile  |    4 
 drivers/base/base.h    |   20 --
 drivers/base/bus.c     |   11 -
 drivers/base/class.c   |  480 +++++++++++++++++++++++++++++++------------------
 drivers/base/core.c    |    2 
 drivers/base/driver.c  |    1 
 include/linux/device.h |  128 +++++++------
 7 files changed, 389 insertions(+), 257 deletions(-)


diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/Makefile	Tue Apr 29 09:48:19 2003
@@ -1,8 +1,6 @@
 # Makefile for the Linux device tree
 
 obj-y			:= core.o sys.o interface.o power.o bus.o \
-			   driver.o class.o intf.o platform.o \
+			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o
 obj-$(CONFIG_NUMA)	+= node.o  memblk.o
-obj-y			+= fs/
-obj-$(CONFIG_HOTPLUG)	+= hotplug.o
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/base.h	Tue Apr 29 09:48:19 2003
@@ -1,28 +1,8 @@
 extern struct semaphore device_sem;
-extern struct semaphore devclass_sem;
 
 extern int bus_add_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
 
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
-
-extern int devclass_add_device(struct device *);
-extern void devclass_remove_device(struct device *);
-
-extern int devclass_add_driver(struct device_driver *);
-extern void devclass_remove_driver(struct device_driver *);
-
-extern int interface_add_dev(struct device *);
-extern void interface_remove_dev(struct device *);
-
-
-#ifdef CONFIG_HOTPLUG
-extern int class_hotplug(struct device *dev, const char *action);
-#else
-static inline int class_hotplug(struct device *dev, const char *action)
-{
-	return 0;
-}
-#endif
 
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/bus.c	Tue Apr 29 09:48:19 2003
@@ -311,8 +311,7 @@
  *	Walk the list of devices that the bus has on it and try to match
  *	the driver with each one.
  *	If bus_match() returns 0 and the @dev->driver is set, we've found
- *	a compatible pair, so we call devclass_add_device() to add the 
- *	device to the class. 
+ *	a compatible pair.
  *
  *	Note that we ignore the error from bus_match(), since it's perfectly
  *	valid for a driver not to bind to any devices.
@@ -328,8 +327,7 @@
 	list_for_each(entry,&bus->devices.list) {
 		struct device * dev = container_of(entry,struct device,bus_list);
 		if (!dev->driver) {
-			if (!bus_match(dev,drv))
-				devclass_add_device(dev);
+			bus_match(dev,drv);
 		}
 	}
 }
@@ -351,7 +349,6 @@
 	if (drv) {
 		sysfs_remove_link(&drv->kobj,dev->kobj.name);
 		list_del_init(&dev->driver_list);
-		devclass_remove_device(dev);
 		if (drv->remove)
 			drv->remove(dev);
 		dev->driver = NULL;
@@ -443,8 +440,7 @@
 		}
 
 		down_write(&bus->subsys.rwsem);
-		if (!(error = devclass_add_driver(drv)))
-			driver_attach(drv);
+		driver_attach(drv);
 		up_write(&bus->subsys.rwsem);
 
 		if (error) {
@@ -471,7 +467,6 @@
 		down_write(&drv->bus->subsys.rwsem);
 		pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name);
 		driver_detach(drv);
-		devclass_remove_driver(drv);
 		up_write(&drv->bus->subsys.rwsem);
 		kobject_unregister(&drv->kobj);
 		put_bus(drv->bus);
diff -Nru a/drivers/base/class.c b/drivers/base/class.c
--- a/drivers/base/class.c	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/class.c	Tue Apr 29 09:48:19 2003
@@ -1,5 +1,7 @@
 /*
  * class.c - basic device class management
+ * 
+ * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
  */
 
 #undef DEBUG
@@ -10,16 +12,14 @@
 #include <linux/string.h>
 #include "base.h"
 
-#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
-#define to_class(obj) container_of(obj,struct device_class,subsys.kset.kobj)
-
-DECLARE_MUTEX(devclass_sem);
+#define to_class_attr(_attr) container_of(_attr,struct class_attribute,attr)
+#define to_class(obj) container_of(obj,struct class,subsys.kset.kobj)
 
 static ssize_t
-devclass_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
-	struct devclass_attribute * class_attr = to_class_attr(attr);
-	struct device_class * dc = to_class(kobj);
+	struct class_attribute * class_attr = to_class_attr(attr);
+	struct class * dc = to_class(kobj);
 	ssize_t ret = 0;
 
 	if (class_attr->show)
@@ -28,11 +28,11 @@
 }
 
 static ssize_t
-devclass_attr_store(struct kobject * kobj, struct attribute * attr, 
-		    const char * buf, size_t count)
+class_attr_store(struct kobject * kobj, struct attribute * attr, 
+		 const char * buf, size_t count)
 {
-	struct devclass_attribute * class_attr = to_class_attr(attr);
-	struct device_class * dc = to_class(kobj);
+	struct class_attribute * class_attr = to_class_attr(attr);
+	struct class * dc = to_class(kobj);
 	ssize_t ret = 0;
 
 	if (class_attr->store)
@@ -41,242 +41,376 @@
 }
 
 static struct sysfs_ops class_sysfs_ops = {
-	.show	= devclass_attr_show,
-	.store	= devclass_attr_store,
+	.show	= class_attr_show,
+	.store	= class_attr_store,
 };
 
-static struct kobj_type ktype_devclass = {
+static struct kobj_type ktype_class = {
 	.sysfs_ops	= &class_sysfs_ops,
 };
 
-/* Classes can't use the kobject hotplug logic, as
- * they do not add new kobjects to the system */
-static decl_subsys(class,&ktype_devclass,NULL);
+/* Hotplug events for classes go to the class_obj subsys */
+static decl_subsys(class,&ktype_class,NULL);
 
 
-static int devclass_dev_link(struct device_class * cls, struct device * dev)
+int class_create_file(struct class * cls, struct class_attribute * attr)
 {
-	char	linkname[16];
-	snprintf(linkname,16,"%u",dev->class_num);
-	return sysfs_create_link(&cls->devices.kobj,&dev->kobj,linkname);
+	int error;
+	if (cls) {
+		error = sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr);
+	} else
+		error = -EINVAL;
+	return error;
 }
 
-static void devclass_dev_unlink(struct device_class * cls, struct device * dev)
+void class_remove_file(struct class * cls, struct class_attribute * attr)
 {
-	char	linkname[16];
-	snprintf(linkname,16,"%u",dev->class_num);
-	sysfs_remove_link(&cls->devices.kobj,linkname);
+	if (cls)
+		sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr);
 }
 
-static int devclass_drv_link(struct device_driver * drv)
+struct class * class_get(struct class * cls)
 {
-	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->drivers.kobj,&drv->kobj,name);
+	if (cls)
+		return container_of(subsys_get(&cls->subsys),struct class,subsys);
+	return NULL;
 }
 
-static void devclass_drv_unlink(struct device_driver * drv)
+void class_put(struct class * cls)
 {
-	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->drivers.kobj,name);
+	subsys_put(&cls->subsys);
 }
 
+int class_register(struct class * cls)
+{
+	pr_debug("device class '%s': registering\n",cls->name);
+
+	INIT_LIST_HEAD(&cls->children);
+	INIT_LIST_HEAD(&cls->interfaces);
+	
+	strncpy(cls->subsys.kset.kobj.name,cls->name,KOBJ_NAME_LEN);
+	subsys_set_kset(cls,class_subsys);
+	subsystem_register(&cls->subsys);
 
-int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr)
+	return 0;
+}
+
+void class_unregister(struct class * cls)
 {
-	int error;
-	if (cls) {
-		error = sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr);
-	} else
-		error = -EINVAL;
+	pr_debug("device class '%s': unregistering\n",cls->name);
+	subsystem_unregister(&cls->subsys);
+}
+
+/* Class Device Stuff */
+
+int class_device_create_file(struct class_device * class_dev,
+			     struct class_device_attribute * attr)
+{
+	int error = -EINVAL;
+	if (class_dev)
+		error = sysfs_create_file(&class_dev->kobj, &attr->attr);
 	return error;
 }
 
-void devclass_remove_file(struct device_class * cls, struct devclass_attribute * attr)
+void class_device_remove_file(struct class_device * class_dev,
+			      struct class_device_attribute * attr)
 {
-	if (cls)
-		sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr);
+	if (class_dev)
+		sysfs_remove_file(&class_dev->kobj, &attr->attr);
 }
 
+static int class_device_dev_link(struct class_device * class_dev)
+{
+	if (class_dev->dev)
+		return sysfs_create_link(&class_dev->kobj,
+					 &class_dev->dev->kobj, "device");
+	return 0;
+}
 
-int devclass_add_driver(struct device_driver * drv)
+static void class_device_dev_unlink(struct class_device * class_dev)
 {
-	struct device_class * cls = get_devclass(drv->devclass);
-	int error = 0;
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, "device");
+}
 
-	if (cls) {
-		down_write(&cls->subsys.rwsem);
-		pr_debug("device class %s: adding driver %s:%s\n",
-			 cls->name,drv->bus->name,drv->name);
-		error = devclass_drv_link(drv);
-		
-		if (!error)
-			list_add_tail(&drv->class_list,&cls->drivers.list);
-		up_write(&cls->subsys.rwsem);
-	}
-	return error;
+#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
+#define to_class_dev_attr(_attr) container_of(_attr,struct class_device_attribute,attr)
+
+static ssize_t
+class_device_attr_show(struct kobject * kobj, struct attribute * attr,
+		       char * buf)
+{
+	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
+	struct class_device * cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->show)
+		ret = class_dev_attr->show(cd,buf);
+	return ret;
 }
 
-void devclass_remove_driver(struct device_driver * drv)
+static ssize_t
+class_device_attr_store(struct kobject * kobj, struct attribute * attr, 
+			const char * buf, size_t count)
 {
-	struct device_class * cls = drv->devclass;
-	if (cls) {
-		down_write(&cls->subsys.rwsem);
-		pr_debug("device class %s: removing driver %s:%s\n",
-			 cls->name,drv->bus->name,drv->name);
-		list_del_init(&drv->class_list);
-		devclass_drv_unlink(drv);
-		up_write(&cls->subsys.rwsem);
-		put_devclass(cls);
-	}
+	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
+	struct class_device * cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->store)
+		ret = class_dev_attr->store(cd,buf,count);
+	return ret;
 }
 
+static struct sysfs_ops class_dev_sysfs_ops = {
+	.show	= class_device_attr_show,
+	.store	= class_device_attr_store,
+};
 
-static void enum_device(struct device_class * cls, struct device * dev)
-{
-	u32 val;
-	val = cls->devnum++;
-	dev->class_num = val;
-	devclass_dev_link(cls,dev);
-}
-
-static void unenum_device(struct device_class * cls, struct device * dev)
-{
-	devclass_dev_unlink(cls,dev);
-	dev->class_num = 0;
-}
-
-/**
- *	devclass_add_device - register device with device class
- *	@dev:   device to be registered 
- *
- *	This is called when a device is either registered with the 
- *	core, or after the a driver module is loaded and bound to
- *	the device. 
- *	The class is determined by looking at @dev's driver, so one
- *	way or another, it must be bound to something. Once the 
- *	class is determined, it's set to prevent against concurrent
- *	calls for the same device stomping on each other. 
- *
- *	/sbin/hotplug should be called once the device is added to 
- *	class and all the interfaces. 
- */
-int devclass_add_device(struct device * dev)
+static struct kobj_type ktype_class_device = {
+	.sysfs_ops	= &class_dev_sysfs_ops,
+};
+
+static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
 {
-	struct device_class * cls;
-	int error = 0;
+	struct kobj_type *ktype = get_ktype(kobj);
 
-	down(&devclass_sem);
-	if (dev->driver) {
-		cls = get_devclass(dev->driver->devclass);
-
-		if (!cls)
-			goto Done;
-
-		pr_debug("device class %s: adding device %s\n",
-			 cls->name,dev->name);
-		if (cls->add_device) 
-			error = cls->add_device(dev);
-		if (error) {
-			put_devclass(cls);
-			goto Done;
-		}
+	if (ktype == &ktype_class_device) {
+		struct class_device *class_dev = to_class_dev(kobj);
+		if (class_dev->class)
+			return 1;
+	}
+	return 0;
+}
+
+static char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
 
-		down_write(&cls->subsys.rwsem);
-		enum_device(cls,dev);
-		list_add_tail(&dev->class_list,&cls->devices.list);
-		/* notify userspace (call /sbin/hotplug) */
-		class_hotplug (dev, "add");
+	return class_dev->class->name;
+}
 
-		up_write(&cls->subsys.rwsem);
+static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
+			 int num_envp, char *buffer, int buffer_size)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+	int retval = 0;
 
-		interface_add_dev(dev);
+	pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
+	if (class_dev->class->hotplug) {
+		/* have the bus specific function add its stuff */
+		retval = class_dev->class->hotplug (class_dev, envp, num_envp,
+						    buffer, buffer_size);
+			if (retval) {
+			pr_debug ("%s - hotplug() returned %d\n",
+				  __FUNCTION__, retval);
+		}
 	}
- Done:
-	up(&devclass_sem);
-	return error;
+
+	return retval;
 }
 
-void devclass_remove_device(struct device * dev)
+static struct kset_hotplug_ops class_hotplug_ops = {
+	.filter =	class_hotplug_filter,
+	.name =		class_hotplug_name,
+	.hotplug =	class_hotplug,
+};
+
+static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
+
+void class_device_initialize(struct class_device *class_dev)
 {
-	struct device_class * cls;
+	kobject_init(&class_dev->kobj);
+	INIT_LIST_HEAD(&class_dev->node);
+}
 
-	down(&devclass_sem);
-	if (dev->driver) {
-		cls = dev->driver->devclass;
-		if (!cls) 
-			goto Done;
+int class_device_add(struct class_device *class_dev)
+{
+	struct class * parent;
+	struct class_interface * class_intf;
+	struct list_head * entry;
+	int error;
 
-		interface_remove_dev(dev);
+	class_dev = class_device_get(class_dev);
+	if (!class_dev || !strlen(class_dev->class_id))
+		return -EINVAL;
+
+	parent = class_get(class_dev->class);
+	if (class_dev->dev)
+		get_device(class_dev->dev);
+
+	pr_debug("CLASS: registering class device: ID = '%s'\n",
+		 class_dev->class_id);
+
+	/* first, register with generic layer. */
+	strncpy(class_dev->kobj.name, class_dev->class_id, KOBJ_NAME_LEN);
+	kobj_set_kset_s(class_dev, class_subsys);
+	kobj_set_kset_s(class_dev, class_obj_subsys);
+	if (parent)
+		class_dev->kobj.parent = &parent->subsys.kset.kobj;
+
+	if ((error = kobject_add(&class_dev->kobj)))
+		goto register_done;
+
+	/* now take care of our own registration */
+	if (parent) {
+		down_write(&parent->subsys.rwsem);
+		list_add_tail(&class_dev->node, &parent->children);
+		list_for_each(entry, &parent->interfaces) {
+			class_intf = container_of(entry, struct class_interface, node);
+			if (class_intf->add)
+				class_intf->add(class_dev);
+		}
+		up_write(&parent->subsys.rwsem);
+	}
 
-		down_write(&cls->subsys.rwsem);
-		pr_debug("device class %s: removing device %s\n",
-			 cls->name,dev->name);
+	class_device_dev_link(class_dev);
 
-		unenum_device(cls,dev);
+ register_done:
+	if (error && parent)
+		class_put(parent);
+	class_device_put(class_dev);
+	return error;
+}
 
-		list_del(&dev->class_list);
+int class_device_register(struct class_device *class_dev)
+{
+	class_device_initialize(class_dev);
+	return class_device_add(class_dev);
+}
 
-		/* notify userspace (call /sbin/hotplug) */
-		class_hotplug (dev, "remove");
+void class_device_del(struct class_device *class_dev)
+{
+	struct class * parent = class_dev->class;
+	struct class_interface * class_intf;
+	struct list_head * entry;
 
-		up_write(&cls->subsys.rwsem);
+	if (parent) {
+		down_write(&parent->subsys.rwsem);
+		list_del_init(&class_dev->node);
+		list_for_each(entry, &parent->interfaces) {
+			class_intf = container_of(entry, struct class_interface, node);
+			if (class_intf->remove)
+				class_intf->remove(class_dev);
+		}
+		up_write(&parent->subsys.rwsem);
+	}
 
-		if (cls->remove_device)
-			cls->remove_device(dev);
-		put_devclass(cls);
+	if (class_dev->dev) {
+		class_device_dev_unlink(class_dev);
+		put_device(class_dev->dev);
 	}
- Done:
-	up(&devclass_sem);
+	
+	kobject_del(&class_dev->kobj);
+
+	if (parent)
+		class_put(parent);
 }
 
-struct device_class * get_devclass(struct device_class * cls)
+void class_device_unregister(struct class_device *class_dev)
 {
-	return cls ? container_of(subsys_get(&cls->subsys),struct device_class,subsys) : NULL;
+	pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
+		 class_dev->class_id);
+	class_device_del(class_dev);
+	class_device_put(class_dev);
 }
 
-void put_devclass(struct device_class * cls)
+struct class_device * class_device_get(struct class_device *class_dev)
 {
-	subsys_put(&cls->subsys);
+	if (class_dev)
+		return to_class_dev(kobject_get(&class_dev->kobj));
+	return NULL;
+}
+
+void class_device_put(struct class_device *class_dev)
+{
+	kobject_put(&class_dev->kobj);
 }
 
 
-int devclass_register(struct device_class * cls)
+int class_interface_register(struct class_interface *class_intf)
 {
-	pr_debug("device class '%s': registering\n",cls->name);
-	strncpy(cls->subsys.kset.kobj.name,cls->name,KOBJ_NAME_LEN);
-	subsys_set_kset(cls,class_subsys);
-	subsystem_register(&cls->subsys);
+	struct class * parent;
+	struct class_device * class_dev;
+	struct list_head * entry;
+
+	if (!class_intf || !class_intf->class)
+		return -ENODEV;
 
-	snprintf(cls->devices.kobj.name,KOBJ_NAME_LEN,"devices");
-	cls->devices.subsys = &cls->subsys;
-	kset_register(&cls->devices);
-
-	snprintf(cls->drivers.kobj.name,KOBJ_NAME_LEN,"drivers");
-	cls->drivers.subsys = &cls->subsys;
-	kset_register(&cls->drivers);
+	parent = class_get(class_intf->class);
+	if (!parent)
+		return -EINVAL;
+
+	down_write(&parent->subsys.rwsem);
+	list_add_tail(&class_intf->node, &parent->interfaces);
+
+	if (class_intf->add) {
+		list_for_each(entry, &parent->children) {
+			class_dev = container_of(entry, struct class_device, node);
+			class_intf->add(class_dev);
+		}
+	}
+	up_write(&parent->subsys.rwsem);
 
 	return 0;
 }
 
-void devclass_unregister(struct device_class * cls)
+void class_interface_unregister(struct class_interface *class_intf)
 {
-	pr_debug("device class '%s': unregistering\n",cls->name);
-	kset_unregister(&cls->drivers);
-	kset_unregister(&cls->devices);
-	subsystem_unregister(&cls->subsys);
+	struct class * parent = class_intf->class;
+	struct list_head * entry;
+
+	if (!parent)
+		return;
+
+	down_write(&parent->subsys.rwsem);
+	list_del_init(&class_intf->node);
+
+	if (class_intf->remove) {
+		list_for_each(entry, &parent->children) {
+			struct class_device *class_dev = container_of(entry, struct class_device, node);
+			class_intf->remove(class_dev);
+		}
+	}
+	up_write(&parent->subsys.rwsem);
+
+	class_put(parent);
 }
 
+
+
 int __init classes_init(void)
 {
-	return subsystem_register(&class_subsys);
+	int retval;
+
+	retval = subsystem_register(&class_subsys);
+	if (retval)
+		return retval;
+
+	/* ick, this is ugly, the things we go through to keep from showing up
+	 * in sysfs... */
+	subsystem_init(&class_obj_subsys);
+	if (!class_obj_subsys.kset.subsys)
+			class_obj_subsys.kset.subsys = &class_obj_subsys;
+	return 0;
 }
 
-EXPORT_SYMBOL(devclass_create_file);
-EXPORT_SYMBOL(devclass_remove_file);
-EXPORT_SYMBOL(devclass_register);
-EXPORT_SYMBOL(devclass_unregister);
-EXPORT_SYMBOL(get_devclass);
-EXPORT_SYMBOL(put_devclass);
+EXPORT_SYMBOL(class_create_file);
+EXPORT_SYMBOL(class_remove_file);
+EXPORT_SYMBOL(class_register);
+EXPORT_SYMBOL(class_unregister);
+EXPORT_SYMBOL(class_get);
+EXPORT_SYMBOL(class_put);
+
+EXPORT_SYMBOL(class_device_register);
+EXPORT_SYMBOL(class_device_unregister);
+EXPORT_SYMBOL(class_device_initialize);
+EXPORT_SYMBOL(class_device_add);
+EXPORT_SYMBOL(class_device_del);
+EXPORT_SYMBOL(class_device_get);
+EXPORT_SYMBOL(class_device_put);
+EXPORT_SYMBOL(class_device_create_file);
+EXPORT_SYMBOL(class_device_remove_file);
 
+EXPORT_SYMBOL(class_interface_register);
+EXPORT_SYMBOL(class_interface_unregister);
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/core.c	Tue Apr 29 09:48:19 2003
@@ -185,7 +185,6 @@
 	INIT_LIST_HEAD(&dev->children);
 	INIT_LIST_HEAD(&dev->driver_list);
 	INIT_LIST_HEAD(&dev->bus_list);
-	INIT_LIST_HEAD(&dev->class_list);
 }
 
 /**
@@ -235,7 +234,6 @@
 	if (platform_notify)
 		platform_notify(dev);
 
-	devclass_add_device(dev);
  register_done:
 	if (error && parent)
 		put_device(parent);
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	Tue Apr 29 09:48:19 2003
+++ b/drivers/base/driver.c	Tue Apr 29 09:48:19 2003
@@ -82,7 +82,6 @@
 int driver_register(struct device_driver * drv)
 {
 	INIT_LIST_HEAD(&drv->devices);
-	INIT_LIST_HEAD(&drv->class_list);
 	init_MUTEX_LOCKED(&drv->unload_sem);
 	return bus_add_driver(drv);
 }
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Tue Apr 29 09:48:19 2003
+++ b/include/linux/device.h	Tue Apr 29 09:48:19 2003
@@ -1,7 +1,7 @@
 /*
  * device.h - generic, centralized driver model
  *
- * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
+ * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
  *
  * This is a relatively simple centralized driver model.
  * The data structures were mainly lifted directly from the PCI
@@ -60,7 +60,8 @@
 
 struct device;
 struct device_driver;
-struct device_class;
+struct class;
+struct class_device;
 
 struct bus_type {
 	char			* name;
@@ -116,11 +117,9 @@
 struct device_driver {
 	char			* name;
 	struct bus_type		* bus;
-	struct device_class	* devclass;
 
 	struct semaphore	unload_sem;
 	struct kobject		kobj;
-	struct list_head	class_list;
 	struct list_head	devices;
 
 	int	(*probe)	(struct device * dev);
@@ -160,74 +159,106 @@
 /*
  * device classes
  */
-struct device_class {
+struct class {
 	char			* name;
-	u32			devnum;
 
 	struct subsystem	subsys;
-	struct kset		devices;
-	struct kset		drivers;
+	struct list_head	children;
+	struct list_head	interfaces;
 
-	int	(*add_device)(struct device *);
-	void	(*remove_device)(struct device *);
-	int	(*hotplug)(struct device *dev, char **envp, 
+	int	(*hotplug)(struct class_device *dev, char **envp, 
 			   int num_envp, char *buffer, int buffer_size);
 };
 
-extern int devclass_register(struct device_class *);
-extern void devclass_unregister(struct device_class *);
+extern int class_register(struct class *);
+extern void class_unregister(struct class *);
 
-extern struct device_class * get_devclass(struct device_class *);
-extern void put_devclass(struct device_class *);
+extern struct class * class_get(struct class *);
+extern void class_put(struct class *);
 
 
-struct devclass_attribute {
+struct class_attribute {
 	struct attribute	attr;
-	ssize_t (*show)(struct device_class *, char * buf);
-	ssize_t (*store)(struct device_class *, const char * buf, size_t count);
+	ssize_t (*show)(struct class *, char * buf);
+	ssize_t (*store)(struct class *, const char * buf, size_t count);
 };
 
-#define DEVCLASS_ATTR(_name,_str,_mode,_show,_store)	\
-struct devclass_attribute devclass_attr_##_name = { 		\
-	.attr = {.name	= _str,	.mode	= _mode },	\
-	.show	= _show,				\
-	.store	= _store,				\
+#define CLASS_ATTR(_name,_mode,_show,_store)			\
+struct class_attribute class_attr_##_name = { 			\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.show	= _show,					\
+	.store	= _store,					\
 };
 
-extern int devclass_create_file(struct device_class *, struct devclass_attribute *);
-extern void devclass_remove_file(struct device_class *, struct devclass_attribute *);
+extern int class_create_file(struct class *, struct class_attribute *);
+extern void class_remove_file(struct class *, struct class_attribute *);
 
 
-/*
- * device interfaces
- * These are the logical interfaces of device classes. 
- * These entities map directly to specific userspace interfaces, like 
- * device nodes.
- * Interfaces are registered with the device class they belong to. When
- * a device is registered with the class, each interface's add_device 
- * callback is called. It is up to the interface to decide whether or not
- * it supports the device.
- */
+struct class_device {
+	struct list_head	node;
 
-struct device_interface {
-	char			* name;
-	struct device_class	* devclass;
+	struct kobject		kobj;
+	struct class		* class;	/* required */
+	struct device		* dev;		/* not necessary, but nice to have */
+	void			* class_data;	/* class-specific data */
+
+	char	class_id[BUS_ID_SIZE];	/* unique to this class */
+};
+
+static inline void *
+class_get_devdata (struct class_device *dev)
+{
+	return dev->class_data;
+}
+
+static inline void
+class_set_devdata (struct class_device *dev, void *data)
+{
+	dev->class_data = data;
+}
+
+
+extern int class_device_register(struct class_device *);
+extern void class_device_unregister(struct class_device *);
+extern void class_device_initialize(struct class_device *);
+extern int class_device_add(struct class_device *);
+extern void class_device_del(struct class_device *);
+
+extern struct class_device * class_device_get(struct class_device *);
+extern void class_device_put(struct class_device *);
+
+struct class_device_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct class_device *, char * buf);
+	ssize_t (*store)(struct class_device *, const char * buf, size_t count);
+};
+
+#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store)		\
+struct class_device_attribute class_device_attr_##_name = { 	\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.show	= _show,					\
+	.store	= _store,					\
+};
 
-	struct kset		kset;
-	u32			devnum;
+extern int class_device_create_file(struct class_device *, struct class_device_attribute *);
+extern void class_device_remove_file(struct class_device *, struct class_device_attribute *);
 
-	int (*add_device)	(struct device *);
-	int (*remove_device)	(struct device *);
+
+struct class_interface {
+	struct list_head	node;
+	struct class		*class;
+
+	int (*add)	(struct class_device *);
+	void (*remove)	(struct class_device *);
 };
 
-extern int interface_register(struct device_interface *);
-extern void interface_unregister(struct device_interface *);
+extern int class_interface_register(struct class_interface *);
+extern void class_interface_unregister(struct class_interface *);
 
 
 struct device {
 	struct list_head node;		/* node in sibling list */
 	struct list_head bus_list;	/* node in bus's list */
-	struct list_head class_list;
 	struct list_head driver_list;
 	struct list_head children;
 	struct device 	* parent;
@@ -240,14 +271,10 @@
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
 	void		*driver_data;	/* data private to the driver */
-
-	u32		class_num;	/* class-enumerated value */
-	void		* class_data;	/* class-specific data */
-
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
 					   BIOS data relevant to device) */
 
-	u32		power_state;  /* Current operating state. In
+	u32		power_state;	/* Current operating state. In
 					   ACPI-speak, this is D0-D3, D0
 					   being fully functional, and D3
 					   being off. */
@@ -347,6 +374,7 @@
 	u32		id;
 	struct sys_root	* root;
 	struct device	dev;
+	struct class_device class_dev;
 };
 
 extern int sys_device_register(struct sys_device *);
