diff options
| author | Dave Young <hidave.darkstar@gmail.com> | 2008-01-22 02:27:08 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-01-24 23:40:44 -0500 |
| commit | fd04897bb20be29d60f7e426a053545aebeaa61a (patch) | |
| tree | 7cd86b2d9de79a70bdeb32997240af5e28be6d03 /drivers/base | |
| parent | 63b6971a0876b744e2fcf3c9df15d130501e1deb (diff) | |
Driver Core: add class iteration api
Add the following class iteration functions for driver use:
class_for_each_device
class_find_device
class_for_each_child
class_find_child
Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/class.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index b962a76875d2..9f737ff0fc71 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
| @@ -809,6 +809,139 @@ void class_device_put(struct class_device *class_dev) | |||
| 809 | kobject_put(&class_dev->kobj); | 809 | kobject_put(&class_dev->kobj); |
| 810 | } | 810 | } |
| 811 | 811 | ||
| 812 | /** | ||
| 813 | * class_for_each_device - device iterator | ||
| 814 | * @class: the class we're iterating | ||
| 815 | * @data: data for the callback | ||
| 816 | * @fn: function to be called for each device | ||
| 817 | * | ||
| 818 | * Iterate over @class's list of devices, and call @fn for each, | ||
| 819 | * passing it @data. | ||
| 820 | * | ||
| 821 | * We check the return of @fn each time. If it returns anything | ||
| 822 | * other than 0, we break out and return that value. | ||
| 823 | * | ||
| 824 | * Note, we hold class->sem in this function, so it can not be | ||
| 825 | * re-acquired in @fn, otherwise it will self-deadlocking. For | ||
| 826 | * example, calls to add or remove class members would be verboten. | ||
| 827 | */ | ||
| 828 | int class_for_each_device(struct class *class, void *data, | ||
| 829 | int (*fn)(struct device *, void *)) | ||
| 830 | { | ||
| 831 | struct device *dev; | ||
| 832 | int error = 0; | ||
| 833 | |||
| 834 | if (!class) | ||
| 835 | return -EINVAL; | ||
| 836 | down(&class->sem); | ||
| 837 | list_for_each_entry(dev, &class->devices, node) { | ||
| 838 | dev = get_device(dev); | ||
| 839 | if (dev) { | ||
| 840 | error = fn(dev, data); | ||
| 841 | put_device(dev); | ||
| 842 | } else | ||
| 843 | error = -ENODEV; | ||
| 844 | if (error) | ||
| 845 | break; | ||
| 846 | } | ||
| 847 | up(&class->sem); | ||
| 848 | |||
| 849 | return error; | ||
| 850 | } | ||
| 851 | EXPORT_SYMBOL_GPL(class_for_each_device); | ||
| 852 | |||
| 853 | /** | ||
| 854 | * class_find_device - device iterator for locating a particular device | ||
| 855 | * @class: the class we're iterating | ||
| 856 | * @data: data for the match function | ||
| 857 | * @match: function to check device | ||
| 858 | * | ||
| 859 | * This is similar to the class_for_each_dev() function above, but it | ||
| 860 | * returns a reference to a device that is 'found' for later use, as | ||
| 861 | * determined by the @match callback. | ||
| 862 | * | ||
| 863 | * The callback should return 0 if the device doesn't match and non-zero | ||
| 864 | * if it does. If the callback returns non-zero, this function will | ||
| 865 | * return to the caller and not iterate over any more devices. | ||
| 866 | |||
| 867 | * Note, you will need to drop the reference with put_device() after use. | ||
| 868 | * | ||
| 869 | * We hold class->sem in this function, so it can not be | ||
| 870 | * re-acquired in @match, otherwise it will self-deadlocking. For | ||
| 871 | * example, calls to add or remove class members would be verboten. | ||
| 872 | */ | ||
| 873 | struct device *class_find_device(struct class *class, void *data, | ||
| 874 | int (*match)(struct device *, void *)) | ||
| 875 | { | ||
| 876 | struct device *dev; | ||
| 877 | int found = 0; | ||
| 878 | |||
| 879 | if (!class) | ||
| 880 | return NULL; | ||
| 881 | |||
| 882 | down(&class->sem); | ||
| 883 | list_for_each_entry(dev, &class->devices, node) { | ||
| 884 | dev = get_device(dev); | ||
| 885 | if (dev) { | ||
| 886 | if (match(dev, data)) { | ||
| 887 | found = 1; | ||
| 888 | break; | ||
| 889 | } else | ||
| 890 | put_device(dev); | ||
| 891 | } else | ||
| 892 | break; | ||
| 893 | } | ||
| 894 | up(&class->sem); | ||
| 895 | |||
| 896 | return found ? dev : NULL; | ||
| 897 | } | ||
| 898 | EXPORT_SYMBOL_GPL(class_find_device); | ||
| 899 | |||
| 900 | /** | ||
| 901 | * class_find_child - device iterator for locating a particular class_device | ||
| 902 | * @class: the class we're iterating | ||
| 903 | * @data: data for the match function | ||
| 904 | * @match: function to check class_device | ||
| 905 | * | ||
| 906 | * This function returns a reference to a class_device that is 'found' for | ||
| 907 | * later use, as determined by the @match callback. | ||
| 908 | * | ||
| 909 | * The callback should return 0 if the class_device doesn't match and non-zero | ||
| 910 | * if it does. If the callback returns non-zero, this function will | ||
| 911 | * return to the caller and not iterate over any more class_devices. | ||
| 912 | * | ||
| 913 | * Note, you will need to drop the reference with class_device_put() after use. | ||
| 914 | * | ||
| 915 | * We hold class->sem in this function, so it can not be | ||
| 916 | * re-acquired in @match, otherwise it will self-deadlocking. For | ||
| 917 | * example, calls to add or remove class members would be verboten. | ||
| 918 | */ | ||
| 919 | struct class_device *class_find_child(struct class *class, void *data, | ||
| 920 | int (*match)(struct class_device *, void *)) | ||
| 921 | { | ||
| 922 | struct class_device *dev; | ||
| 923 | int found = 0; | ||
| 924 | |||
| 925 | if (!class) | ||
| 926 | return NULL; | ||
| 927 | |||
| 928 | down(&class->sem); | ||
| 929 | list_for_each_entry(dev, &class->children, node) { | ||
| 930 | dev = class_device_get(dev); | ||
| 931 | if (dev) { | ||
| 932 | if (match(dev, data)) { | ||
| 933 | found = 1; | ||
| 934 | break; | ||
| 935 | } else | ||
| 936 | class_device_put(dev); | ||
| 937 | } else | ||
| 938 | break; | ||
| 939 | } | ||
| 940 | up(&class->sem); | ||
| 941 | |||
| 942 | return found ? dev : NULL; | ||
| 943 | } | ||
| 944 | EXPORT_SYMBOL_GPL(class_find_child); | ||
| 812 | 945 | ||
| 813 | int class_interface_register(struct class_interface *class_intf) | 946 | int class_interface_register(struct class_interface *class_intf) |
| 814 | { | 947 | { |
