linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] Device class rework [0/5]
@ 2003-04-22 20:55 Greg KH
  2003-04-22 20:57 ` [RFC] Device class rework [1/5] Greg KH
  2003-04-23  0:59 ` [RFC] Device class rework [0/5] Hanna Linder
  0 siblings, 2 replies; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:55 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

Hi,

Here's a set of patches that rework the current class support in the
kernel today into something that works a bit better, and is simpler to
use.

Currently, classes are assigned to drivers at compile time (or at the
latest, at driver_register() time) and enforce a 1 to 1 relationship
between class devices and struct device objects.  This is not practical
in the kernel, as there are a number of physical devices that
correspond to multiple "class" devices.  It's also unwieldy to bind
classes to devices so early.  They should be explicitly done later when
the class device is registered with that subsystem.

So with that in mind, here's some changes.  The rework of the driver
core is all done right now in one big patch, but I'll split it up
smaller for inclusion later on.

This patch gets rid of struct device_class and struct device_interface,
and replaces them with struct class[1], struct class_device, and struct
class_interface.  struct class is much like struct device_class used to
be, but is much smaller, and not bound to any drivers.  This makes the
driver core a lot smaller, as we get hotplug events for free now (struct
class_device is a kobject), and is more flexible.

A struct class_device is registered with a class when that device is
registered within the kernel.  As an example of this, see the tty patch
later on in this email thread.

A struct class_interface is used to get a callback whenever a struct
class_device is registered or unregistered with a class.  This can be
used to attach files to the class_device, or do more complicated things.
The patch that changes the cpufreq code in this email thread shows how
this can be used (although the cpufreq code can be further simplified
based on these changes, I've not done it yet.)

If there are no major objections to this, I'll split it up into smaller
pieces for inclusion in the kernel tree.

I'll follow this message up with 5 patches that do the following things:
 - all of the driver core conversions.  This is the meat of the
   changes.
 - Fixes for the input core to build properly.  I've not converted the
   input core to the new class model yet, but will after this.
 - Crude patches to the scsi core to get it to build properly.  This
   patch is not correct, but needed if your machines have scsi.  Mike
   Anderson has said he will fix up the scsi code based on these core
   changes.
 - cpufreq changes.  This converts the cpufreq code to the new driver
   class changes.
 - tty changes.  This converts the tty code to the new driver class
   changes.  With this patch, we now show all tty devices, and their
   device major/minor number in the /sys/class/tty/ directory.  Yes,
   this is still a bit crude (all ptys are shown, and they should not
   be), but it's an example of why these changes are needed, and how to
   add class support to a subsystem.  I'll rework this after Christoph's
   and Al Viro's tty changes are in the main tree, as we all are
   touching the same part of code.

Oh, and I didn't touch the pcmcia code yet either, with these patches,
that code will not compile properly.

Any comments?

thanks,

greg k-h

[1] Yes, that's "struct class", and yes, I mean it.  If you don't like
    it, please propose something else that describes what it does.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC] Device class rework [1/5]
  2003-04-22 20:55 [RFC] Device class rework [0/5] Greg KH
