Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 10548
b: refs/heads/master
c: 51d172d
h: refs/heads/master
v: v3
  • Loading branch information
Greg Kroah-Hartman committed Oct 28, 2005
1 parent ea8d7f0 commit 7cb8345
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 48 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a7fd67062efc5b0fc9a61368c607fa92d1d57f9e
refs/heads/master: 51d172d5f3a193e4b8f76179b2e55d7a36b94117
125 changes: 81 additions & 44 deletions trunk/drivers/base/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ struct class * class_get(struct class * cls)

void class_put(struct class * cls)
{
subsys_put(&cls->subsys);
if (cls)
subsys_put(&cls->subsys);
}


Expand Down Expand Up @@ -165,14 +166,25 @@ void class_unregister(struct class * cls)

static void class_create_release(struct class *cls)
{
pr_debug("%s called for %s\n", __FUNCTION__, cls->name);
kfree(cls);
}

static void class_device_create_release(struct class_device *class_dev)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
kfree(class_dev);
}

/* needed to allow these devices to have parent class devices */
static int class_device_create_hotplug(struct class_device *class_dev,
char **envp, int num_envp,
char *buffer, int buffer_size)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
return 0;
}

/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
Expand Down Expand Up @@ -301,10 +313,12 @@ static void class_dev_release(struct kobject * kobj)
kfree(cd->devt_attr);
cd->devt_attr = NULL;

if (cls->release)
if (cd->release)
cd->release(cd);
else if (cls->release)
cls->release(cd);
else {
printk(KERN_ERR "Device class '%s' does not have a release() function, "
printk(KERN_ERR "Class Device '%s' does not have a release() function, "
"it is broken and must be fixed.\n",
cd->class_id);
WARN_ON(1);
Expand Down Expand Up @@ -382,14 +396,18 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
buffer = &buffer[length];
buffer_size -= length;

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);
}
if (class_dev->hotplug) {
/* have the class device specific function add its stuff */
retval = class_dev->hotplug(class_dev, envp, num_envp,
buffer, buffer_size);
if (retval)
pr_debug("class_dev->hotplug() returned %d\n", retval);
} else if (class_dev->class->hotplug) {
/* have the class specific function add its stuff */
retval = class_dev->class->hotplug(class_dev, envp, num_envp,
buffer, buffer_size);
if (retval)
pr_debug("class->hotplug() returned %d\n", retval);
}

return retval;
Expand Down Expand Up @@ -476,37 +494,42 @@ static char *make_class_name(struct class_device *class_dev)

int class_device_add(struct class_device *class_dev)
{
struct class * parent = NULL;
struct class_interface * class_intf;
struct class *parent_class = NULL;
struct class_device *parent_class_dev = NULL;
struct class_interface *class_intf;
char *class_name = NULL;
int error;
int error = -EINVAL;

class_dev = class_device_get(class_dev);
if (!class_dev)
return -EINVAL;

if (!strlen(class_dev->class_id)) {
error = -EINVAL;
if (!strlen(class_dev->class_id))
goto register_done;
}

parent = class_get(class_dev->class);
parent_class = class_get(class_dev->class);
if (!parent_class)
goto register_done;
parent_class_dev = class_device_get(class_dev->parent);

pr_debug("CLASS: registering class device: ID = '%s'\n",
class_dev->class_id);

/* first, register with generic layer. */
kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
if (parent)
class_dev->kobj.parent = &parent->subsys.kset.kobj;
if (parent_class_dev)
class_dev->kobj.parent = &parent_class_dev->kobj;
else
class_dev->kobj.parent = &parent_class->subsys.kset.kobj;

if ((error = kobject_add(&class_dev->kobj)))
error = kobject_add(&class_dev->kobj);
if (error)
goto register_done;

/* add the needed attributes to this device */
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent->owner;
class_dev->uevent_attr.attr.owner = parent_class->owner;
class_dev->uevent_attr.store = store_uevent;
class_device_create_file(class_dev, &class_dev->uevent_attr);

Expand All @@ -520,7 +543,7 @@ int class_device_add(struct class_device *class_dev)
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
attr->attr.owner = parent->owner;
attr->attr.owner = parent_class->owner;
attr->show = show_dev;
class_device_create_file(class_dev, attr);
class_dev->devt_attr = attr;
Expand All @@ -538,18 +561,20 @@ int class_device_add(struct class_device *class_dev)
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);

