aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-01-11 19:07:46 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-01-11 19:07:46 -0500
commit989652871b06f1fb173bc5e8e2ea03bec8f8eeeb (patch)
tree1a9331bbbf04b5e04148e68214e52551b2f1317f /drivers/base
parentafd2ff9b7e1b367172f18ba7f693dfb62bdcb2dc (diff)
parentf6740c1899d2ee2c4c9ec5301d4b712d4e706a79 (diff)
Merge branch 'device-properties'
* device-properties: device property: avoid allocations of 0 length device property: the secondary fwnode needs to depend on the primary device property: add spaces to PROPERTY_ENTRY_STRING macro include/linux/property.h: fix build issues with gcc-4.4.4 i2c: designware: Convert to use unified device property API mfd: intel-lpss: Pass HSUART configuration via properties mfd: intel-lpss: Pass SDA hold time to I2C host controller driver mfd: intel-lpss: Add support for passing device properties mfd: core: propagate device properties to sub devices drivers driver core: Do not overwrite secondary fwnode with NULL if it is set driver core: platform: Add support for built-in device properties device property: Take a copy of the property set device property: Fallback to secondary fwnode if primary misses the property device property: return -EINVAL when property isn't found in ACPI device property: improve readability of macros device property: helper macros for property entry creation device property: keep single value inplace device property: refactor built-in properties support device property: rename helper functions device property: always check for fwnode type
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c5
-rw-r--r--drivers/base/platform.c25
-rw-r--r--drivers/base/property.c495
3 files changed, 430 insertions, 95 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index b7d56c5ea3c6..0a8bdade53f2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2261,7 +2261,10 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
2261 if (fwnode_is_primary(fn)) 2261 if (fwnode_is_primary(fn))
2262 fn = fn->secondary; 2262 fn = fn->secondary;
2263 2263
2264 fwnode->secondary = fn; 2264 if (fn) {
2265 WARN_ON(fwnode->secondary);
2266 fwnode->secondary = fn;
2267 }
2265 dev->fwnode = fwnode; 2268 dev->fwnode = fwnode;
2266 } else { 2269 } else {
2267 dev->fwnode = fwnode_is_primary(dev->fwnode) ? 2270 dev->fwnode = fwnode_is_primary(dev->fwnode) ?
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 1dd6d3bf1098..d77ed0c946dd 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -26,6 +26,7 @@
26#include <linux/acpi.h> 26#include <linux/acpi.h>
27#include <linux/clk/clk-conf.h> 27#include <linux/clk/clk-conf.h>
28#include <linux/limits.h> 28#include <linux/limits.h>
29#include <linux/property.h>
29 30
30#include "base.h" 31#include "base.h"
31#include "power/power.h" 32#include "power/power.h"
@@ -299,6 +300,22 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
299EXPORT_SYMBOL_GPL(platform_device_add_data); 300EXPORT_SYMBOL_GPL(platform_device_add_data);
300 301
301/** 302/**
303 * platform_device_add_properties - add built-in properties to a platform device
304 * @pdev: platform device to add properties to
305 * @pset: properties to add
306 *
307 * The function will take deep copy of the properties in @pset and attach
308 * the copy to the platform device. The memory associated with properties
309 * will be freed when the platform device is released.
310 */
311int platform_device_add_properties(struct platform_device *pdev,
312 const struct property_set *pset)
313{
314 return device_add_property_set(&pdev->dev, pset);
315}
316EXPORT_SYMBOL_GPL(platform_device_add_properties);
317
318/**
302 * platform_device_add - add a platform device to device hierarchy 319 * platform_device_add - add a platform device to device hierarchy
303 * @pdev: platform device we're adding 320 * @pdev: platform device we're adding
304 * 321 *
@@ -409,6 +426,8 @@ void platform_device_del(struct platform_device *pdev)
409 if (r->parent) 426 if (r->parent)
410 release_resource(r); 427 release_resource(r);
411 } 428 }
429
430 device_remove_property_set(&pdev->dev);
412 } 431 }
413} 432}
414EXPORT_SYMBOL_GPL(platform_device_del); 433EXPORT_SYMBOL_GPL(platform_device_del);
@@ -487,6 +506,12 @@ struct platform_device *platform_device_register_full(
487 if (ret) 506 if (ret)
488 goto err; 507 goto err;
489 508
509 if (pdevinfo->pset) {
510 ret = platform_device_add_properties(pdev, pdevinfo->pset);
511 if (ret)
512 goto err;
513 }
514
490 ret = platform_device_add(pdev); 515 ret = platform_device_add(pdev);
491 if (ret) { 516 if (ret) {
492err: 517err:
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 1325ff225cc4..c359351d50f1 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -19,32 +19,14 @@
19#include <linux/etherdevice.h> 19#include <linux/etherdevice.h>
20#include <linux/phy.h> 20#include <linux/phy.h>
21 21
22/** 22static inline bool is_pset_node(struct fwnode_handle *fwnode)
23 * device_add_property_set - Add a collection of properties to a device object.
24 * @dev: Device to add properties to.
25 * @pset: Collection of properties to add.
26 *
27 * Associate a collection of device properties represented by @pset with @dev
28 * as its secondary firmware node.
29 */
30void device_add_property_set(struct device *dev, struct property_set *pset)
31{
32 if (!pset)
33 return;
34
35 pset->fwnode.type = FWNODE_PDATA;
36 set_secondary_fwnode(dev, &pset->fwnode);
37}
38EXPORT_SYMBOL_GPL(device_add_property_set);
39
40static inline bool is_pset(struct fwnode_handle *fwnode)
41{ 23{
42 return fwnode && fwnode->type == FWNODE_PDATA; 24 return fwnode && fwnode->type == FWNODE_PDATA;
43} 25}
44 26
45static inline struct property_set *to_pset(struct fwnode_handle *fwnode) 27static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode)
46{ 28{
47 return is_pset(fwnode) ? 29 return is_pset_node(fwnode) ?
48 container_of(fwnode, struct property_set, fwnode) : NULL; 30 container_of(fwnode, struct property_set, fwnode) : NULL;
49} 31}
50 32
@@ -63,45 +45,135 @@ static struct property_entry *pset_prop_get(struct property_set *pset,
63 return NULL; 45 return NULL;
64} 46}
65 47
66static int pset_prop_read_array(struct property_set *pset, const char *name, 48static void *pset_prop_find(struct property_set *pset, const char *propname,
67 enum dev_prop_type type, void *val, size_t nval) 49 size_t length)
68{ 50{
69 struct property_entry *prop; 51 struct property_entry *prop;
70 unsigned int item_size; 52 void *pointer;
71 53
72 prop = pset_prop_get(pset, name); 54 prop = pset_prop_get(pset, propname);
73 if (!prop) 55 if (!prop)
74 return -ENODATA; 56 return ERR_PTR(-EINVAL);
57 if (prop->is_array)
58 pointer = prop->pointer.raw_data;
59 else
60 pointer = &prop->value.raw_data;
61 if (!pointer)
62 return ERR_PTR(-ENODATA);
63 if (length > prop->length)
64 return ERR_PTR(-EOVERFLOW);
65 return pointer;
66}
67
68static int pset_prop_read_u8_array(struct property_set *pset,
69 const char *propname,
70 u8 *values, size_t nval)
71{
72 void *pointer;
73 size_t length = nval * sizeof(*values);
74
75 pointer = pset_prop_find(pset, propname, length);
76 if (IS_ERR(pointer))
77 return PTR_ERR(pointer);
78
79 memcpy(values, pointer, length);
80 return 0;
81}
82
83static int pset_prop_read_u16_array(struct property_set *pset,
84 const char *propname,
85 u16 *values, size_t nval)
86{
87 void *pointer;
88 size_t length = nval * sizeof(*values);
89
90 pointer = pset_prop_find(pset, propname, length);
91 if (IS_ERR(pointer))
92 return PTR_ERR(pointer);
93
94 memcpy(values, pointer, length);
95 return 0;
96}
97
98static int pset_prop_read_u32_array(struct property_set *pset,
99 const char *propname,
100 u32 *values, size_t nval)
101{
102 void *pointer;
103 size_t length = nval * sizeof(*values);
104
105 pointer = pset_prop_find(pset, propname, length);
106 if (IS_ERR(pointer))
107 return PTR_ERR(pointer);
108
109 memcpy(values, pointer, length);
110 return 0;
111}
112
113static int pset_prop_read_u64_array(struct property_set *pset,
114 const char *propname,
115 u64 *values, size_t nval)
116{
117 void *pointer;
118 size_t length = nval * sizeof(*values);
119
120 pointer = pset_prop_find(pset, propname, length);
121 if (IS_ERR(pointer))
122 return PTR_ERR(pointer);
123
124 memcpy(values, pointer, length);
125 return 0;
126}
127
128static int pset_prop_count_elems_of_size(struct property_set *pset,
129 const char *propname, size_t length)
130{
131 struct property_entry *prop;
132
133 prop = pset_prop_get(pset, propname);
134 if (!prop)
135 return -EINVAL;
136
137 return prop->length / length;
138}
139
140static int pset_prop_read_string_array(struct property_set *pset,
141 const char *propname,
142 const char **strings, size_t nval)
143{
144 void *pointer;
145 size_t length = nval * sizeof(*strings);
146
147 pointer = pset_prop_find(pset, propname, length);
148 if (IS_ERR(pointer))
149 return PTR_ERR(pointer);
150
151 memcpy(strings, pointer, length);
152 return 0;
153}
154
155static int pset_prop_read_string(struct property_set *pset,
156 const char *propname, const char **strings)
157{
158 struct property_entry *prop;
159 const char **pointer;
75 160
76 if (prop->type != type) 161 prop = pset_prop_get(pset, propname);
77 return -EPROTO; 162 if (!prop)
78
79 if (!val)
80 return prop->nval;
81
82 if (prop->nval < nval)
83 return -EOVERFLOW;
84
85 switch (type) {
86 case DEV_PROP_U8:
87 item_size = sizeof(u8);
88 break;
89 case DEV_PROP_U16:
90 item_size = sizeof(u16);
91 break;
92 case DEV_PROP_U32:
93 item_size = sizeof(u32);
94 break;
95 case DEV_PROP_U64:
96 item_size = sizeof(u64);
97 break;
98 case DEV_PROP_STRING:
99 item_size = sizeof(const char *);
100 break;
101 default:
102 return -EINVAL; 163 return -EINVAL;
164 if (!prop->is_string)
165 return -EILSEQ;
166 if (prop->is_array) {
167 pointer = prop->pointer.str;
168 if (!pointer)
169 return -ENODATA;
170 } else {
171 pointer = &prop->value.str;
172 if (*pointer && strnlen(*pointer, prop->length) >= prop->length)
173 return -EILSEQ;
103 } 174 }
104 memcpy(val, prop->value.raw_data, nval * item_size); 175
176 *strings = *pointer;
105 return 0; 177 return 0;
106} 178}
107 179
@@ -124,6 +196,18 @@ bool device_property_present(struct device *dev, const char *propname)
124} 196}
125EXPORT_SYMBOL_GPL(device_property_present); 197EXPORT_SYMBOL_GPL(device_property_present);
126 198
199static bool __fwnode_property_present(struct fwnode_handle *fwnode,
200 const char *propname)
201{
202 if (is_of_node(fwnode))
203 return of_property_read_bool(to_of_node(fwnode), propname);
204 else if (is_acpi_node(fwnode))
205 return !acpi_node_prop_get(fwnode, propname, NULL);
206 else if (is_pset_node(fwnode))
207 return !!pset_prop_get(to_pset_node(fwnode), propname);
208 return false;
209}
210
127/** 211/**
128 * fwnode_property_present - check if a property of a firmware node is present 212 * fwnode_property_present - check if a property of a firmware node is present
129 * @fwnode: Firmware node whose property to check 213 * @fwnode: Firmware node whose property to check
@@ -131,12 +215,12 @@ EXPORT_SYMBOL_GPL(device_property_present);
131 */ 215 */
132bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) 216bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
133{ 217{
134 if (is_of_node(fwnode)) 218 bool ret;
135 return of_property_read_bool(to_of_node(fwnode), propname);
136 else if (is_acpi_node(fwnode))
137 return !acpi_node_prop_get(fwnode, propname, NULL);
138 219
139 return !!pset_prop_get(to_pset(fwnode), propname); 220 ret = __fwnode_property_present(fwnode, propname);
221 if (ret == false && fwnode && fwnode->secondary)
222 ret = __fwnode_property_present(fwnode->secondary, propname);
223 return ret;
140} 224}
141EXPORT_SYMBOL_GPL(fwnode_property_present); 225EXPORT_SYMBOL_GPL(fwnode_property_present);
142 226
@@ -309,25 +393,40 @@ int device_property_match_string(struct device *dev, const char *propname,
309} 393}
310EXPORT_SYMBOL_GPL(device_property_match_string); 394EXPORT_SYMBOL_GPL(device_property_match_string);
311 395
312#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ 396#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
313 (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ 397 (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
314 : of_property_count_elems_of_size((node), (propname), sizeof(type)) 398 : of_property_count_elems_of_size((node), (propname), sizeof(type))
315 399
316#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ 400#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \
317({ \ 401 (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \
318 int _ret_; \ 402 : pset_prop_count_elems_of_size((node), (propname), sizeof(type))
319 if (is_of_node(_fwnode_)) \ 403
320 _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ 404#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
321 _type_, _val_, _nval_); \ 405({ \
322 else if (is_acpi_node(_fwnode_)) \ 406 int _ret_; \
323 _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ 407 if (is_of_node(_fwnode_)) \
324 _val_, _nval_); \ 408 _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \
325 else if (is_pset(_fwnode_)) \ 409 _type_, _val_, _nval_); \
326 _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ 410 else if (is_acpi_node(_fwnode_)) \
327 _proptype_, _val_, _nval_); \ 411 _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \
328 else \ 412 _val_, _nval_); \
329 _ret_ = -ENXIO; \ 413 else if (is_pset_node(_fwnode_)) \
330 _ret_; \ 414 _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \
415 _type_, _val_, _nval_); \
416 else \
417 _ret_ = -ENXIO; \
418 _ret_; \
419})
420
421#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
422({ \
423 int _ret_; \
424 _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \
425 _val_, _nval_); \
426 if (_ret_ == -EINVAL && _fwnode_ && _fwnode_->secondary) \
427 _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \
428 _proptype_, _val_, _nval_); \
429 _ret_; \
331}) 430})
332 431
333/** 432/**
@@ -434,6 +533,41 @@ int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
434} 533}
435EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); 534EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
436 535
536static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
537 const char *propname,
538 const char **val, size_t nval)
539{
540 if (is_of_node(fwnode))
541 return val ?
542 of_property_read_string_array(to_of_node(fwnode),
543 propname, val, nval) :
544 of_property_count_strings(to_of_node(fwnode), propname);
545 else if (is_acpi_node(fwnode))
546 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
547 val, nval);
548 else if (is_pset_node(fwnode))
549 return val ?
550 pset_prop_read_string_array(to_pset_node(fwnode),
551 propname, val, nval) :
552 pset_prop_count_elems_of_size(to_pset_node(fwnode),
553 propname,
554 sizeof(const char *));
555 return -ENXIO;
556}
557
558static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
559 const char *propname, const char **val)
560{
561 if (is_of_node(fwnode))
562 return of_property_read_string(to_of_node(fwnode), propname, val);
563 else if (is_acpi_node(fwnode))
564 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
565 val, 1);
566 else if (is_pset_node(fwnode))
567 return pset_prop_read_string(to_pset_node(fwnode), propname, val);
568 return -ENXIO;
569}
570
437/** 571/**
438 * fwnode_property_read_string_array - return string array property of a node 572 * fwnode_property_read_string_array - return string array property of a node
439 * @fwnode: Firmware node to get the property of 573 * @fwnode: Firmware node to get the property of
@@ -456,18 +590,13 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
456 const char *propname, const char **val, 590 const char *propname, const char **val,
457 size_t nval) 591 size_t nval)
458{ 592{
459 if (is_of_node(fwnode)) 593 int ret;
460 return val ? 594
461 of_property_read_string_array(to_of_node(fwnode), 595 ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
462 propname, val, nval) : 596 if (ret == -EINVAL && fwnode && fwnode->secondary)
463 of_property_count_strings(to_of_node(fwnode), propname); 597 ret = __fwnode_property_read_string_array(fwnode->secondary,
464 else if (is_acpi_node(fwnode)) 598 propname, val, nval);
465 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, 599 return ret;
466 val, nval);
467 else if (is_pset(fwnode))
468 return pset_prop_read_array(to_pset(fwnode), propname,
469 DEV_PROP_STRING, val, nval);
470 return -ENXIO;
471} 600}
472EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); 601EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
473 602
@@ -489,14 +618,13 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
489int fwnode_property_read_string(struct fwnode_handle *fwnode, 618int fwnode_property_read_string(struct fwnode_handle *fwnode,
490 const char *propname, const char **val) 619 const char *propname, const char **val)
491{ 620{
492 if (is_of_node(fwnode)) 621 int ret;
493 return of_property_read_string(to_of_node(fwnode), propname, val);
494 else if (is_acpi_node(fwnode))
495 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
496 val, 1);
497 622
498 return pset_prop_read_array(to_pset(fwnode), propname, 623 ret = __fwnode_property_read_string(fwnode, propname, val);
499 DEV_PROP_STRING, val, 1); 624 if (ret == -EINVAL && fwnode && fwnode->secondary)
625 ret = __fwnode_property_read_string(fwnode->secondary,
626 propname, val);
627 return ret;
500} 628}
501EXPORT_SYMBOL_GPL(fwnode_property_read_string); 629EXPORT_SYMBOL_GPL(fwnode_property_read_string);
502 630
@@ -525,6 +653,9 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode,
525 if (nval < 0) 653 if (nval < 0)
526 return nval; 654 return nval;
527 655
656 if (nval == 0)
657 return -ENODATA;
658
528 values = kcalloc(nval, sizeof(*values), GFP_KERNEL); 659 values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
529 if (!values) 660 if (!values)
530 return -ENOMEM; 661 return -ENOMEM;
@@ -547,6 +678,182 @@ out:
547EXPORT_SYMBOL_GPL(fwnode_property_match_string); 678EXPORT_SYMBOL_GPL(fwnode_property_match_string);
548 679
549/** 680/**
681 * pset_free_set - releases memory allocated for copied property set
682 * @pset: Property set to release
683 *
684 * Function takes previously copied property set and releases all the
685 * memory allocated to it.
686 */
687static void pset_free_set(struct property_set *pset)
688{
689 const struct property_entry *prop;
690 size_t i, nval;
691
692 if (!pset)
693 return;
694
695 for (prop = pset->properties; prop->name; prop++) {
696 if (prop->is_array) {
697 if (prop->is_string && prop->pointer.str) {
698 nval = prop->length / sizeof(const char *);
699 for (i = 0; i < nval; i++)
700 kfree(prop->pointer.str[i]);
701 }
702 kfree(prop->pointer.raw_data);
703 } else if (prop->is_string) {
704 kfree(prop->value.str);
705 }
706 kfree(prop->name);
707 }
708
709 kfree(pset->properties);
710 kfree(pset);
711}
712
713static int pset_copy_entry(struct property_entry *dst,
714 const struct property_entry *src)
715{
716 const char **d, **s;
717 size_t i, nval;
718
719 dst->name = kstrdup(src->name, GFP_KERNEL);
720 if (!dst->name)
721 return -ENOMEM;
722
723 if (src->is_array) {
724 if (!src->length)
725 return -ENODATA;
726
727 if (src->is_string) {
728 nval = src->length / sizeof(const char *);
729 dst->pointer.str = kcalloc(nval, sizeof(const char *),
730 GFP_KERNEL);
731 if (!dst->pointer.str)
732 return -ENOMEM;
733
734 d = dst->pointer.str;
735 s = src->pointer.str;
736 for (i = 0; i < nval; i++) {
737 d[i] = kstrdup(s[i], GFP_KERNEL);
738 if (!d[i] && s[i])
739 return -ENOMEM;
740 }
741 } else {
742 dst->pointer.raw_data = kmemdup(src->pointer.raw_data,
743 src->length, GFP_KERNEL);
744 if (!dst->pointer.raw_data)
745 return -ENOMEM;
746 }
747 } else if (src->is_string) {
748 dst->value.str = kstrdup(src->value.str, GFP_KERNEL);
749 if (!dst->value.str && src->value.str)
750 return -ENOMEM;
751 } else {
752 dst->value.raw_data = src->value.raw_data;
753 }
754
755 dst->length = src->length;
756 dst->is_array = src->is_array;
757 dst->is_string = src->is_string;
758
759 return 0;
760}
761
762/**
763 * pset_copy_set - copies property set
764 * @pset: Property set to copy
765 *
766 * This function takes a deep copy of the given property set and returns
767 * pointer to the copy. Call device_free_property_set() to free resources
768 * allocated in this function.
769 *
770 * Return: Pointer to the new property set or error pointer.
771 */
772static struct property_set *pset_copy_set(const struct property_set *pset)
773{
774 const struct property_entry *entry;
775 struct property_set *p;
776 size_t i, n = 0;
777
778 p = kzalloc(sizeof(*p), GFP_KERNEL);
779 if (!p)
780 return ERR_PTR(-ENOMEM);
781
782 while (pset->properties[n].name)
783 n++;
784
785 p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL);
786 if (!p->properties) {
787 kfree(p);
788 return ERR_PTR(-ENOMEM);
789 }
790
791 for (i = 0; i < n; i++) {
792 int ret = pset_copy_entry(&p->properties[i],
793 &pset->properties[i]);
794 if (ret) {
795 pset_free_set(p);
796 return ERR_PTR(ret);
797 }
798 }
799
800 return p;
801}
802
803/**
804 * device_remove_property_set - Remove properties from a device object.
805 * @dev: Device whose properties to remove.
806 *
807 * The function removes properties previously associated to the device
808 * secondary firmware node with device_add_property_set(). Memory allocated
809 * to the properties will also be released.
810 */
811void device_remove_property_set(struct device *dev)
812{
813 struct fwnode_handle *fwnode;
814
815 fwnode = dev_fwnode(dev);
816 if (!fwnode)
817 return;
818 /*
819 * Pick either primary or secondary node depending which one holds
820 * the pset. If there is no real firmware node (ACPI/DT) primary
821 * will hold the pset.
822 */
823 if (!is_pset_node(fwnode))
824 fwnode = fwnode->secondary;
825 if (!IS_ERR(fwnode) && is_pset_node(fwnode))
826 pset_free_set(to_pset_node(fwnode));
827 set_secondary_fwnode(dev, NULL);
828}
829EXPORT_SYMBOL_GPL(device_remove_property_set);
830
831/**
832 * device_add_property_set - Add a collection of properties to a device object.
833 * @dev: Device to add properties to.
834 * @pset: Collection of properties to add.
835 *
836 * Associate a collection of device properties represented by @pset with @dev
837 * as its secondary firmware node. The function takes a copy of @pset.
838 */
839int device_add_property_set(struct device *dev, const struct property_set *pset)
840{
841 struct property_set *p;
842
843 if (!pset)
844 return -EINVAL;
845
846 p = pset_copy_set(pset);
847 if (IS_ERR(p))
848 return PTR_ERR(p);
849
850 p->fwnode.type = FWNODE_PDATA;
851 set_secondary_fwnode(dev, &p->fwnode);
852 return 0;
853}
854EXPORT_SYMBOL_GPL(device_add_property_set);
855
856/**
550 * device_get_next_child_node - Return the next child node handle for a device 857 * device_get_next_child_node - Return the next child node handle for a device
551 * @dev: Device to find the next child node for. 858 * @dev: Device to find the next child node for.
552 * @child: Handle to one of the device's child nodes or a null handle. 859 * @child: Handle to one of the device's child nodes or a null handle.