@ 2003-04-22 20:57 ` Greg KH
  2003-04-22 20:57   ` [RFC] Device class rework [2/5] Greg KH
  2003-04-23  0:59 ` [RFC] Device class rework [0/5] Hanna Linder
  1 sibling, 1 reply; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:57 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

Oh, these are all against a clean 2.5.68, sorry to not note that, last
message.

On Tue, Apr 22, 2003 at 01:55:45PM -0700, Greg KH wrote:
>  - all of the driver core conversions.  This is the meat of the
>    changes.


diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Tue Apr 22 13:08:01 2003
+++ b/drivers/base/Makefile	Tue Apr 22 13:08:01 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 22 13:07:57 2003
+++ b/drivers/base/base.h	Tue Apr 22 13:07:57 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 22 13:07:50 2003
+++ b/drivers/base/bus.c	Tue Apr 22 13:07:50 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 22 13:08:03 2003
+++ b/drivers/base/class.c	Tue Apr 22 13:08:03 2003
@@ -10,16 +10,16 @@
 #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)
+#define to_class_attr(_attr) container_of(_attr,struct class_attribute,attr)
+#define to_class(obj) container_of(obj,struct class,subsys.kset.kobj)
 
-DECLARE_MUTEX(devclass_sem);
+DECLARE_MUTEX(class_dev_sem);
 
 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,369 @@
 }
 
 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);
 
-int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr)
+	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);
+
+	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 struct kobj_type ktype_class_device = {
+	.sysfs_ops	= &class_dev_sysfs_ops,
+};
 
-static void enum_device(struct device_class * cls, struct device * dev)
+static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
 {
-	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)
-{
-	struct device_class * cls;
-	int error = 0;
-
-	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;
-		}
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	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(&class_dev_sem);
+		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(&class_dev_sem);
+	}
 
-		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(&class_dev_sem);
+		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(&class_dev_sem);
+	}
 
-		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;
+
+	parent = class_get(class_intf->class);
+
+	down(&class_dev_sem);
+	list_add_tail(&class_intf->node, &parent->interfaces);
 
-	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);
+	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(&class_dev_sem);
 
 	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;
+
+	down(&class_dev_sem);
+	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(&class_dev_sem);
+
+	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);
 
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Tue Apr 22 13:07:51 2003
+++ b/drivers/base/core.c	Tue Apr 22 13:07:51 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/cpu.c b/drivers/base/cpu.c
--- a/drivers/base/cpu.c	Tue Apr 22 13:07:58 2003
+++ b/drivers/base/cpu.c	Tue Apr 22 13:07:58 2003
@@ -10,23 +10,16 @@
 #include <asm/topology.h>
 
 
-static int cpu_add_device(struct device * dev)
-{
-	return 0;
-}
-struct device_class cpu_devclass = {
+struct class cpu_class = {
 	.name		= "cpu",
-	.add_device	= cpu_add_device,
 };
 
 
 struct device_driver cpu_driver = {
 	.name		= "cpu",
 	.bus		= &system_bus_type,
-	.devclass	= &cpu_devclass,
 };
 
-
 /*
  * register_cpu - Setup a driverfs device for a CPU.
  * @num - CPU number to use when creating the device.
@@ -35,6 +28,8 @@
  */
 int __init register_cpu(struct cpu *cpu, int num, struct node *root)
 {
+	int retval;
+
 	cpu->node_id = cpu_to_node(num);
 	cpu->sysdev.name = "cpu";
 	cpu->sysdev.id = num;
@@ -42,7 +37,19 @@
 		cpu->sysdev.root = &root->sysroot;
 	snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num);
 	cpu->sysdev.dev.driver = &cpu_driver;
-	return sys_device_register(&cpu->sysdev);
+	retval = sys_device_register(&cpu->sysdev);
+	if (retval)
+		return retval;
+	memset(&cpu->sysdev.class_dev, 0x00, sizeof(struct class_device));
+	cpu->sysdev.class_dev.dev = &cpu->sysdev.dev;
+	cpu->sysdev.class_dev.class = &cpu_class;
+	snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num);
+	retval = class_device_register(&cpu->sysdev.class_dev);
+	if (retval) {
+		// FIXME cleanup sys_device_register
+		return retval;
+	}
+	return 0;
 }
 
 
@@ -50,11 +57,11 @@
 {
 	int error;
 
-	error = devclass_register(&cpu_devclass);
+	error = class_register(&cpu_class);
 	if (!error) {
 		error = driver_register(&cpu_driver);
 		if (error)
-			devclass_unregister(&cpu_devclass);
+			class_unregister(&cpu_class);
 	}
 	return error;
 }
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	Tue Apr 22 13:08:03 2003
+++ b/drivers/base/driver.c	Tue Apr 22 13:08:03 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/drivers/base/fs/Makefile b/drivers/base/fs/Makefile
--- a/drivers/base/fs/Makefile	Tue Apr 22 13:08:03 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,2 +0,0 @@
-obj-y		:= device.o
-
diff -Nru a/drivers/base/fs/device.c b/drivers/base/fs/device.c
--- a/drivers/base/fs/device.c	Tue Apr 22 13:07:49 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,49 +0,0 @@
-/*
- * drivers/base/fs.c - driver model interface to driverfs 
- *
- * Copyright (c) 2002 Patrick Mochel
- *		 2002 Open Source Development Lab
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/stat.h>
-#include <linux/limits.h>
-
-int get_devpath_length(struct device * dev)
-{
-	int length = 1;
-	struct device * parent = dev;
-
-	/* walk up the ancestors until we hit the root.
-	 * Add 1 to strlen for leading '/' of each level.
-	 */
-	do {
-		length += strlen(parent->bus_id) + 1;
-		parent = parent->parent;
-	} while (parent);
-	return length;
-}
-
-void fill_devpath(struct device * dev, char * path, int length)
-{
-	struct device * parent;
-	--length;
-	for (parent = dev; parent; parent = parent->parent) {
-		int cur = strlen(parent->bus_id);
-
-		/* back up enough to print this bus id with '/' */
-		length -= cur;
-		strncpy(path + length,parent->bus_id,cur);
-		*(path + --length) = '/';
-	}
-
-	pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
-}
-
diff -Nru a/drivers/base/fs/fs.h b/drivers/base/fs/fs.h
--- a/drivers/base/fs/fs.h	Tue Apr 22 13:07:53 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-
-int get_devpath_length(struct device * dev);
-
-void fill_devpath(struct device * dev, char * path, int length);
-
diff -Nru a/drivers/base/hotplug.c b/drivers/base/hotplug.c
--- a/drivers/base/hotplug.c	Tue Apr 22 13:07:49 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-/*
- * drivers/base/hotplug.c - hotplug call code
- * 
- * Copyright (c) 2000-2001 David Brownell
- * Copyright (c) 2002-2003 Greg Kroah-Hartman
- * Copyright (c) 2002-2003 IBM Corp.
- *
- * Based off of drivers/usb/core/usb.c:call_agent(), which was 
- * written by David Brownell.
- *
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/kmod.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include "base.h"
-#include "fs/fs.h"
-
-/*
- * hotplugging invokes what /proc/sys/kernel/hotplug says (normally
- * /sbin/hotplug) when devices or classes get added or removed.
- *
- * This invokes a user mode policy agent, typically helping to load driver
- * or other modules, configure the device, and more.  Drivers can provide
- * a MODULE_DEVICE_TABLE to help with module loading subtasks.
- *
- * See the documentation at http://linux-hotplug.sf.net for more info.
- * 
- */
-
-#define BUFFER_SIZE	1024	/* should be enough memory for the env */
-#define NUM_ENVP	32	/* number of env pointers */
-
-static char prefix [] = "devices";	/* /sys/devices/... */
-
-static int do_hotplug (struct device *dev, char *argv1, const char *action,
-			int (* hotplug) (struct device *, char **, int, char *, int))
-{
-	char *argv [3], **envp, *buffer, *scratch;
-	char *dev_path;
-	int retval;
-	int i = 0;
-	int dev_length;
-
-	pr_debug ("%s\n", __FUNCTION__);
-
-	if (!hotplug_path [0])
-		return -ENODEV;
-
-	envp = (char **) kmalloc (NUM_ENVP * sizeof (char *), GFP_KERNEL);
-	if (!envp)
-		return -ENOMEM;
-	memset (envp, 0x00, NUM_ENVP * sizeof (char *));
-
-	buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
-	if (!buffer) {
-		kfree (envp);
-		return -ENOMEM;
-	}
-
-	dev_length = get_devpath_length (dev);
-	dev_length += strlen(prefix);
-	dev_path = kmalloc (dev_length, GFP_KERNEL);
-	if (!dev_path) {
-		kfree (buffer);
-		kfree (envp);
-		return -ENOMEM;
-	}
-	memset (dev_path, 0x00, dev_length);
-	strcpy (dev_path, prefix);
-	fill_devpath (dev, dev_path, dev_length);
-
-	argv [0] = hotplug_path;
-	argv [1] = argv1;
-	argv [2] = 0;
-
-	/* minimal command environment */
-	envp [i++] = "HOME=/";
-	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
-	scratch = buffer;
-
-	envp [i++] = scratch;
-	scratch += sprintf (scratch, "ACTION=%s", action) + 1;
-
-	envp [i++] = scratch;
-	scratch += sprintf (scratch, "DEVPATH=%s", dev_path) + 1;
-	
-	if (hotplug) {
-		/* have the bus specific function add its stuff */
-		retval = hotplug (dev, &envp[i], NUM_ENVP - i, scratch,
-				  BUFFER_SIZE - (scratch - buffer));
-		if (retval) {
-			pr_debug ("%s - hotplug() returned %d\n",
-				  __FUNCTION__, retval);
-			goto exit;
-		}
-	}
-
-	pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1],
-		  envp[0], envp[1], envp[2], envp[3]);
-	retval = call_usermodehelper (argv [0], argv, envp, 0);
-	if (retval)
-		pr_debug ("%s - call_usermodehelper returned %d\n",
-			  __FUNCTION__, retval);
-
-exit:
-	kfree (dev_path);
-	kfree (buffer);
-	kfree (envp);
-	return retval;
-}
-
-/*
- * class_hotplug - called when a class is added or removed from a device
- */
-int class_hotplug (struct device *dev, const char *action)
-{
-	struct device_class * cls;
-	int retval;
-
-	pr_debug ("%s\n", __FUNCTION__);
-
-	if (!dev)
-		return -ENODEV;
-
-	if (!dev->bus)
-		return -ENODEV;
-
-	cls = get_devclass(dev->driver->devclass);
-	if (!cls)
-		return -ENODEV;
-
-	retval = do_hotplug (dev, cls->name, action, cls->hotplug);
-
-	put_devclass(cls);
-
-	return retval;
-}
diff -Nru a/drivers/base/intf.c b/drivers/base/intf.c
--- a/drivers/base/intf.c	Tue Apr 22 13:07:50 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,225 +0,0 @@
-/*
- * intf.c - class-specific interface management
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include "base.h"
-
-
-#define to_intf(node) container_of(node,struct device_interface,kset.kobj.entry)
-
-#define to_dev(d) container_of(d,struct device,class_list)
-
-/**
- *	intf_dev_link - create sysfs symlink for interface.
- *	@intf:	interface.
- *	@dev:	device.
- *
- *	Create a symlink 'phys' in the interface's directory to 
- */
-
-static int intf_dev_link(struct device_interface * intf, struct device * dev)
-{
-	return sysfs_create_link(&intf->kset.kobj,&dev->kobj,dev->bus_id);
-}
-
-/**
- *	intf_dev_unlink - remove symlink for interface.
- *	@intf:	interface.
- *	@dev:	device.
- *
- */
-
-static void intf_dev_unlink(struct device_interface * intf, struct device * dev)
-{
-	sysfs_remove_link(&intf->kset.kobj,dev->bus_id);
-}
-
-
-/**
- *	add - attach device to interface
- *	@intf:	interface.
- *	@dev:	device.
- *
- *	This is just a simple helper. Check the interface's interface
- *	helper and call it. This is called when adding an interface
- *	the class's devices, or a device to the class's interfaces.
- */
-
-static int add(struct device_interface * intf, struct device * dev)
-{
-	int error = 0;
-
-	if (intf->add_device) {
-		if (!(error = intf->add_device(dev)))
-			intf_dev_link(intf,dev);
-	}
-	pr_debug(" -> %s (%d)\n",dev->bus_id,error);
-	return error;
-}
-
-/**
- *	del - detach device from interface.
- *	@intf:	interface.
- *	@dev:	device.
- */
-
-static void del(struct device_interface * intf, struct device * dev)
-{
-	pr_debug(" -> %s ",intf->name);
-	if (intf->remove_device)
-		intf->remove_device(dev);
-	intf_dev_unlink(intf,dev);
-}
-
-
-/**
- *	add_intf - add class's devices to interface.
- *	@intf:	interface.
- *
- *	Loop over the devices registered with the class, and call
- *	the interface's add_device() method for each.
- *
- *	On an error, we won't break, but we will print debugging info.
- */
-static void add_intf(struct device_interface * intf)
-{
-	struct device_class * cls = intf->devclass;
-	struct list_head * entry;
-
-	list_for_each(entry,&cls->devices.list)
-		add(intf,to_dev(entry));
-}
-
-/**
- *	interface_register - register an interface with a device class.
- *	@intf:	interface.
- *
- *	An interface may be loaded after drivers and devices have been
- *	added to the class. So, we must add each device already known to
- *	the class to the interface as its registered.
- */
-
-int interface_register(struct device_interface * intf)
-{
-	struct device_class * cls = get_devclass(intf->devclass);
-
-	down(&devclass_sem);
-	if (cls) {
-		pr_debug("register interface '%s' with class '%s'\n",
-			 intf->name,cls->name);
-
-		strncpy(intf->kset.kobj.name,intf->name,KOBJ_NAME_LEN);
-		kset_set_kset_s(intf,cls->subsys);
-		kset_register(&intf->kset);
-		add_intf(intf);
-	}
-	up(&devclass_sem);
-	return 0;
-}
-
-
-/**
- *	del_intf - remove devices from interface.
- *	@intf:	interface being unloaded.
- *
- *	This loops over the devices registered with a class and 
- *	calls the interface's remove_device() method for each.
- *	This is called when an interface is being unregistered.
- */
-
-static void del_intf(struct device_interface * intf)
-{
-	struct device_class * cls = intf->devclass;
-	struct list_head * entry;
-
-	list_for_each(entry,&cls->devices.list) {
-		struct device * dev = to_dev(entry);
-		del(intf,dev);
-	}
-}
-
-/**
- *	interface_unregister - remove interface from class.
- *	@intf:	interface.
- *
- *	This is called when an interface in unloaded, giving it a
- *	chance to remove itself from devicse that have been added to 
- *	it.
- */
-
-void interface_unregister(struct device_interface * intf)
-{
-	struct device_class * cls = intf->devclass;
-
-	down(&devclass_sem);
-	if (cls) {
-		pr_debug("unregistering interface '%s' from class '%s'\n",
-			 intf->name,cls->name);
-		del_intf(intf);
-		kset_unregister(&intf->kset);
-		put_devclass(cls);
-	}
-	up(&devclass_sem);
-}
-
-
-/**
- *	interface_add_dev - add device to interfaces.
- *	@dev:	device.
- *
- *	This is a helper for the class driver core. When a 
- *	device is being added to a class, this is called to add
- *	the device to all the interfaces in the class.
- *
- *	The operation is simple enough: loop over the interfaces
- *	and call add() [above] for each. The class rwsem is assumed
- *	to be held.
- */
-
-int interface_add_dev(struct device * dev)
-{
-	struct device_class * cls = dev->driver->devclass;
-	struct list_head * node;
-
-	pr_debug("interfaces: adding device %s\n",dev->name);
-
-	list_for_each(node,&cls->subsys.kset.list) {
-		struct device_interface * intf = to_intf(node);
-		add(intf,dev);
-	}
-	return 0;
-}
-
-
-/**
- *	interface_remove_dev - remove device from interfaces.
- *	@dev:	device.
- *
- *	This is another helper for the class driver core, and called
- *	when the device is being removed from the class. 
- *	
- *	We iterate over the list of the class's devices and call del() 
- *	[above] for each. Again, the class's rwsem is _not_ held, but
- *	the devclass_sem is (see class.c).
- */
-
-void interface_remove_dev(struct device * dev)
-{
-	struct list_head * entry, * next;
-	struct device_class * cls = dev->driver->devclass;
-
-	pr_debug("interfaces: removing device %s\n",dev->name);
-
-	list_for_each_safe(entry,next,&cls->subsys.kset.list) {
-		struct device_interface * intf = to_intf(entry);
-		del(intf,dev);
-	}
-}
-
-EXPORT_SYMBOL(interface_register);
-EXPORT_SYMBOL(interface_unregister);
diff -Nru a/drivers/base/memblk.c b/drivers/base/memblk.c
--- a/drivers/base/memblk.c	Tue Apr 22 13:07:56 2003
+++ b/drivers/base/memblk.c	Tue Apr 22 13:07:56 2003
@@ -11,20 +11,14 @@
 #include <asm/topology.h>
 
 
-static int memblk_add_device(struct device * dev)
-{
-	return 0;
-}
-struct device_class memblk_devclass = {
+static struct class memblk_class = {
 	.name		= "memblk",
-	.add_device	= memblk_add_device,
 };
 
 
-struct device_driver memblk_driver = {
+static struct device_driver memblk_driver = {
 	.name		= "memblk",
 	.bus		= &system_bus_type,
-	.devclass	= &memblk_devclass,
 };
 
 
@@ -51,11 +45,11 @@
 {
 	int error;
 
-	error = devclass_register(&memblk_devclass);
+	error = class_register(&memblk_class);
 	if (!error) {
 		error = driver_register(&memblk_driver);
 		if (error)
-			devclass_unregister(&memblk_devclass);
+			class_unregister(&memblk_class);
 	}
 	return error;
 }
diff -Nru a/drivers/base/node.c b/drivers/base/node.c
--- a/drivers/base/node.c	Tue Apr 22 13:07:58 2003
+++ b/drivers/base/node.c	Tue Apr 22 13:07:58 2003
@@ -11,20 +11,14 @@
 #include <asm/topology.h>
 
 
-static int node_add_device(struct device * dev)
-{
-	return 0;
-}
-struct device_class node_devclass = {
+static struct class node_class = {
 	.name		= "node",
-	.add_device	= node_add_device,
 };
 
 
-struct device_driver node_driver = {
+static struct device_driver node_driver = {
 	.name		= "node",
 	.bus		= &system_bus_type,
-	.devclass	= &node_devclass,
 };
 
 
@@ -93,11 +87,11 @@
 {
 	int error;
 	
-	error = devclass_register(&node_devclass);
+	error = class_register(&node_class);
 	if (!error) {
 		error = driver_register(&node_driver);
 		if (error)
-			devclass_unregister(&node_devclass);
+			class_unregister(&node_class);
 	}
 	return error;
 }
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Tue Apr 22 13:08:00 2003
+++ b/include/linux/device.h	Tue Apr 22 13:08:00 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 *);
+	int (*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 *);

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC] Device class rework [2/5]
  2003-04-22 20:57 ` [RFC] Device class rework [1/5] Greg KH
