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