/* notify any interfaces this device is now here */
if (parent) {
down(&parent->sem);
list_add_tail(&class_dev->node, &parent->children);
list_for_each_entry(class_intf, &parent->interfaces, node)
if (parent_class) {
down(&parent_class->sem);
list_add_tail(&class_dev->node, &parent_class->children);
list_for_each_entry(class_intf, &parent_class->interfaces, node)
if (class_intf->add)
class_intf->add(class_dev, class_intf);
up(&parent->sem);
up(&parent_class->sem);
}

register_done:
if (error && parent)
class_put(parent);
if (error) {
class_put(parent_class);
class_device_put(parent_class_dev);
}
class_device_put(class_dev);
kfree(class_name);
return error;
Expand All @@ -564,21 +589,28 @@ int class_device_register(struct class_device *class_dev)
/**
* class_device_create - creates a class device and registers it with sysfs
* @cs: pointer to the struct class that this device should be registered to.
* @parent: pointer to the parent struct class_device of this new device, if any.
* @dev: the dev_t for the char device to be added.
* @device: a pointer to a struct device that is assiociated with this class device.
* @fmt: string for the class device's name
*
* This function can be used by char device classes. A struct
* class_device will be created in sysfs, registered to the specified
* class. A "dev" file will be created, showing the dev_t for the
* device. The pointer to the struct class_device will be returned from
* the call. Any further sysfs files that might be required can be
* created using this pointer.
* class.
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct class_device is passed in, the newly
* created struct class_device will be a child of that device in sysfs.
* The pointer to the struct class_device will be returned from the
* call. Any further sysfs files that might be required can be created
* using this pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
struct class_device *class_device_create(struct class *cls, dev_t devt,
struct class_device *class_device_create(struct class *cls,
struct class_device *parent,
dev_t devt,
struct device *device, char *fmt, ...)
{
va_list args;
Expand All @@ -597,6 +629,9 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,
class_dev->devt = devt;
class_dev->dev = device;
class_dev->class = cls;
class_dev->parent = parent;
class_dev->release = class_device_create_release;
class_dev->hotplug = class_device_create_hotplug;

va_start(args, fmt);
vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
Expand All @@ -614,17 +649,18 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,

void class_device_del(struct class_device *class_dev)
{
struct class * parent = class_dev->class;
struct class_interface * class_intf;
struct class *parent_class = class_dev->class;
struct class_device *parent_device = class_dev->parent;
struct class_interface *class_intf;
char *class_name = NULL;

if (parent) {
down(&parent->sem);
if (parent_class) {
down(&parent_class->sem);
list_del_init(&class_dev->node);
list_for_each_entry(class_intf, &parent->interfaces, node)
list_for_each_entry(class_intf, &parent_class->interfaces, node)
if (class_intf->remove)
class_intf->remove(class_dev, class_intf);
up(&parent->sem);
up(&parent_class->sem);
}

if (class_dev->dev) {
Expand All @@ -640,8 +676,8 @@ void class_device_del(struct class_device *class_dev)
kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
kobject_del(&class_dev->kobj);

if (parent)
class_put(parent);
class_device_put(parent_device);
class_put(parent_class);
kfree(class_name);
}

Expand Down Expand Up @@ -721,7 +757,8 @@ struct class_device * class_device_get(struct class_device *class_dev)

void class_device_put(struct class_device *class_dev)
{
kobject_put(&class_dev->kobj);
if (class_dev)
kobject_put(&class_dev->kobj);
}


Expand Down
13 changes: 10 additions & 3 deletions trunk/include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,11 @@ struct class_device {
struct class_device_attribute uevent_attr;
struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */
struct class_device *parent; /* parent of this child device, if there is one */

void (*release)(struct class_device *dev);
int (*hotplug)(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
char class_id[BUS_ID_SIZE]; /* unique to this class */
};

Expand Down Expand Up @@ -261,9 +265,12 @@ extern void class_interface_unregister(struct class_interface *);

extern struct class *class_create(struct module *owner, char *name);
extern void class_destroy(struct class *cls);
extern struct class_device *class_device_create(struct class *cls, dev_t devt,
struct device *device, char *fmt, ...)
__attribute__((format(printf,4,5)));
extern struct class_device *class_device_create(struct class *cls,
struct class_device *parent,
dev_t devt,
struct device *device,
char *fmt, ...)
__attribute__((format(printf,5,6)));
extern void class_device_destroy(struct class *cls, dev_t devt);


Expand Down

0 comments on commit 7cb8345

Please sign in to comment.