@ 2003-04-22 20:57   ` Greg KH
  2003-04-22 20:58     ` [RFC] Device class rework [3/5] Greg KH
  0 siblings, 1 reply; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:57 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

On Tue, Apr 22, 2003 at 01:55:45PM -0700, Greg KH wrote:
>  - Fixes for the input core to build properly.  I've not converted the
>    input core to the new class model yet, but will after this.


diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c
--- a/drivers/input/evbug.c	Tue Apr 22 13:07:49 2003
+++ b/drivers/input/evbug.c	Tue Apr 22 13:07:49 2003
@@ -88,19 +88,8 @@
 	.id_table =	evbug_ids,
 };
 
-static struct device_interface evbug_intf = {
-	.name		= "debug",
-	.devclass	= &input_devclass,
-};
-
 int __init evbug_init(void)
 {
-	int retval;
-
-	retval = interface_register(&evbug_intf);
-	if(retval < 0)
-		return retval;
-
 	input_register_handler(&evbug_handler);
 	return 0;
 }
@@ -108,7 +97,6 @@
 void __exit evbug_exit(void)
 {
 	input_unregister_handler(&evbug_handler);
-	interface_unregister(&evbug_intf);
 }
 
 module_init(evbug_init);
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Tue Apr 22 13:07:53 2003
+++ b/drivers/input/evdev.c	Tue Apr 22 13:07:53 2003
@@ -435,19 +435,8 @@
 	.id_table =	evdev_ids,
 };
 
