aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/class.c145
-rw-r--r--include/linux/device.h9
2 files changed, 143 insertions, 11 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 344b8cd73901..a3b006b6f2ba 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -16,6 +16,7 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/string.h> 17#include <linux/string.h>
18#include <linux/kdev_t.h> 18#include <linux/kdev_t.h>
19#include <linux/err.h>
19#include "base.h" 20#include "base.h"
20 21
21#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) 22#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
@@ -162,6 +163,51 @@ void class_unregister(struct class * cls)
162 subsystem_unregister(&cls->subsys); 163 subsystem_unregister(&cls->subsys);
163} 164}
164 165
166static void class_create_release(struct class *cls)
167{
168 kfree(cls);
169}
170
171static void class_device_create_release(struct class_device *class_dev)
172{
173 kfree(class_dev);
174}
175
176struct class *class_create(struct module *owner, char *name)
177{
178 struct class *cls;
179 int retval;
180
181 cls = kmalloc(sizeof(struct class), GFP_KERNEL);
182 if (!cls) {
183 retval = -ENOMEM;
184 goto error;
185 }
186 memset(cls, 0x00, sizeof(struct class));
187
188 cls->name = name;
189 cls->owner = owner;
190 cls->class_release = class_create_release;
191 cls->release = class_device_create_release;
192
193 retval = class_register(cls);
194 if (retval)
195 goto error;
196
197 return cls;
198
199error:
200 kfree(cls);
201 return ERR_PTR(retval);
202}
203
204void class_destroy(struct class *cls)
205{
206 if ((cls == NULL) || (IS_ERR(cls)))
207 return;
208
209 class_unregister(cls);
210}
165 211
166/* Class Device Stuff */ 212/* Class Device Stuff */
167 213
@@ -375,7 +421,6 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
375{ 421{
376 return print_dev_t(buf, class_dev->devt); 422 return print_dev_t(buf, class_dev->devt);
377} 423}
378static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
379 424
380void class_device_initialize(struct class_device *class_dev) 425void class_device_initialize(struct class_device *class_dev)
381{ 426{
@@ -412,7 +457,31 @@ int class_device_add(struct class_device *class_dev)
412 if ((error = kobject_add(&class_dev->kobj))) 457 if ((error = kobject_add(&class_dev->kobj)))
413 goto register_done; 458 goto register_done;
414 459
415 /* now take care of our own registration */ 460 /* add the needed attributes to this device */
461 if (MAJOR(class_dev->devt)) {
462 struct class_device_attribute *attr;
463 attr = kmalloc(sizeof(*attr), GFP_KERNEL);
464 if (!attr) {
465 error = -ENOMEM;
466 kobject_del(&class_dev->kobj);
467 goto register_done;
468 }
469 memset(attr, sizeof(*attr), 0x00);
470 attr->attr.name = "dev";
471 attr->attr.mode = S_IRUGO;
472 attr->attr.owner = parent->owner;
473 attr->show = show_dev;
474 attr->store = NULL;
475 class_device_create_file(class_dev, attr);
476 class_dev->devt_attr = attr;
477 }
478
479 class_device_add_attrs(class_dev);
480 if (class_dev->dev)
481 sysfs_create_link(&class_dev->kobj,
482 &class_dev->dev->kobj, "device");
483
484 /* notify any interfaces this device is now here */
416 if (parent) { 485 if (parent) {
417 down(&parent->sem); 486 down(&parent->sem);
418 list_add_tail(&class_dev->node, &parent->children); 487 list_add_tail(&class_dev->node, &parent->children);
@@ -421,16 +490,8 @@ int class_device_add(struct class_device *class_dev)
421 class_intf->add(class_dev); 490 class_intf->add(class_dev);
422 up(&parent->sem); 491 up(&parent->sem);
423 } 492 }
424
425 if (MAJOR(class_dev->devt))
426 class_device_create_file(class_dev, &class_device_attr_dev);
427
428 class_device_add_attrs(class_dev);
429 if (class_dev->dev)
430 sysfs_create_link(&class_dev->kobj,
431 &class_dev->dev->kobj, "device");
432
433 kobject_hotplug(&class_dev->kobj, KOBJ_ADD); 493 kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
494
434 register_done: 495 register_done:
435 if (error && parent) 496 if (error && parent)
436 class_put(parent); 497 class_put(parent);
@@ -444,6 +505,41 @@ int class_device_register(struct class_device *class_dev)
444 return class_device_add(class_dev); 505 return class_device_add(class_dev);
445} 506}
446 507
508struct class_device *class_device_create(struct class *cls, dev_t devt,
509 struct device *device, char *fmt, ...)
510{
511 va_list args;
512 struct class_device *class_dev = NULL;
513 int retval = -ENODEV;
514
515 if (cls == NULL || IS_ERR(cls))
516 goto error;
517
518 class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
519 if (!class_dev) {
520 retval = -ENOMEM;
521 goto error;
522 }
523 memset(class_dev, 0x00, sizeof(struct class_device));
524
525 class_dev->devt = devt;
526 class_dev->dev = device;
527 class_dev->class = cls;
528
529 va_start(args, fmt);
530 vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
531 va_end(args);
532 retval = class_device_register(class_dev);
533 if (retval)
534 goto error;
535
536 return class_dev;
537
538error:
539 kfree(class_dev);
540 return ERR_PTR(retval);
541}
542
447void class_device_del(struct class_device *class_dev) 543void class_device_del(struct class_device *class_dev)
448{ 544{
449 struct class * parent = class_dev->class; 545 struct class * parent = class_dev->class;
@@ -460,6 +556,11 @@ void class_device_del(struct class_device *class_dev)
460 556
461 if (class_dev->dev) 557 if (class_dev->dev)
462 sysfs_remove_link(&class_dev->kobj, "device"); 558 sysfs_remove_link(&class_dev->kobj, "device");
559 if (class_dev->devt_attr) {
560 class_device_remove_file(class_dev, class_dev->devt_attr);
561 kfree(class_dev->devt_attr);
562 class_dev->devt_attr = NULL;
563 }
463 class_device_remove_attrs(class_dev); 564 class_device_remove_attrs(class_dev);
464 565
465 kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE); 566 kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
@@ -477,6 +578,24 @@ void class_device_unregister(struct class_device *class_dev)
477 class_device_put(class_dev); 578 class_device_put(class_dev);
478} 579}
479 580
581void class_device_destroy(struct class *cls, dev_t devt)
582{
583 struct class_device *class_dev = NULL;
584 struct class_device *class_dev_tmp;
585
586 down(&cls->sem);
587 list_for_each_entry(class_dev_tmp, &cls->children, node) {
588 if (class_dev_tmp->devt == devt) {
589 class_dev = class_dev_tmp;
590 break;
591 }
592 }
593 up(&cls->sem);
594
595 if (class_dev)
596 class_device_unregister(class_dev);
597}
598
480int class_device_rename(struct class_device *class_dev, char *new_name) 599int class_device_rename(struct class_device *class_dev, char *new_name)
481{ 600{
482 int error = 0; 601 int error = 0;
@@ -576,6 +695,8 @@ EXPORT_SYMBOL_GPL(class_register);
576EXPORT_SYMBOL_GPL(class_unregister); 695EXPORT_SYMBOL_GPL(class_unregister);
577EXPORT_SYMBOL_GPL(class_get); 696EXPORT_SYMBOL_GPL(class_get);
578EXPORT_SYMBOL_GPL(class_put); 697EXPORT_SYMBOL_GPL(class_put);
698EXPORT_SYMBOL_GPL(class_create);
699EXPORT_SYMBOL_GPL(class_destroy);
579 700
580EXPORT_SYMBOL_GPL(class_device_register); 701EXPORT_SYMBOL_GPL(class_device_register);
581EXPORT_SYMBOL_GPL(class_device_unregister); 702EXPORT_SYMBOL_GPL(class_device_unregister);
@@ -584,6 +705,8 @@ EXPORT_SYMBOL_GPL(class_device_add);
584EXPORT_SYMBOL_GPL(class_device_del); 705EXPORT_SYMBOL_GPL(class_device_del);
585EXPORT_SYMBOL_GPL(class_device_get); 706EXPORT_SYMBOL_GPL(class_device_get);
586EXPORT_SYMBOL_GPL(class_device_put); 707EXPORT_SYMBOL_GPL(class_device_put);
708EXPORT_SYMBOL_GPL(class_device_create);
709EXPORT_SYMBOL_GPL(class_device_destroy);
587EXPORT_SYMBOL_GPL(class_device_create_file); 710EXPORT_SYMBOL_GPL(class_device_create_file);
588EXPORT_SYMBOL_GPL(class_device_remove_file); 711EXPORT_SYMBOL_GPL(class_device_remove_file);
589EXPORT_SYMBOL_GPL(class_device_create_bin_file); 712EXPORT_SYMBOL_GPL(class_device_create_bin_file);
diff --git a/include/linux/device.h b/include/linux/device.h
index fa9e6ca08f5a..73250d01c01f 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -143,6 +143,7 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
143 */ 143 */
144struct class { 144struct class {
145 const char * name; 145 const char * name;
146 struct module * owner;
146 147
147 struct subsystem subsys; 148 struct subsystem subsys;
148 struct list_head children; 149 struct list_head children;
@@ -185,6 +186,7 @@ struct class_device {
185 struct kobject kobj; 186 struct kobject kobj;
186 struct class * class; /* required */ 187 struct class * class; /* required */
187 dev_t devt; /* dev_t, creates the sysfs "dev" */ 188 dev_t devt; /* dev_t, creates the sysfs "dev" */
189 struct class_device_attribute *devt_attr;
188 struct device * dev; /* not necessary, but nice to have */ 190 struct device * dev; /* not necessary, but nice to have */
189 void * class_data; /* class-specific data */ 191 void * class_data; /* class-specific data */
190 192
@@ -245,6 +247,13 @@ struct class_interface {
245extern int class_interface_register(struct class_interface *); 247extern int class_interface_register(struct class_interface *);
246extern void class_interface_unregister(struct class_interface *); 248extern void class_interface_unregister(struct class_interface *);
247 249
250extern struct class *class_create(struct module *owner, char *name);
251extern void class_destroy(struct class *cls);
252extern struct class_device *class_device_create(struct class *cls, dev_t devt,
253 struct device *device, char *fmt, ...)
254 __attribute__((format(printf,4,5)));
255extern void class_device_destroy(struct class *cls, dev_t devt);
256
248/* interface for class simple stuff */ 257/* interface for class simple stuff */
249extern struct class_simple *class_simple_create(struct module *owner, char *name); 258extern struct class_simple *class_simple_create(struct module *owner, char *name);
250extern void class_simple_destroy(struct class_simple *cs); 259extern void class_simple_destroy(struct class_simple *cs);