Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751560AbaJROza (ORCPT ); Sat, 18 Oct 2014 10:55:30 -0400 Received: from mail-wi0-f176.google.com ([209.85.212.176]:60753 "EHLO mail-wi0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751320AbaJROzY (ORCPT ); Sat, 18 Oct 2014 10:55:24 -0400 From: Grant Likely Subject: Re: [PATCH v5 09/12] Driver core: Unified interface for firmware node properties To: "Rafael J. Wysocki" , Linux Kernel Mailing List Cc: Greg Kroah-Hartman , Arnd Bergmann , Mika Westerberg , ACPI Devel Maling List , Aaron Lu , devicetree@vger.kernel.org, Linus Walleij , Alexandre Courbot , Dmitry Torokhov , Bryan Wu , Darren Hart , Mark Rutland In-Reply-To: <1628104.Ek1EGbdVha@vostro.rjw.lan> References: <2660541.BycO7TFnA2@vostro.rjw.lan> <11223831.j9KAEfSQsY@vostro.rjw.lan> <1628104.Ek1EGbdVha@vostro.rjw.lan> Date: Sat, 18 Oct 2014 16:55:20 +0200 Message-Id: <20141018145520.6039FC40591@trevor.secretlab.ca> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, 17 Oct 2014 14:14:53 +0200 , "Rafael J. Wysocki" wrote: > From: Rafael J. Wysocki > > Add new generic routines are provided for retrieving properties from > device description objects in the platform firmware in case there are > no struct device objects for them (either those objects have not been > created yet or they do not exist at all). > > The following functions are provided: > > fwnode_property_present() > fwnode_property_read_u8() > fwnode_property_read_u16() > fwnode_property_read_u32() > fwnode_property_read_u64() > fwnode_property_read_string() > fwnode_property_read_u8_array() > fwnode_property_read_u16_array() > fwnode_property_read_u32_array() > fwnode_property_read_u64_array() > fwnode_property_read_string_array() > > in analogy with the corresponding functions for struct device added > previously. For all of them, the first argument is a pointer to struct > fwnode_handle (new type) that allows a device description object > (depending on what platform firmware interface is in use) to be > obtained. > > Add a new macro device_for_each_child_node() for iterating over the > children of the device description object associated with a given > device and a new function device_get_child_node_count() returning the > number of a given device's child nodes. > > The interface covers both ACPI and Device Trees. This is all *so much* better. I'm a lot happier. I was about to make the comment that the implementation for device_property_read_*() should merely be wrappers around fwnode_property_read_*(), but when when I actually looked at it, I saw this: In patch 2: int device_property_read_u8(struct device *dev, const char *propname, u8 *val) { if (IS_ENABLED(CONFIG_OF) && dev->of_node) return of_property_read_u8(dev->of_node, propname, val); return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, DEV_PROP_U8, val); } And in this patch: int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname, u8 *val) { if (is_of_node(fwnode)) return of_property_read_u8(of_node(fwnode), propname, val); else if (is_acpi_node(fwnode)) return acpi_dev_prop_read(acpi_node(fwnode), propname, DEV_PROP_U8, val); return -ENXIO; } Making the device_property functions wrappers around fwnode_property_* wouldn't actually be great since it would need to decode the fwnode pointer twice. I do still think the functions above should be macro generated, just in terms of keeping the line count down, and I would suggest merging patches #2 and #9. Something like: #define define_fwnode_accessors(__type, __devprop_type) \ int device_property_read_##__type(struct device *dev, \ const char *propname, __type *val) \ { \ if (IS_ENABLED(CONFIG_OF) && dev->of_node) \ return of_property_read_##__type(dev->of_node, propname, val); \ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \ __devprop_type, val); \ } \ int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \ const char *propname, __type *val) \ { \ if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \ return of_property_read_##__type(of_node(fwnode), propname, val); \ else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \ return acpi_dev_prop_read(acpi_node(fwnode), propname, \ __devprop_type, val); \ return -ENXIO; \ } define_fwnode_accessors(u8, DEV_PROP_U8); define_fwnode_accessors(u16, DEV_PROP_U16); define_fwnode_accessors(u32, DEV_PROP_U32); define_fwnode_accessors(u64, DEV_PROP_U64); That significantly reduces the code size for these things. Also, can the non-array versions be implemented as a wrapper around the array versions? That also will reduce the sheer number of lines of code a lot. Maybe this: #define define_fwnode_accessors(__type, __devprop_type) \ int device_property_read_##__type##_array(struct device *dev, \ const char *propname, __type *val, \ size_t nval) \ { \ if (IS_ENABLED(CONFIG_OF) && dev->of_node) \ return of_property_read_##__type##_array(dev->of_node, \ propname, val, nval); \ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, \ __devprop_type, val, nval); \ } \ static inline int device_property_read_##__type(struct device *dev, \ const char *propname, __type *val) \ { \ return device_property_read_##__type##_array(dev, propname, val, 1) \ } \ int fwnode_property_read_##__type##_array(struct fwnode_handle *fwnode, \ const char *propname, __type *val, \ size_t nval) \ { \ if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \ return of_property_read_##__type(of_node(fwnode), propname, val, nval); \ else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \ return acpi_dev_prop_read(acpi_node(fwnode), propname, \ __devprop_type, val, nval); \ return -ENXIO; \ } \ static inline int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \ const char *propname, __type *val) \ { \ return fwnode_property_read_##__type##_array(fwnode, propname, val, 1) \ } define_fwnode_accessors(u8, DEV_PROP_U8); define_fwnode_accessors(u16, DEV_PROP_U16); define_fwnode_accessors(u32, DEV_PROP_U32); define_fwnode_accessors(u64, DEV_PROP_U64); g. > > Suggested-by: Grant Likely > Signed-off-by: Rafael J. Wysocki > --- > drivers/acpi/scan.c | 21 ++ > drivers/base/property.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++ > include/acpi/acpi_bus.h | 12 + > include/linux/acpi.h | 21 ++ > include/linux/of.h | 22 ++ > include/linux/property.h | 48 ++++++ > 6 files changed, 497 insertions(+) > > Index: linux-pm/include/linux/property.h > =================================================================== > --- linux-pm.orig/include/linux/property.h > +++ linux-pm/include/linux/property.h > @@ -44,4 +44,52 @@ int device_property_read_u64_array(struc > int device_property_read_string_array(struct device *dev, const char *propname, > char **val, size_t nval); > > +enum fwnode_type { > + FWNODE_INVALID = 0, > + FWNODE_OF, > + FWNODE_ACPI, > +}; > + > +struct fwnode_handle { > + enum fwnode_type type; > +}; > + > +bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname); > +int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname, > + u8 *val); > +int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname, > + u16 *val); > +int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname, > + u32 *val); > +int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname, > + u64 *val); > +int fwnode_property_read_string(struct fwnode_handle *fwnode, > + const char *propname, const char **val); > +int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, > + const char *propname, u8 *val, > + size_t nval); > +int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, > + const char *propname, u16 *val, > + size_t nval); > +int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, > + const char *propname, u32 *val, > + size_t nval); > +int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, > + const char *propname, u64 *val, > + size_t nval); > +int fwnode_property_read_string_array(struct fwnode_handle *fwnode, > + const char *propname, char **val, > + size_t nval); > + > +struct fwnode_handle *device_get_next_child_node(struct device *dev, > + struct fwnode_handle *child); > + > +#define device_for_each_child_node(dev, child) \ > + for (child = device_get_next_child_node(dev, NULL); child; \ > + child = device_get_next_child_node(dev, child)) > + > +void fwnode_handle_put(struct fwnode_handle *fwnode); > + > +unsigned int device_get_child_node_count(struct device *dev); > + > #endif /* _LINUX_PROPERTY_H_ */ > Index: linux-pm/include/acpi/acpi_bus.h > =================================================================== > --- linux-pm.orig/include/acpi/acpi_bus.h > +++ linux-pm/include/acpi/acpi_bus.h > @@ -27,6 +27,7 @@ > #define __ACPI_BUS_H__ > > #include > +#include > > /* TBD: Make dynamic */ > #define ACPI_MAX_HANDLES 10 > @@ -348,6 +349,7 @@ struct acpi_device_data { > struct acpi_device { > int device_type; > acpi_handle handle; /* no handle for fixed hardware */ > + struct fwnode_handle fwnode; > struct acpi_device *parent; > struct list_head children; > struct list_head node; > @@ -372,6 +374,16 @@ struct acpi_device { > void (*remove)(struct acpi_device *); > }; > > +static inline bool is_acpi_node(struct fwnode_handle *fwnode) > +{ > + return fwnode && fwnode->type == FWNODE_ACPI; > +} > + > +static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode) > +{ > + return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL; > +} > + > static inline void *acpi_driver_data(struct acpi_device *d) > { > return d->driver_data; > Index: linux-pm/include/linux/acpi.h > =================================================================== > --- linux-pm.orig/include/linux/acpi.h > +++ linux-pm/include/linux/acpi.h > @@ -439,6 +439,18 @@ int acpi_device_modalias(struct device * > #define ACPI_COMPANION_SET(dev, adev) do { } while (0) > #define ACPI_HANDLE(dev) (NULL) > > +struct fwnode_handle; > + > +static inline bool is_acpi_node(struct fwnode_handle *fwnode) > +{ > + return false; > +} > + > +static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode) > +{ > + return NULL; > +} > + > static inline const char *acpi_dev_name(struct acpi_device *adev) > { > return NULL; > @@ -681,6 +693,9 @@ int acpi_dev_prop_read(struct acpi_devic > int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname, > enum dev_prop_type proptype, void *val, > size_t nval); > + > +struct acpi_device *acpi_get_next_child(struct device *dev, > + struct acpi_device *child); > #else > static inline int acpi_dev_get_property(struct acpi_device *adev, > const char *name, acpi_object_type type, > @@ -724,6 +739,12 @@ static inline int acpi_dev_prop_read_arr > return -ENXIO; > } > > +static inline struct acpi_device *acpi_get_next_child(struct device *dev, > + struct acpi_device *child) > +{ > + return NULL; > +} > + > #endif > > #endif /*_LINUX_ACPI_H*/ > Index: linux-pm/include/linux/of.h > =================================================================== > --- linux-pm.orig/include/linux/of.h > +++ linux-pm/include/linux/of.h > @@ -50,6 +50,7 @@ struct device_node { > const char *type; > phandle phandle; > const char *full_name; > + struct fwnode_handle fwnode; > > struct property *properties; > struct property *deadprops; /* removed properties */ > @@ -80,6 +81,7 @@ extern struct kobj_type of_node_ktype; > static inline void of_node_init(struct device_node *node) > { > kobject_init(&node->kobj, &of_node_ktype); > + node->fwnode.type = FWNODE_OF; > } > > /* true when node is initialized */ > @@ -115,6 +117,16 @@ extern struct device_node *of_aliases; > extern struct device_node *of_stdout; > extern raw_spinlock_t devtree_lock; > > +static inline bool is_of_node(struct fwnode_handle *fwnode) > +{ > + return fwnode && fwnode->type == FWNODE_OF; > +} > + > +static inline struct device_node *of_node(struct fwnode_handle *fwnode) > +{ > + return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL; > +} > + > static inline bool of_have_populated_dt(void) > { > return of_allnodes != NULL; > @@ -365,6 +377,16 @@ bool of_console_check(struct device_node > > #else /* CONFIG_OF */ > > +static inline bool is_of_node(struct fwnode_handle *fwnode) > +{ > + return false; > +} > + > +static inline struct device_node *of_node(struct fwnode_handle *fwnode) > +{ > + return NULL; > +} > + > static inline const char* of_node_full_name(const struct device_node *np) > { > return ""; > Index: linux-pm/drivers/base/property.c > =================================================================== > --- linux-pm.orig/drivers/base/property.c > +++ linux-pm/drivers/base/property.c > @@ -156,6 +156,166 @@ int device_property_read_string(struct d > } > EXPORT_SYMBOL_GPL(device_property_read_string); > > +/** > + * fwnode_property_present - check if a property of a firmware node is present > + * @fwnode: Firmware node whose property to check > + * @propname: Name of the property > + */ > +bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_bool(of_node(fwnode), propname); > + else if (is_acpi_node(fwnode)) > + return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); > + > + return false; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_present); > + > +/** > + * fwnode_property_read_u8 - return a u8 property of a firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The value is stored here > + * > + * Read property @propname from the given firmware node and store the value into > + * @val if found. The value is checked to be of type u8. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO or %-EILSEQ if the property type is not u8, > + * %-EOVERFLOW if the property value is out of bounds of u8, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname, > + u8 *val) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_u8(of_node(fwnode), propname, val); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read(acpi_node(fwnode), propname, > + DEV_PROP_U8, val); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u8); > + > +/** > + * fwnode_property_read_u16 - return a u16 property of a firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The value is stored here > + * > + * Read property @propname from the given firmware node and store the value into > + * @val if found. The value is checked to be of type u16. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO or %-EILSEQ if the property type is not u16, > + * %-EOVERFLOW if the property value is out of bounds of u16, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname, > + u16 *val) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_u16(of_node(fwnode), propname, val); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read(acpi_node(fwnode), propname, > + DEV_PROP_U16, val); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u16); > + > +/** > + * fwnode_property_read_u32 - return a u32 property of a firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The value is stored here > + * > + * Read property @propname from the given firmware node and store the value into > + * @val if found. The value is checked to be of type u32. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO or %-EILSEQ if the property type is not u32, > + * %-EOVERFLOW if the property value is out of bounds of u32, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname, > + u32 *val) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_u32(of_node(fwnode), propname, val); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read(acpi_node(fwnode), propname, > + DEV_PROP_U32, val); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u32); > + > +/** > + * fwnode_property_read_u64 - return a u64 property of a firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The value is stored here > + * > + * Read property @propname from the given firmware node and store the value into > + * @val if found. The value is checked to be of type u64. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO or %-EILSEQ if the property type is not u64, > + * %-EOVERFLOW if the property value is out of bounds of u64, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname, > + u64 *val) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_u64(of_node(fwnode), propname, val); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read(acpi_node(fwnode), propname, > + DEV_PROP_U64, val); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u64); > + > +/** > + * fwnode_property_read_string - return a string property of a firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The value is stored here > + * > + * Read property @propname from the given firmware node and store the value into > + * @val if found. The value is checked to be a string. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO or %-EILSEQ if the property is not a string, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_string(struct fwnode_handle *fwnode, > + const char *propname, const char **val) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_string(of_node(fwnode), propname, val); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read(acpi_node(fwnode), propname, > + DEV_PROP_STRING, val); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_string); > + > #define of_dev_prop_read_array(node, propname, type, val, nval) \ > (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ > : of_property_count_elems_of_size((node), (propname), sizeof(type)) > @@ -299,3 +459,216 @@ int device_property_read_string_array(st > DEV_PROP_STRING, val, nval); > } > EXPORT_SYMBOL_GPL(device_property_read_string_array); > + > +/** > + * fwnode_property_read_u8_array - return a u8 array property of firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The values are stored here > + * @nval: Size of the @val array > + * > + * Read an array of u8 properties with @propname from @fwnode and stores them to > + * @val if found. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO if the property is not an array of numbers, > + * %-EOVERFLOW if the size of the property is not as expected, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, > + const char *propname, u8 *val, size_t nval) > +{ > + if (is_of_node(fwnode)) > + return of_dev_prop_read_array(of_node(fwnode), propname, > + u8, val, nval); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read_array(acpi_node(fwnode), propname, > + DEV_PROP_U8, val, nval); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); > + > +/** > + * fwnode_property_read_u16_array - return a u16 array property of firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The values are stored here > + * @nval: Size of the @val array > + * > + * Read an array of u16 properties with @propname from @fwnode and store them to > + * @val if found. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO if the property is not an array of numbers, > + * %-EOVERFLOW if the size of the property is not as expected, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, > + const char *propname, u16 *val, size_t nval) > +{ > + if (is_of_node(fwnode)) > + return of_dev_prop_read_array(of_node(fwnode), propname, > + u16, val, nval); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read_array(acpi_node(fwnode), propname, > + DEV_PROP_U16, val, nval); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); > + > +/** > + * fwnode_property_read_u32_array - return a u32 array property of firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The values are stored here > + * @nval: Size of the @val array > + * > + * Read an array of u32 properties with @propname from @fwnode store them to > + * @val if found. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO if the property is not an array of numbers, > + * %-EOVERFLOW if the size of the property is not as expected, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, > + const char *propname, u32 *val, size_t nval) > +{ > + if (is_of_node(fwnode)) > + return of_dev_prop_read_array(of_node(fwnode), propname, > + u32, val, nval); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read_array(acpi_node(fwnode), propname, > + DEV_PROP_U32, val, nval); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); > + > +/** > + * fwnode_property_read_u64_array - return a u64 array property firmware node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The values are stored here > + * @nval: Size of the @val array > + * > + * Read an array of u64 properties with @propname from @fwnode and store them to > + * @val if found. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO if the property is not an array of numbers, > + * %-EOVERFLOW if the size of the property is not as expected, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, > + const char *propname, u64 *val, size_t nval) > +{ > + if (is_of_node(fwnode)) > + return of_dev_prop_read_array(of_node(fwnode), propname, > + u64, val, nval); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read_array(acpi_node(fwnode), propname, > + DEV_PROP_U64, val, nval); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); > + > +/** > + * fwnode_property_read_string_array - return string array property of a node > + * @fwnode: Firmware node to get the property of > + * @propname: Name of the property > + * @val: The values are stored here > + * @nval: Size of the @val array > + * > + * Read an string list property @propname from the given firmware node and store > + * them to @val if found. > + * > + * Return: %0 if the property was found (success), > + * %-EINVAL if given arguments are not valid, > + * %-ENODATA if the property does not have a value, > + * %-EPROTO if the property is not an array of strings, > + * %-EOVERFLOW if the size of the property is not as expected, > + * %-ENXIO if no suitable firmware interface is present. > + */ > +int fwnode_property_read_string_array(struct fwnode_handle *fwnode, > + const char *propname, char **val, > + size_t nval) > +{ > + if (is_of_node(fwnode)) > + return of_property_read_string_array(of_node(fwnode), propname, > + val, nval); > + else if (is_acpi_node(fwnode)) > + return acpi_dev_prop_read_array(acpi_node(fwnode), propname, > + DEV_PROP_STRING, val, nval); > + > + return -ENXIO; > +} > +EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); > + > + > +/** > + * device_get_next_child_node - Return the next child node handle for a device > + * @dev: Device to find the next child node for. > + * @child: Handle to one of the device's child nodes or a null handle. > + */ > +struct fwnode_handle *device_get_next_child_node(struct device *dev, > + struct fwnode_handle *child) > +{ > + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { > + struct device_node *node; > + > + node = of_get_next_available_child(dev->of_node, of_node(child)); > + if (node) > + return &node->fwnode; > + } else if (ACPI_COMPANION(dev)) { > + struct acpi_device *node; > + > + node = acpi_get_next_child(dev, acpi_node(child)); > + if (node) > + return &node->fwnode; > + } > + return NULL; > +} > +EXPORT_SYMBOL_GPL(device_get_next_child_node); > + > +/** > + * fwnode_handle_put - Drop reference to a device node > + * @fwnode: Pointer to the device node to drop the reference to. > + * > + * This has to be used when terminating device_for_each_child_node() iteration > + * with break or return to prevent stale device node references from being left > + * behind. > + */ > +void fwnode_handle_put(struct fwnode_handle *fwnode) > +{ > + if (is_of_node(fwnode)) > + of_node_put(of_node(fwnode)); > +} > +EXPORT_SYMBOL_GPL(fwnode_handle_put); > + > +/** > + * device_get_child_node_count - return the number of child nodes for device > + * @dev: Device to cound the child nodes for > + */ > +unsigned int device_get_child_node_count(struct device *dev) > +{ > + struct fwnode_handle *child; > + unsigned int count = 0; > + > + device_for_each_child_node(dev, child) > + count++; > + > + return count; > +} > +EXPORT_SYMBOL_GPL(device_get_child_node_count); > Index: linux-pm/drivers/acpi/scan.c > =================================================================== > --- linux-pm.orig/drivers/acpi/scan.c > +++ linux-pm/drivers/acpi/scan.c > @@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device * > return result; > } > > +struct acpi_device *acpi_get_next_child(struct device *dev, > + struct acpi_device *child) > +{ > + struct acpi_device *adev = ACPI_COMPANION(dev); > + struct list_head *head, *next; > + > + if (!adev) > + return NULL; > + > + head = &adev->children; > + if (list_empty(head)) > + return NULL; > + > + if (!child) > + return list_first_entry(head, struct acpi_device, node); > + > + next = child->node.next; > + return next == head ? NULL : list_entry(next, struct acpi_device, node); > +} > + > /* -------------------------------------------------------------------------- > Driver Management > -------------------------------------------------------------------------- */ > @@ -1961,6 +1981,7 @@ void acpi_init_device_object(struct acpi > device->device_type = type; > device->handle = handle; > device->parent = acpi_bus_get_parent(handle); > + device->fwnode.type = FWNODE_ACPI; > acpi_set_device_status(device, sta); > acpi_device_get_busid(device); > acpi_set_pnp_ids(handle, &device->pnp, type); > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/