-static struct device_interface evdev_intf = {
-	.name		= "event",
-	.devclass	= &input_devclass,
-};
-
 static int __init evdev_init(void)
 {
-	int retval;
-
-	retval = interface_register(&evdev_intf);
-	if(retval < 0)
-		return retval;
-
 	input_register_handler(&evdev_handler);
 	return 0;
 }
@@ -455,7 +444,6 @@
 static void __exit evdev_exit(void)
 {
 	input_unregister_handler(&evdev_handler);
-	interface_unregister(&evdev_intf);
 }
 
 module_init(evdev_init);
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Tue Apr 22 13:07:58 2003
+++ b/drivers/input/input.c	Tue Apr 22 13:07:58 2003
@@ -38,7 +38,7 @@
 EXPORT_SYMBOL(input_accept_process);
 EXPORT_SYMBOL(input_flush_device);
 EXPORT_SYMBOL(input_event);
-EXPORT_SYMBOL(input_devclass);
+EXPORT_SYMBOL(input_class);
 
 #define INPUT_MAJOR	13
 #define INPUT_DEVICES	256
@@ -675,7 +675,7 @@
 
 #endif
 
-struct device_class input_devclass = {
+struct class input_class = {
 	.name		= "input",
 };
 
@@ -683,7 +683,7 @@
 {
 	struct proc_dir_entry *entry;
 
-	devclass_register(&input_devclass);
+	class_register(&input_class);
 
 #ifdef CONFIG_PROC_FS
 	proc_bus_input_dir = proc_mkdir("input", proc_bus);
@@ -714,7 +714,7 @@
 	devfs_unregister(input_devfs_handle);
         if (unregister_chrdev(INPUT_MAJOR, "input"))
                 printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
-	devclass_unregister(&input_devclass);
+	class_unregister(&input_class);
 }
 
 subsys_initcall(input_init);
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	Tue Apr 22 13:08:02 2003
+++ b/drivers/input/mousedev.c	Tue Apr 22 13:08:02 2003
@@ -487,18 +487,8 @@
 };
 #endif
 
-static struct device_interface mousedev_intf = {
-	.name		= "mouse",
-	.devclass	= &input_devclass,
-};
-
 static int __init mousedev_init(void)
 {
-	int retval;
-
-	if((retval = interface_register(&mousedev_intf)) < 0)
-		return retval;
-
 	input_register_handler(&mousedev_handler);
 
 	memset(&mousedev_mix, 0, sizeof(struct mousedev));
@@ -527,7 +517,6 @@
 #endif
 	input_unregister_minor(mousedev_mix.devfs);
 	input_unregister_handler(&mousedev_handler);
-	interface_unregister(&mousedev_intf);
 }
 
 module_init(mousedev_init);
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Tue Apr 22 13:07:59 2003
+++ b/drivers/usb/input/hid-core.c	Tue Apr 22 13:07:59 2003
@@ -1664,9 +1664,6 @@
 	.probe =	hid_probe,
 	.disconnect =	hid_disconnect,
 	.id_table =	hid_usb_ids,
-	.driver	= {
-		.devclass = &input_devclass,
-	},
 };
 
 static int __init hid_init(void)
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Tue Apr 22 13:07:53 2003
+++ b/include/linux/input.h	Tue Apr 22 13:07:53 2003
@@ -909,7 +909,7 @@
 #define input_regs(a,b)		do { (a)->regs = (b); } while (0)
 #define input_sync(a)		do { input_event(a, EV_SYN, SYN_REPORT, 0); (a)->regs = NULL; } while (0)
 
-extern struct device_class input_devclass;
+extern struct class input_class;
 
 #endif
 #endif

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC] Device class rework [3/5]
  2003-04-22 20:57   ` [RFC] Device class rework [2/5] Greg KH
@ 2003-04-22 20:58     ` Greg KH
  2003-04-22 20:59       ` [RFC] Device class rework [4/5] Greg KH
  0 siblings, 1 reply; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:58 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

On Tue, Apr 22, 2003 at 01:55:45PM -0700, Greg KH wrote:
>  - Crude patches to the scsi core to get it to build properly.  This
>    patch is not correct, but needed if your machines have scsi.  Mike
>    Anderson has said he will fix up the scsi code based on these core
>    changes.


diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Tue Apr 22 13:08:01 2003
+++ b/drivers/scsi/hosts.c	Tue Apr 22 13:08:01 2003
@@ -294,7 +294,7 @@
 			sht->info ? sht->info(shost) : sht->name);
 
 	if (dev) {
-		dev->class_data = shost;
+//		dev->class_data = shost;
 		shost->host_gendev = dev;
 	}
 
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Tue Apr 22 13:07:58 2003
+++ b/drivers/scsi/hosts.h	Tue Apr 22 13:07:58 2003
@@ -495,7 +495,8 @@
         __attribute__ ((aligned (sizeof(unsigned long))));
 };
 
-#define	to_scsi_host(d)	d->class_data
+//#define	to_scsi_host(d)	d->class_data
+#define	to_scsi_host(d)	d->driver_data	// Major breakage, but we compile now...
 	
 /*
  * These two functions are used to allocate and free a pseudo device
@@ -607,7 +608,7 @@
 extern int scsi_upper_driver_register(struct Scsi_Device_Template *);
 extern void scsi_upper_driver_unregister(struct Scsi_Device_Template *);
 
-extern struct device_class shost_devclass;
+extern struct class shost_devclass;
 
 #endif
 /*
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Tue Apr 22 13:07:57 2003
+++ b/drivers/scsi/scsi_debug.c	Tue Apr 22 13:07:57 2003
@@ -183,7 +183,7 @@
 	.name 		= sdebug_proc_name,
 	.probe          = sdebug_driver_probe,
 	.remove         = sdebug_driver_remove,
-	.devclass 	= &shost_devclass,
+//	.devclass 	= &shost_devclass,
 };
 
 static const int check_condition_result = 
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Tue Apr 22 13:08:01 2003
+++ b/drivers/scsi/scsi_sysfs.c	Tue Apr 22 13:08:01 2003
@@ -95,10 +95,8 @@
 	device_remove_file(dev, &dev_attr_class_name);
 }
 
-struct device_class shost_devclass = {
+struct class shost_devclass = {
 	.name		= "scsi-host",
-	.add_device	= scsi_host_class_add_dev,
-	.remove_device	= scsi_host_class_rm_dev,
 };
 
 /**
@@ -136,14 +134,14 @@
 int scsi_sysfs_register(void)
 {
 	bus_register(&scsi_bus_type);
-	devclass_register(&shost_devclass);
+	class_register(&shost_devclass);
 
 	return 0;
 }
 
 void scsi_sysfs_unregister(void)
 {
-	devclass_unregister(&shost_devclass);
+	class_unregister(&shost_devclass);
 	bus_unregister(&scsi_bus_type);
 }
 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC] Device class rework [4/5]
  2003-04-22 20:58     ` [RFC] Device class rework [3/5] Greg KH
