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 #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 -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 -#include -#include -#include -#include -#include -#include -#include - -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 -#include -#include -#include -#include -#include -#include -#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 -#include -#include -#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 -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 -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 + * Copyright (c) 2001-2003 Patrick Mochel * * 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 *);