diff options
| -rw-r--r-- | drivers/base/property.c | 98 | ||||
| -rw-r--r-- | include/linux/fwnode.h | 1 | ||||
| -rw-r--r-- | include/linux/property.h | 33 |
3 files changed, 127 insertions, 5 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c index 62787bc89a1d..6a3f7d8af341 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c | |||
| @@ -10,10 +10,96 @@ | |||
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/property.h> | ||
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
| 14 | #include <linux/export.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
| 17 | #include <linux/property.h> | ||
| 18 | |||
| 19 | /** | ||
| 20 | * device_add_property_set - Add a collection of properties to a device object. | ||
| 21 | * @dev: Device to add properties to. | ||
| 22 | * @pset: Collection of properties to add. | ||
| 23 | * | ||
| 24 | * Associate a collection of device properties represented by @pset with @dev | ||
| 25 | * as its secondary firmware node. | ||
| 26 | */ | ||
| 27 | void device_add_property_set(struct device *dev, struct property_set *pset) | ||
| 28 | { | ||
| 29 | if (pset) | ||
| 30 | pset->fwnode.type = FWNODE_PDATA; | ||
| 31 | |||
| 32 | set_secondary_fwnode(dev, &pset->fwnode); | ||
| 33 | } | ||
| 34 | EXPORT_SYMBOL_GPL(device_add_property_set); | ||
| 35 | |||
| 36 | static inline bool is_pset(struct fwnode_handle *fwnode) | ||
| 37 | { | ||
| 38 | return fwnode && fwnode->type == FWNODE_PDATA; | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline struct property_set *to_pset(struct fwnode_handle *fwnode) | ||
| 42 | { | ||
| 43 | return is_pset(fwnode) ? | ||
| 44 | container_of(fwnode, struct property_set, fwnode) : NULL; | ||
| 45 | } | ||
| 46 | |||
| 47 | static struct property_entry *pset_prop_get(struct property_set *pset, | ||
| 48 | const char *name) | ||
| 49 | { | ||
| 50 | struct property_entry *prop; | ||
| 51 | |||
| 52 | if (!pset || !pset->properties) | ||
| 53 | return NULL; | ||
| 54 | |||
| 55 | for (prop = pset->properties; prop->name; prop++) | ||
| 56 | if (!strcmp(name, prop->name)) | ||
| 57 | return prop; | ||
| 58 | |||
| 59 | return NULL; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int pset_prop_read_array(struct property_set *pset, const char *name, | ||
| 63 | enum dev_prop_type type, void *val, size_t nval) | ||
| 64 | { | ||
| 65 | struct property_entry *prop; | ||
| 66 | unsigned int item_size; | ||
| 67 | |||
| 68 | prop = pset_prop_get(pset, name); | ||
| 69 | if (!prop) | ||
| 70 | return -ENODATA; | ||
| 71 | |||
| 72 | if (prop->type != type) | ||
| 73 | return -EPROTO; | ||
| 74 | |||
| 75 | if (!val) | ||
| 76 | return prop->nval; | ||
| 77 | |||
| 78 | if (prop->nval < nval) | ||
| 79 | return -EOVERFLOW; | ||
| 80 | |||
| 81 | switch (type) { | ||
| 82 | case DEV_PROP_U8: | ||
| 83 | item_size = sizeof(u8); | ||
| 84 | break; | ||
| 85 | case DEV_PROP_U16: | ||
| 86 | item_size = sizeof(u16); | ||
| 87 | break; | ||
| 88 | case DEV_PROP_U32: | ||
| 89 | item_size = sizeof(u32); | ||
| 90 | break; | ||
| 91 | case DEV_PROP_U64: | ||
| 92 | item_size = sizeof(u64); | ||
| 93 | break; | ||
| 94 | case DEV_PROP_STRING: | ||
| 95 | item_size = sizeof(const char *); | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | return -EINVAL; | ||
| 99 | } | ||
| 100 | memcpy(val, prop->value.raw_data, nval * item_size); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 17 | 103 | ||
| 18 | static inline struct fwnode_handle *dev_fwnode(struct device *dev) | 104 | static inline struct fwnode_handle *dev_fwnode(struct device *dev) |
| 19 | { | 105 | { |
| @@ -46,7 +132,7 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) | |||
| 46 | else if (is_acpi_node(fwnode)) | 132 | else if (is_acpi_node(fwnode)) |
| 47 | return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); | 133 | return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); |
| 48 | 134 | ||
| 49 | return false; | 135 | return !!pset_prop_get(to_pset(fwnode), propname); |
| 50 | } | 136 | } |
| 51 | EXPORT_SYMBOL_GPL(fwnode_property_present); | 137 | EXPORT_SYMBOL_GPL(fwnode_property_present); |
| 52 | 138 | ||
| @@ -205,7 +291,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string); | |||
| 205 | _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ | 291 | _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ |
| 206 | _proptype_, _val_, _nval_); \ | 292 | _proptype_, _val_, _nval_); \ |
| 207 | else \ | 293 | else \ |
| 208 | _ret_ = -ENXIO; \ | 294 | _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ |
| 295 | _proptype_, _val_, _nval_); \ | ||
| 209 | _ret_; \ | 296 | _ret_; \ |
| 210 | }) | 297 | }) |
| 211 | 298 | ||
| @@ -344,7 +431,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, | |||
| 344 | return acpi_dev_prop_read(acpi_node(fwnode), propname, | 431 | return acpi_dev_prop_read(acpi_node(fwnode), propname, |
| 345 | DEV_PROP_STRING, val, nval); | 432 | DEV_PROP_STRING, val, nval); |
| 346 | 433 | ||
| 347 | return -ENXIO; | 434 | return pset_prop_read_array(to_pset(fwnode), propname, |
| 435 | DEV_PROP_STRING, val, nval); | ||
| 348 | } | 436 | } |
| 349 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | 437 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); |
| 350 | 438 | ||
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index fc30b84b532a..0408545bce42 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h | |||
| @@ -16,6 +16,7 @@ enum fwnode_type { | |||
| 16 | FWNODE_INVALID = 0, | 16 | FWNODE_INVALID = 0, |
| 17 | FWNODE_OF, | 17 | FWNODE_OF, |
| 18 | FWNODE_ACPI, | 18 | FWNODE_ACPI, |
| 19 | FWNODE_PDATA, | ||
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 21 | struct fwnode_handle { | 22 | struct fwnode_handle { |
diff --git a/include/linux/property.h b/include/linux/property.h index 31dfd3db35d6..de8bdf417a35 100644 --- a/include/linux/property.h +++ b/include/linux/property.h | |||
| @@ -131,4 +131,37 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, | |||
| 131 | return fwnode_property_read_u64_array(fwnode, propname, val, 1); | 131 | return fwnode_property_read_u64_array(fwnode, propname, val, 1); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | /** | ||
| 135 | * struct property_entry - "Built-in" device property representation. | ||
| 136 | * @name: Name of the property. | ||
| 137 | * @type: Type of the property. | ||
| 138 | * @nval: Number of items of type @type making up the value. | ||
| 139 | * @value: Value of the property (an array of @nval items of type @type). | ||
| 140 | */ | ||
| 141 | struct property_entry { | ||
| 142 | const char *name; | ||
| 143 | enum dev_prop_type type; | ||
| 144 | size_t nval; | ||
| 145 | union { | ||
| 146 | void *raw_data; | ||
| 147 | u8 *u8_data; | ||
| 148 | u16 *u16_data; | ||
| 149 | u32 *u32_data; | ||
| 150 | u64 *u64_data; | ||
| 151 | const char **str; | ||
| 152 | } value; | ||
| 153 | }; | ||
| 154 | |||
| 155 | /** | ||
| 156 | * struct property_set - Collection of "built-in" device properties. | ||
| 157 | * @fwnode: Handle to be pointed to by the fwnode field of struct device. | ||
| 158 | * @properties: Array of properties terminated with a null entry. | ||
| 159 | */ | ||
| 160 | struct property_set { | ||
| 161 | struct fwnode_handle fwnode; | ||
| 162 | struct property_entry *properties; | ||
| 163 | }; | ||
| 164 | |||
| 165 | void device_add_property_set(struct device *dev, struct property_set *pset); | ||
| 166 | |||
| 134 | #endif /* _LINUX_PROPERTY_H_ */ | 167 | #endif /* _LINUX_PROPERTY_H_ */ |