@ 2003-04-22 20:59       ` Greg KH
  2003-04-22 20:59         ` [RFC] Device class rework [5/5] Greg KH
  0 siblings, 1 reply; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:59 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

On Tue, Apr 22, 2003 at 01:55:45PM -0700, Greg KH wrote:
>  - cpufreq changes.  This converts the cpufreq code to the new driver
>    class changes.


diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h	Tue Apr 22 13:07:50 2003
+++ b/include/linux/cpufreq.h	Tue Apr 22 13:07:50 2003
@@ -68,7 +68,6 @@
         unsigned int            policy; /* see above */
 	struct cpufreq_governor *governor; /* see below */
 	struct cpufreq_cpuinfo  cpuinfo;     /* see above */
-	struct device		* dev;
 	struct kobject		kobj;
  	struct semaphore	lock;   /* CPU ->setpolicy or ->target may
 					   only be called once a time */
diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c
--- a/kernel/cpufreq.c	Tue Apr 22 13:07:50 2003
+++ b/kernel/cpufreq.c	Tue Apr 22 13:07:50 2003
@@ -49,23 +49,17 @@
 static LIST_HEAD(cpufreq_governor_list);
 static DECLARE_MUTEX		(cpufreq_governor_sem);
 
-static struct device_interface cpufreq_interface;
+static struct class_interface cpufreq_interface;
 
 static int cpufreq_cpu_get(unsigned int cpu) {
 	if (cpu >= NR_CPUS)
 		return 0;
 
-	if (!kset_get(&cpufreq_interface.kset))
-		return 0;
-
-	if (!try_module_get(cpufreq_driver->owner)) {
-		kset_put(&cpufreq_interface.kset);
+	if (!try_module_get(cpufreq_driver->owner))
 		return 0;
-	}
 
 	if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) {
 		module_put(cpufreq_driver->owner);
-		kset_put(&cpufreq_interface.kset);
 		return 0;
 	}
 
@@ -75,7 +69,6 @@
 static void cpufreq_cpu_put(unsigned int cpu) {
 	kobject_put(&cpufreq_driver->policy[cpu].kobj);
 	module_put(cpufreq_driver->owner);
-	kset_put(&cpufreq_interface.kset);
 }
 
 /*********************************************************************
@@ -115,24 +108,20 @@
 
 
 /* forward declarations */
-static int cpufreq_add_dev (struct device * dev);
-static int cpufreq_remove_dev (struct device * dev);
+static int cpufreq_add_dev (struct class_device * dev);
+static int cpufreq_remove_dev (struct class_device * dev);
 
 /* drivers/base/cpu.c */
 extern struct device_class cpu_devclass;
 
-static struct device_interface cpufreq_interface = {
-        .name = "cpufreq",
-        .devclass = &cpu_devclass,
-        .add_device = &cpufreq_add_dev,
-        .remove_device = &cpufreq_remove_dev,
-	.kset = { .subsys = &cpu_devclass.subsys, },
-        .devnum = 0,
+static struct class_interface cpufreq_interface = {
+        .add =		&cpufreq_add_dev,
+        .remove =	&cpufreq_remove_dev,
 };
 
-static inline int to_cpu_nr (struct device *dev)
+static inline int to_cpu_nr (struct class_device *dev)
 {
-	struct sys_device * cpu_sys_dev = container_of(dev, struct sys_device, dev);
+	struct sys_device * cpu_sys_dev = container_of(dev->dev, struct sys_device, dev);
 	return (cpu_sys_dev->id);
 }
 
@@ -334,21 +323,16 @@
  *
  * Adds the cpufreq interface for a CPU device. 
  */
-static int cpufreq_add_dev (struct device * dev)
+static int cpufreq_add_dev (struct class_device * class_dev)
 {
-	unsigned int cpu = to_cpu_nr(dev);
+	unsigned int cpu = to_cpu_nr(class_dev);
 	int ret = 0;
 	struct cpufreq_policy new_policy;
 	struct cpufreq_policy *policy;
 	struct freq_attr **drv_attr;
 
-	if (!kset_get(&cpufreq_interface.kset))
-		return -EINVAL;
-
-	if (!try_module_get(cpufreq_driver->owner)) {
-		kset_put(&cpufreq_interface.kset);
+	if (!try_module_get(cpufreq_driver->owner))
 		return -EINVAL;
-	}
 
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
@@ -366,15 +350,15 @@
 	memcpy(&new_policy, 
 	       policy, 
 	       sizeof(struct cpufreq_policy));
+	class_set_devdata(class_dev, policy);
 	up(&cpufreq_driver_sem);
 
 	init_MUTEX(&policy->lock);
 	/* prepare interface data */
-	policy->kobj.parent = &dev->kobj;
+	policy->kobj.parent = &class_dev->kobj;
 	policy->kobj.ktype = &ktype_cpufreq;
-	policy->dev = dev;
-	strncpy(policy->kobj.name, 
-		cpufreq_interface.name, KOBJ_NAME_LEN);
+//	policy->dev = dev->dev;
+	strncpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
 
 	ret = kobject_register(&policy->kobj);
 	if (ret)
@@ -385,7 +369,9 @@
 		sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
 		drv_attr++;
 	}
+	/* set up files for this cpu device */
 
+	
 	/* set default policy */
 	ret = cpufreq_set_policy(&new_policy);
 	if (ret)
@@ -393,7 +379,6 @@
 
  out:
 	module_put(cpufreq_driver->owner);
-	kset_put(&cpufreq_interface.kset);
 	return ret;
 }
 
@@ -403,18 +388,13 @@
  *
  * Removes the cpufreq interface for a CPU device.
  */
