lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 18 Oct 2014 16:55:20 +0200
From:	Grant Likely <grant.likely@...aro.org>
To:	"Rafael J. Wysocki" <rjw@...ysocki.net>,
	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Cc:	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Arnd Bergmann <arnd@...db.de>,
	Mika Westerberg <mika.westerberg@...ux.intel.com>,
	ACPI Devel Maling List <linux-acpi@...r.kernel.org>,
	Aaron Lu <aaron.lu@...el.com>, devicetree@...r.kernel.org,
	Linus Walleij <linus.walleij@...aro.org>,
	Alexandre Courbot <gnurou@...il.com>,
	Dmitry Torokhov <dmitry.torokhov@...il.com>,
	Bryan Wu <cooloney@...il.com>,
	Darren Hart <dvhart@...ux.intel.com>,
	Mark Rutland <mark.rutland@....com>
Subject: Re: [PATCH v5 09/12] Driver core: Unified interface for firmware
 node properties

On Fri, 17 Oct 2014 14:14:53 +0200
, "Rafael J. Wysocki" <rjw@...ysocki.net>
 wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
> 
> 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 <grant.likely@...aro.org>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
> ---
>  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 <linux/device.h>
> +#include <linux/property.h>
>  
>  /* 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 "<no-node>";
> 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@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists