diff options
-rw-r--r-- | drivers/base/class.c | 10 | ||||
-rw-r--r-- | drivers/base/core.c | 14 | ||||
-rw-r--r-- | include/linux/device.h | 2 |
3 files changed, 25 insertions, 1 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index cbdf47c0c60d..b06b0e2b9c62 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -842,6 +842,7 @@ int class_interface_register(struct class_interface *class_intf) | |||
842 | { | 842 | { |
843 | struct class *parent; | 843 | struct class *parent; |
844 | struct class_device *class_dev; | 844 | struct class_device *class_dev; |
845 | struct device *dev; | ||
845 | 846 | ||
846 | if (!class_intf || !class_intf->class) | 847 | if (!class_intf || !class_intf->class) |
847 | return -ENODEV; | 848 | return -ENODEV; |
@@ -856,6 +857,10 @@ int class_interface_register(struct class_interface *class_intf) | |||
856 | list_for_each_entry(class_dev, &parent->children, node) | 857 | list_for_each_entry(class_dev, &parent->children, node) |
857 | class_intf->add(class_dev, class_intf); | 858 | class_intf->add(class_dev, class_intf); |
858 | } | 859 | } |
860 | if (class_intf->add_dev) { | ||
861 | list_for_each_entry(dev, &parent->devices, node) | ||
862 | class_intf->add_dev(dev, class_intf); | ||
863 | } | ||
859 | up(&parent->sem); | 864 | up(&parent->sem); |
860 | 865 | ||
861 | return 0; | 866 | return 0; |
@@ -865,6 +870,7 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
865 | { | 870 | { |
866 | struct class * parent = class_intf->class; | 871 | struct class * parent = class_intf->class; |
867 | struct class_device *class_dev; | 872 | struct class_device *class_dev; |
873 | struct device *dev; | ||
868 | 874 | ||
869 | if (!parent) | 875 | if (!parent) |
870 | return; | 876 | return; |
@@ -875,6 +881,10 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
875 | list_for_each_entry(class_dev, &parent->children, node) | 881 | list_for_each_entry(class_dev, &parent->children, node) |
876 | class_intf->remove(class_dev, class_intf); | 882 | class_intf->remove(class_dev, class_intf); |
877 | } | 883 | } |
884 | if (class_intf->remove_dev) { | ||
885 | list_for_each_entry(dev, &parent->devices, node) | ||
886 | class_intf->remove_dev(dev, class_intf); | ||
887 | } | ||
878 | up(&parent->sem); | 888 | up(&parent->sem); |
879 | 889 | ||
880 | class_put(parent); | 890 | class_put(parent); |
diff --git a/drivers/base/core.c b/drivers/base/core.c index e21a65fc043e..1d3d3582fcca 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -372,6 +372,7 @@ int device_add(struct device *dev) | |||
372 | { | 372 | { |
373 | struct device *parent = NULL; | 373 | struct device *parent = NULL; |
374 | char *class_name = NULL; | 374 | char *class_name = NULL; |
375 | struct class_interface *class_intf; | ||
375 | int error = -EINVAL; | 376 | int error = -EINVAL; |
376 | 377 | ||
377 | dev = get_device(dev); | 378 | dev = get_device(dev); |
@@ -451,9 +452,14 @@ int device_add(struct device *dev) | |||
451 | klist_add_tail(&dev->knode_parent, &parent->klist_children); | 452 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
452 | 453 | ||
453 | if (dev->class) { | 454 | if (dev->class) { |
454 | /* tie the class to the device */ | ||
455 | down(&dev->class->sem); | 455 | down(&dev->class->sem); |
456 | /* tie the class to the device */ | ||
456 | list_add_tail(&dev->node, &dev->class->devices); | 457 | list_add_tail(&dev->node, &dev->class->devices); |
458 | |||
459 | /* notify any interfaces that the device is here */ | ||
460 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | ||
461 | if (class_intf->add_dev) | ||
462 | class_intf->add_dev(dev, class_intf); | ||
457 | up(&dev->class->sem); | 463 | up(&dev->class->sem); |
458 | } | 464 | } |
459 | 465 | ||
@@ -548,6 +554,7 @@ void device_del(struct device * dev) | |||
548 | { | 554 | { |
549 | struct device * parent = dev->parent; | 555 | struct device * parent = dev->parent; |
550 | char *class_name = NULL; | 556 | char *class_name = NULL; |
557 | struct class_interface *class_intf; | ||
551 | 558 | ||
552 | if (parent) | 559 | if (parent) |
553 | klist_del(&dev->knode_parent); | 560 | klist_del(&dev->knode_parent); |
@@ -563,6 +570,11 @@ void device_del(struct device * dev) | |||
563 | } | 570 | } |
564 | kfree(class_name); | 571 | kfree(class_name); |
565 | down(&dev->class->sem); | 572 | down(&dev->class->sem); |
573 | /* notify any interfaces that the device is now gone */ | ||
574 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | ||
575 | if (class_intf->remove_dev) | ||
576 | class_intf->remove_dev(dev, class_intf); | ||
577 | /* remove the device from the class list */ | ||
566 | list_del_init(&dev->node); | 578 | list_del_init(&dev->node); |
567 | up(&dev->class->sem); | 579 | up(&dev->class->sem); |
568 | } | 580 | } |
diff --git a/include/linux/device.h b/include/linux/device.h index bbb0d6b5d232..e0fae0e76fa9 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -278,6 +278,8 @@ struct class_interface { | |||
278 | 278 | ||
279 | int (*add) (struct class_device *, struct class_interface *); | 279 | int (*add) (struct class_device *, struct class_interface *); |
280 | void (*remove) (struct class_device *, struct class_interface *); | 280 | void (*remove) (struct class_device *, struct class_interface *); |
281 | int (*add_dev) (struct device *, struct class_interface *); | ||
282 | void (*remove_dev) (struct device *, struct class_interface *); | ||
281 | }; | 283 | }; |
282 | 284 | ||
283 | extern int class_interface_register(struct class_interface *); | 285 | extern int class_interface_register(struct class_interface *); |