-static int cpufreq_remove_dev (struct device * dev)
+static int cpufreq_remove_dev (struct class_device * class_dev)
 {
-	unsigned int cpu = to_cpu_nr(dev);
+	unsigned int cpu = to_cpu_nr(class_dev);
 
-	if (!kset_get(&cpufreq_interface.kset))
+	if (!kobject_get(&cpufreq_driver->policy[cpu].kobj))
 		return -EINVAL;
 
-	if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) {
-		kset_put(&cpufreq_interface.kset);
-		return -EINVAL;
-	}
-
 	down(&cpufreq_driver_sem);
 	if ((cpufreq_driver->target) && 
 	    (cpufreq_driver->policy[cpu].policy == CPUFREQ_POLICY_GOVERNOR)) {
@@ -433,7 +413,6 @@
 
 	up(&cpufreq_driver_sem);
 	kobject_put(&cpufreq_driver->policy[cpu].kobj);
-	kset_put(&cpufreq_interface.kset);
 	return 0;
 }
 
@@ -840,12 +819,6 @@
 	    ((!driver_data->setpolicy) && (!driver_data->target)))
 		return -EINVAL;
 
-
-	if (kset_get(&cpufreq_interface.kset)) {
-		kset_put(&cpufreq_interface.kset);
-		return -EBUSY;
-	}
-
 	down(&cpufreq_driver_sem);
 	if (cpufreq_driver) {
 		up(&cpufreq_driver_sem);		
@@ -862,7 +835,7 @@
 
 	memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy));
 
-	return interface_register(&cpufreq_interface);
+	return class_interface_register(&cpufreq_interface);
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
 
@@ -877,16 +850,10 @@
  */
 int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 {
-	if (!kset_get(&cpufreq_interface.kset))
-		return 0;
-
-	if (!cpufreq_driver || (driver != cpufreq_driver)) {
-		kset_put(&cpufreq_interface.kset);
+	if (!cpufreq_driver || (driver != cpufreq_driver))
 		return -EINVAL;
-	}
 
-	kset_put(&cpufreq_interface.kset);
-	interface_unregister(&cpufreq_interface);
+	class_interface_unregister(&cpufreq_interface);
 
 	down(&cpufreq_driver_sem);
 	kfree(cpufreq_driver->policy);
@@ -914,9 +881,6 @@
 	if (in_interrupt())
 		panic("cpufreq_restore() called from interrupt context!");
 
-	if (!kset_get(&cpufreq_interface.kset))
-		return 0;
-
 	if (!try_module_get(cpufreq_driver->owner))
 		goto error_out;
 
@@ -934,8 +898,6 @@
 
 	module_put(cpufreq_driver->owner);
  error_out:
-	kset_put(&cpufreq_interface.kset);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_restore);

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC] Device class rework [5/5]
  2003-04-22 20:59       ` [RFC] Device class rework [4/5] Greg KH
@ 2003-04-22 20:59         ` Greg KH
  0 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2003-04-22 20:59 UTC (permalink / raw)
  To: Patrick Mochel, linux-kernel; +Cc: hannal, andmike

On Tue, Apr 22, 2003 at 01:55:45PM -0700, Greg KH wrote:
>  - tty changes.  This converts the tty code to the new driver class
>    changes.  With this patch, we now show all tty devices, and their
>    device major/minor number in the /sys/class/tty/ directory.  Yes,
>    this is still a bit crude (all ptys are shown, and they should not
>    be), but it's an example of why these changes are needed, and how
>    to
>    add class support to a subsystem.  I'll rework this after
>    Christoph's
>    and Al Viro's tty changes are in the main tree, as we all are
>    touching the same part of code.



diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Tue Apr 22 13:07:51 2003
+++ b/drivers/char/tty_io.c	Tue Apr 22 13:07:51 2003
@@ -2133,18 +2133,94 @@
 # define tty_register_devfs(driver, minor)	do { } while (0)
 # define tty_unregister_devfs(driver, minor)	do { } while (0)
 #endif /* CONFIG_DEVFS_FS */
+static struct class tty_class = {
+	.name	= "tty",
+};
+
+struct tty_dev {
+	struct list_head node;
+	struct tty_driver *driver;
+	unsigned minor;
+	struct class_device class_dev;
+};
+#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev)
+
+static LIST_HEAD(tty_dev_list);
+
+static ssize_t show_dev (struct class_device *class_dev, char *buf)
+{
+	struct tty_dev *tty_dev = to_tty_dev(class_dev);
+	dev_t base;
+
+	base = MKDEV(tty_dev->driver->major, tty_dev->minor);
+	return sprintf(buf, "%04x\n", base);
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 
 /*
  * Register a tty device described by <driver>, with minor number <minor>.
  */
-void tty_register_device(struct tty_driver *driver, unsigned minor)
+void tty_register_device (struct tty_driver *driver, unsigned minor, struct device *dev)
 {
+	struct tty_dev *tty_dev = NULL;
+	char *name = NULL;
+	char *temp;
+	int retval;
+
 	tty_register_devfs(driver, minor);
+
+	tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL);
+	if (!tty_dev)
+		return;
+	memset(tty_dev, 0x00, sizeof(*tty_dev));
+	name = kmalloc(DEVICE_NAME_SIZE, GFP_KERNEL);
+	if (!name)
+		goto error;
+
+	/* stupid '%' in tty name strings... */
+	strncpy(name, driver->name, DEVICE_NAME_SIZE);
+	temp = strchr(name, '%');
+	if (temp)
+		*temp = 0x00;
+
+	tty_dev->class_dev.dev = dev;
+	tty_dev->class_dev.class = &tty_class;
+	snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s%d", name,
+		 minor - driver->minor_start);
+	retval = class_device_register(&tty_dev->class_dev);
+	if (retval)
+		goto error;
+	class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev);
+	tty_dev->driver = driver;
+	tty_dev->minor = minor;
+	list_add(&tty_dev->node, &tty_dev_list);
+	return;
+error:
+	kfree(name);
+	kfree(tty_dev);
 }
 
 void tty_unregister_device(struct tty_driver *driver, unsigned minor)
 {
+	struct tty_dev *tty_dev = NULL;
+	struct list_head *tmp;
+	int found = 0;
+
 	tty_unregister_devfs(driver, minor);
+
+	list_for_each (tmp, &tty_dev_list) {
+		tty_dev = list_entry(tmp, struct tty_dev, node);
+		if ((tty_dev->driver == driver) &&
+		    (tty_dev->minor == minor)) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		list_del(&tty_dev->node);
+		class_device_unregister(&tty_dev->class_dev);
+		kfree(tty_dev);
+	}
 }
 
 EXPORT_SYMBOL(tty_register_device);
@@ -2175,7 +2251,7 @@
 	
 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
 		for(i = 0; i < driver->num; i++)
-		    tty_register_device(driver, driver->minor_start + i);
+		    tty_register_device(driver, driver->minor_start + i, NULL);
 	}
 	proc_tty_register_driver(driver);
 	return error;
@@ -2263,14 +2339,9 @@
 extern int vty_init(void);
 #endif
 
