driver core: implement device_for_each_child_reverse()
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Mon, 27 Jul 2015 15:04:00 +0000 (18:04 +0300)
committerLee Jones <lee.jones@linaro.org>
Tue, 28 Jul 2015 07:50:42 +0000 (08:50 +0100)
The new function device_for_each_child_reverse() is helpful to traverse the
registered devices in a reversed order, e.g. in the case when an operation on
each device should be done first on the last added device, then on one before
last and so on.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/base/core.c
include/linux/device.h

index dafae6d2f7ace1fd2941fcbc26ca50fa6450b0f9..7d6279554afc73222ab12af6671bf0d0d74a869c 100644 (file)
@@ -1252,6 +1252,19 @@ void device_unregister(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(device_unregister);
 
+static struct device *prev_device(struct klist_iter *i)
+{
+       struct klist_node *n = klist_prev(i);
+       struct device *dev = NULL;
+       struct device_private *p;
+
+       if (n) {
+               p = to_device_private_parent(n);
+               dev = p->device;
+       }
+       return dev;
+}
+
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
@@ -1340,6 +1353,36 @@ int device_for_each_child(struct device *parent, void *data,
 }
 EXPORT_SYMBOL_GPL(device_for_each_child);
 
+/**
+ * device_for_each_child_reverse - device child iterator in reversed order.
+ * @parent: parent struct device.
+ * @fn: function to be called for each device.
+ * @data: data for the callback.
+ *
+ * Iterate over @parent's child devices, and call @fn for each,
+ * passing it @data.
+ *
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
+ */
+int device_for_each_child_reverse(struct device *parent, void *data,
+                                 int (*fn)(struct device *dev, void *data))
+{
+       struct klist_iter i;
+       struct device *child;
+       int error = 0;
+
+       if (!parent->p)
+               return 0;
+
+       klist_iter_init(&parent->p->klist_children, &i);
+       while ((child = prev_device(&i)) && !error)
+               error = fn(child, data);
+       klist_iter_exit(&i);
+       return error;
+}
+EXPORT_SYMBOL_GPL(device_for_each_child_reverse);
+
 /**
  * device_find_child - device iterator for locating a particular device.
  * @parent: parent struct device
index 5a31bf3a40243e1faff078fdc509361568143f01..af6fbc35d8a6c76ee341b3629389aefbf08e96ee 100644 (file)
@@ -958,6 +958,8 @@ extern int __must_check device_add(struct device *dev);
 extern void device_del(struct device *dev);
 extern int device_for_each_child(struct device *dev, void *data,
                     int (*fn)(struct device *dev, void *data));
+extern int device_for_each_child_reverse(struct device *dev, void *data,
+                    int (*fn)(struct device *dev, void *data));
 extern struct device *device_find_child(struct device *dev, void *data,
                                int (*match)(struct device *dev, void *data));
 extern int device_rename(struct device *dev, const char *new_name);