-struct device_class tty_devclass = {
-	.name	= "tty",
-};
-EXPORT_SYMBOL(tty_devclass);
-
 static int __init tty_devclass_init(void)
 {
-	return devclass_register(&tty_devclass);
+	return class_register(&tty_class);
 }
 
 postcore_initcall(tty_devclass_init);
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Tue Apr 22 13:07:51 2003
+++ b/drivers/char/vt.c	Tue Apr 22 13:07:51 2003
@@ -2665,7 +2665,7 @@
 
 	for (i = 0; i < console_driver.num; i++)
 		tty_register_device (&console_driver,
-				    console_driver.minor_start + i);
+				    console_driver.minor_start + i, NULL);
 }
 
 /*
diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
--- a/drivers/serial/8250_pci.c	Tue Apr 22 13:08:02 2003
+++ b/drivers/serial/8250_pci.c	Tue Apr 22 13:08:02 2003
@@ -2043,9 +2043,6 @@
 	.suspend	= pciserial_suspend_one,
 	.resume		= pciserial_resume_one,
 	.id_table	= serial_pci_tbl,
-	.driver = {
-		.devclass = &tty_devclass,
-	},
 };
 
 static int __init serial8250_pci_init(void)
diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c
--- a/drivers/serial/core.c	Tue Apr 22 13:07:50 2003
+++ b/drivers/serial/core.c	Tue Apr 22 13:07:50 2003
@@ -2231,7 +2231,7 @@
 	 * Register the port whether it's detected or not.  This allows
 	 * setserial to be used to alter this ports parameters.
 	 */
-	tty_register_device(drv->tty_driver, drv->minor + port->line);
+	tty_register_device(drv->tty_driver, drv->minor + port->line, NULL);
 
  out:
 	up(&port_sem);
diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Tue Apr 22 13:07:53 2003
+++ b/drivers/usb/class/bluetty.c	Tue Apr 22 13:07:53 2003
@@ -1198,7 +1198,7 @@
 		     bluetooth, endpoint->bInterval);
 
 	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
-	tty_register_device (&bluetooth_tty_driver, minor);
+	tty_register_device (&bluetooth_tty_driver, minor, &intf->dev);
 	info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor);
 
 	bluetooth_table[minor] = bluetooth;
diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c	Tue Apr 22 13:08:03 2003
+++ b/drivers/usb/class/cdc-acm.c	Tue Apr 22 13:08:03 2003
@@ -649,7 +649,7 @@
 		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
 		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
 
-		tty_register_device(&acm_tty_driver, minor);
+		tty_register_device(&acm_tty_driver, minor, &intf->dev);
 
 		acm_table[minor] = acm;
 		usb_set_intfdata (intf, acm);
diff -Nru a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
--- a/drivers/usb/serial/bus.c	Tue Apr 22 13:07:48 2003
+++ b/drivers/usb/serial/bus.c	Tue Apr 22 13:07:48 2003
@@ -23,18 +23,6 @@
 
 #include "usb-serial.h"
 
-static ssize_t show_dev (struct device *dev, char *buf)
-{
-	struct usb_serial_port *port= to_usb_serial_port(dev);
-	dev_t base;
-
-	port = to_usb_serial_port(dev);
-
-	base = MKDEV(SERIAL_TTY_MAJOR, port->number);
-	return sprintf(buf, "%04x\n", base);
-}
-static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-
 static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
 {
 	struct usb_serial_device_type *driver;
@@ -88,10 +76,7 @@
 	}
 
 	minor = port->number;
-
-	tty_register_device (&usb_serial_tty_driver, minor);
-	device_create_file (dev, &dev_attr_dev);
-
+	tty_register_device (&usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
 		 "%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n",
 		 driver->name, minor, minor);
@@ -142,7 +127,6 @@
 	device->driver.bus = &usb_serial_bus_type;
 	device->driver.probe = usb_serial_device_probe;
 	device->driver.remove = usb_serial_device_remove;
-	device->driver.devclass = &tty_devclass;
 
 	retval = driver_register(&device->driver);
 
diff -Nru a/include/linux/tty.h b/include/linux/tty.h
--- a/include/linux/tty.h	Tue Apr 22 13:07:48 2003
+++ b/include/linux/tty.h	Tue Apr 22 13:07:48 2003
@@ -243,6 +243,7 @@
 #define L_PENDIN(tty)	_L_FLAG((tty),PENDIN)
 #define L_IEXTEN(tty)	_L_FLAG((tty),IEXTEN)
 
+struct device;
 /*
  * Where all of the state associated with a tty is kept while the tty
  * is open.  Since the termios state should be kept even if the tty
@@ -378,7 +379,7 @@
 extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
-extern void tty_register_device(struct tty_driver *driver, unsigned minor);
+extern void tty_register_device(struct tty_driver *driver, unsigned minor, struct device *dev);
 extern void tty_unregister_device(struct tty_driver *driver, unsigned minor);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 			     int buflen);
diff -Nru a/include/linux/tty_driver.h b/include/linux/tty_driver.h
--- a/include/linux/tty_driver.h	Tue Apr 22 13:07:53 2003
+++ b/include/linux/tty_driver.h	Tue Apr 22 13:07:53 2003
@@ -231,6 +231,4 @@
 #define SERIAL_TYPE_NORMAL	1
 #define SERIAL_TYPE_CALLOUT	2
 
-extern struct device_class tty_devclass;
-
 #endif /* #ifdef _LINUX_TTY_DRIVER_H */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] Device class rework [0/5]
  2003-04-22 20:55 [RFC] Device class rework [0/5] Greg KH
  2003-04-22 20:57 ` [RFC] Device class rework [1/5] Greg KH
@ 2003-04-23  0:59 ` Hanna Linder
  2003-04-23  1:54   ` Greg KH
  1 sibling, 1 reply; 11+ messages in thread
From: Hanna Linder @ 2003-04-23  0:59 UTC (permalink / raw)
  To: Greg KH; +Cc: Patrick Mochel, linux-kernel, hannal, andmike

--On Tuesday, April 22, 2003 01:55:45 PM -0700 Greg KH <greg@kroah.com> wrote:

> Hi,
> 
> Here's a set of patches that rework the current class support in the
> kernel today into something that works a bit better, and is simpler to
> use.

Greg,

I did a quick sanity test of these patches on a 2-way PIII.
It built and booted fine for me. I don't have any devices that 
span multiple classes but the patch hasnt changed any of my 
existing /sys/class output.

Hanna
---

[root@w-hlinder2 root]# tree /sys/class
/sys/class
|-- cpu
|   |-- devices
|   |   |-- 0 -> ../../../devices/sys/cpu0
|   |   `-- 1 -> ../../../devices/sys/cpu1
|   `-- drivers
|       `-- system:cpu -> ../../../bus/system/drivers/cpu
|-- input
|   |-- devices
|   |   |-- 0 -> ../../../devices/pci0/00:0f.2/usb1/1-1/1-1.1/1-1.1:0
|   |   |-- 1 -> ../../../devices/pci0/00:0f.2/usb1/1-1/1-1.1/1-1.1:1
|   |   `-- 2 -> ../../../devices/pci0/00:0f.2/usb1/1-1/1-1.2/1-1.2:0
|   |-- drivers
|   |   `-- usb:hid -> ../../../bus/usb/drivers/hid
|   `-- mouse
|-- pcmcia_socket
|   |-- devices
|   |-- drivers
|   `-- pcmcia-bus
|-- scsi-host
|   |-- devices
|   `-- drivers
`-- tty
    |-- devices
    `-- drivers
        `-- pci:serial -> ../../../bus/pci/drivers/serial

25 directories, 0 files




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] Device class rework [0/5]
  2003-04-23  0:59 ` [RFC] Device class rework [0/5] Hanna Linder
@ 2003-04-23  1:54   ` Greg KH
  2003-04-23 16:18     ` Hanna Linder
  0 siblings, 1 reply; 11+ messages in thread
From: Greg KH @ 2003-04-23  1:54 UTC (permalink / raw)
  To: Hanna Linder; +Cc: Patrick Mochel, linux-kernel, andmike

On Tue, Apr 22, 2003 at 05:59:43PM -0700, Hanna Linder wrote:
> --On Tuesday, April 22, 2003 01:55:45 PM -0700 Greg KH <greg@kroah.com> wrote:
> 
> > Here's a set of patches that rework the current class support in the
> > kernel today into something that works a bit better, and is simpler to
> > use.
> 
> I did a quick sanity test of these patches on a 2-way PIII.
> It built and booted fine for me. I don't have any devices that 
> span multiple classes but the patch hasnt changed any of my 
> existing /sys/class output.

Hm, are you sure you applied them and are using that kernel?  :)

/sys/class should look something like this:

$ tree /sys/class/
/sys/class/
|-- cpu
|   `-- cpu0
|       |-- device -> ../../../devices/sys/cpu0
|       `-- foo
|-- input
`-- tty
    |-- console0
    |   `-- dev
    |-- ptmx0
    |   `-- dev
    |-- pts0
    |   `-- dev
    |-- pts1
    |   `-- dev
    |-- pts2
    |   `-- dev
    |-- pts3
    |   `-- dev
    |-- pts4
    |   `-- dev
    |-- pts5
    |   `-- dev
    |-- pts6
    |   `-- dev
    |-- pts7
    |   `-- dev
    |-- pty0
    |   `-- dev
    |-- pty1
    |   `-- dev
... and so on...


thanks,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] Device class rework [0/5]
  2003-04-23  1:54   ` Greg KH
@ 2003-04-23 16:18     ` Hanna Linder
  2003-04-23 16:23       ` Greg KH
  0 siblings, 1 reply; 11+ messages in thread
From: Hanna Linder @ 2003-04-23 16:18 UTC (permalink / raw)
  To: Greg KH; +Cc: Hanna Linder, Patrick Mochel, linux-kernel, andmike

--On Tuesday, April 22, 2003 06:54:54 PM -0700 Greg KH <greg@kroah.com> wrote:

>> I did a quick sanity test of these patches on a 2-way PIII.
>> It built and booted fine for me. I don't have any devices that 
>> span multiple classes but the patch hasnt changed any of my 
>> existing /sys/class output.
> 
> Hm, are you sure you applied them and are using that kernel?  :)
> 

Yes. I did apply the patches... Just not to the kernel I booted ;(

Here is the correct tree I see on my 2xPIII:


/sys/class
|-- cpu
|   |-- cpu0
|   |   `-- device -> ../../../devices/sys/cpu0
|   `-- cpu1
|       `-- device -> ../../../devices/sys/cpu1
|-- input
|-- scsi-host
`-- tty
    |-- console0
    |   `-- dev
    |-- ptmx0
    |   `-- dev
    |-- pty0
    |   `-- dev
    |-- pty1
    |   `-- dev
    |-- pty10
    |   `-- dev
    |-- pty100
    |   `-- dev
    |-- pty101
    |   `-- dev
    |-- pty102
    |   `-- dev
    |-- pty103
    |   `-- dev
    |-- pty104
    |   `-- dev
    |-- pty105
    |   `-- dev
    |-- pty106
    |   `-- dev
    |-- pty107
    |   `-- dev
    |-- pty108
    |   `-- dev



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] Device class rework [0/5]
  2003-04-23 16:18     ` Hanna Linder
@ 2003-04-23 16:23       ` Greg KH
  0 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2003-04-23 16:23 UTC (permalink / raw)
  To: Hanna Linder; +Cc: Patrick Mochel, linux-kernel, andmike

On Wed, Apr 23, 2003 at 09:18:08AM -0700, Hanna Linder wrote:
> --On Tuesday, April 22, 2003 06:54:54 PM -0700 Greg KH <greg@kroah.com> wrote:
> 
> >> I did a quick sanity test of these patches on a 2-way PIII.
> >> It built and booted fine for me. I don't have any devices that 
> >> span multiple classes but the patch hasnt changed any of my 
> >> existing /sys/class output.
> > 
> > Hm, are you sure you applied them and are using that kernel?  :)
> > 
> 
> Yes. I did apply the patches... Just not to the kernel I booted ;(
> 
> Here is the correct tree I see on my 2xPIII:
> 
> 
> /sys/class
> |-- cpu
> |   |-- cpu0
> |   |   `-- device -> ../../../devices/sys/cpu0
> |   `-- cpu1
> |       `-- device -> ../../../devices/sys/cpu1

Looks good.  That "foo" file in the example I posted was from an older
kernel version on one of my boxes.  This is the correct information.

Thanks for testing,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] Device class rework [0/5]
  2003-04-23  7:54 Shaheed R. Haque
@ 2003-04-23 16:00 ` Greg KH
  0 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2003-04-23 16:00 UTC (permalink / raw)
  To: Shaheed R. Haque; +Cc: linux-kernel, with

On Wed, Apr 23, 2003 at 08:54:04AM +0100, Shaheed R. Haque wrote:
> 
> Hi Greg,
> 
> I support the intent of this patch, but would it not be a better idea to rename 
> the struct something like "device_class"? Rationale:

Ok, if I do that, and that was what I originally did, then we end up
with:
	struct device_class;
	struct device_class_device;
	struct device_class_interface;

Um, I don't think "struct device_class_device" is going to be
acceptable...

So I talked to a lot of people, explaining what the structures were, and
what they did, and in the end everyone agreed that dropping the
beginning "device_" is probably the best.

Well, not everyone agreed, but they couldn't come up with a better name,
so I took that as agreement :)

> 2. The word "class" is too generic and conveys no sense that is is to do with 
> devices.

In a way, it is generic.  It doesn't have to refer to a device (if the
pointer to struct device is NULL, then you don't get the "device"
symlink for free, that's it.)  So we can now move block "devices", which
includes partitions, into this model, and also network "devices" if we
want too.  Oh, how about filesystems, they also fit nicely into this
model, and aren't really a "device" at all...

> 3. I know that C++ is never going to make it into the kernel, but...

I know, I'm a stinker, but I honestly couldn't think of a better name,
and am open to ideas from everyone else.

And, I like the way my editor highlights the code, "struct class"...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2003-04-23 16:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-04-22 20:55 [RFC] Device class rework [0/5] Greg KH
2003-04-22 20:57 ` [RFC] Device class rework [1/5] Greg KH
2003-04-22 20:57   ` [RFC] Device class rework [2/5] Greg KH
2003-04-22 20:58     ` [RFC] Device class rework [3/5] Greg KH
2003-04-22 20:59       ` [RFC] Device class rework [4/5] Greg KH
2003-04-22 20:59         ` [RFC] Device class rework [5/5] Greg KH
2003-04-23  0:59 ` [RFC] Device class rework [0/5] Hanna Linder
2003-04-23  1:54   ` Greg KH
2003-04-23 16:18     ` Hanna Linder
2003-04-23 16:23       ` Greg KH
2003-04-23  7:54 Shaheed R. Haque
2003-04-23 16:00 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).