diff options
| -rw-r--r-- | drivers/base/property.c | 104 | ||||
| -rw-r--r-- | drivers/firmware/efi/apple-properties.c | 8 | ||||
| -rw-r--r-- | include/linux/property.h | 52 |
3 files changed, 117 insertions, 47 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c index 8f205f6461ed..240ab5230ff6 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c | |||
| @@ -56,6 +56,72 @@ pset_prop_get(const struct property_set *pset, const char *name) | |||
| 56 | return NULL; | 56 | return NULL; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static const void *property_get_pointer(const struct property_entry *prop) | ||
| 60 | { | ||
| 61 | switch (prop->type) { | ||
| 62 | case DEV_PROP_U8: | ||
| 63 | if (prop->is_array) | ||
| 64 | return prop->pointer.u8_data; | ||
| 65 | return &prop->value.u8_data; | ||
| 66 | case DEV_PROP_U16: | ||
| 67 | if (prop->is_array) | ||
| 68 | return prop->pointer.u16_data; | ||
| 69 | return &prop->value.u16_data; | ||
| 70 | case DEV_PROP_U32: | ||
| 71 | if (prop->is_array) | ||
| 72 | return prop->pointer.u32_data; | ||
| 73 | return &prop->value.u32_data; | ||
| 74 | case DEV_PROP_U64: | ||
| 75 | if (prop->is_array) | ||
| 76 | return prop->pointer.u64_data; | ||
| 77 | return &prop->value.u64_data; | ||
| 78 | case DEV_PROP_STRING: | ||
| 79 | if (prop->is_array) | ||
| 80 | return prop->pointer.str; | ||
| 81 | return &prop->value.str; | ||
| 82 | default: | ||
| 83 | return NULL; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | static void property_set_pointer(struct property_entry *prop, const void *pointer) | ||
| 88 | { | ||
| 89 | switch (prop->type) { | ||
| 90 | case DEV_PROP_U8: | ||
| 91 | if (prop->is_array) | ||
| 92 | prop->pointer.u8_data = pointer; | ||
| 93 | else | ||
| 94 | prop->value.u8_data = *((u8 *)pointer); | ||
| 95 | break; | ||
| 96 | case DEV_PROP_U16: | ||
| 97 | if (prop->is_array) | ||
| 98 | prop->pointer.u16_data = pointer; | ||
| 99 | else | ||
| 100 | prop->value.u16_data = *((u16 *)pointer); | ||
| 101 | break; | ||
| 102 | case DEV_PROP_U32: | ||
| 103 | if (prop->is_array) | ||
| 104 | prop->pointer.u32_data = pointer; | ||
| 105 | else | ||
| 106 | prop->value.u32_data = *((u32 *)pointer); | ||
| 107 | break; | ||
| 108 | case DEV_PROP_U64: | ||
| 109 | if (prop->is_array) | ||
| 110 | prop->pointer.u64_data = pointer; | ||
| 111 | else | ||
| 112 | prop->value.u64_data = *((u64 *)pointer); | ||
| 113 | break; | ||
| 114 | case DEV_PROP_STRING: | ||
| 115 | if (prop->is_array) | ||
| 116 | prop->pointer.str = pointer; | ||
| 117 | else | ||
| 118 | prop->value.str = pointer; | ||
| 119 | break; | ||
| 120 | default: | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 59 | static const void *pset_prop_find(const struct property_set *pset, | 125 | static const void *pset_prop_find(const struct property_set *pset, |
| 60 | const char *propname, size_t length) | 126 | const char *propname, size_t length) |
| 61 | { | 127 | { |
| @@ -65,10 +131,7 @@ static const void *pset_prop_find(const struct property_set *pset, | |||
| 65 | prop = pset_prop_get(pset, propname); | 131 | prop = pset_prop_get(pset, propname); |
| 66 | if (!prop) | 132 | if (!prop) |
| 67 | return ERR_PTR(-EINVAL); | 133 | return ERR_PTR(-EINVAL); |
| 68 | if (prop->is_array) | 134 | pointer = property_get_pointer(prop); |
| 69 | pointer = prop->pointer.raw_data; | ||
| 70 | else | ||
| 71 | pointer = &prop->value.raw_data; | ||
| 72 | if (!pointer) | 135 | if (!pointer) |
| 73 | return ERR_PTR(-ENODATA); | 136 | return ERR_PTR(-ENODATA); |
| 74 | if (length > prop->length) | 137 | if (length > prop->length) |
| @@ -698,16 +761,17 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); | |||
| 698 | 761 | ||
| 699 | static void property_entry_free_data(const struct property_entry *p) | 762 | static void property_entry_free_data(const struct property_entry *p) |
| 700 | { | 763 | { |
| 764 | const void *pointer = property_get_pointer(p); | ||
| 701 | size_t i, nval; | 765 | size_t i, nval; |
| 702 | 766 | ||
| 703 | if (p->is_array) { | 767 | if (p->is_array) { |
| 704 | if (p->is_string && p->pointer.str) { | 768 | if (p->type == DEV_PROP_STRING && p->pointer.str) { |
| 705 | nval = p->length / sizeof(const char *); | 769 | nval = p->length / sizeof(const char *); |
| 706 | for (i = 0; i < nval; i++) | 770 | for (i = 0; i < nval; i++) |
| 707 | kfree(p->pointer.str[i]); | 771 | kfree(p->pointer.str[i]); |
| 708 | } | 772 | } |
| 709 | kfree(p->pointer.raw_data); | 773 | kfree(pointer); |
| 710 | } else if (p->is_string) { | 774 | } else if (p->type == DEV_PROP_STRING) { |
| 711 | kfree(p->value.str); | 775 | kfree(p->value.str); |
| 712 | } | 776 | } |
| 713 | kfree(p->name); | 777 | kfree(p->name); |
| @@ -716,7 +780,7 @@ static void property_entry_free_data(const struct property_entry *p) | |||
| 716 | static int property_copy_string_array(struct property_entry *dst, | 780 | static int property_copy_string_array(struct property_entry *dst, |
| 717 | const struct property_entry *src) | 781 | const struct property_entry *src) |
| 718 | { | 782 | { |
| 719 | char **d; | 783 | const char **d; |
| 720 | size_t nval = src->length / sizeof(*d); | 784 | size_t nval = src->length / sizeof(*d); |
| 721 | int i; | 785 | int i; |
| 722 | 786 | ||
| @@ -734,40 +798,44 @@ static int property_copy_string_array(struct property_entry *dst, | |||
| 734 | } | 798 | } |
| 735 | } | 799 | } |
| 736 | 800 | ||
| 737 | dst->pointer.raw_data = d; | 801 | dst->pointer.str = d; |
| 738 | return 0; | 802 | return 0; |
| 739 | } | 803 | } |
| 740 | 804 | ||
| 741 | static int property_entry_copy_data(struct property_entry *dst, | 805 | static int property_entry_copy_data(struct property_entry *dst, |
| 742 | const struct property_entry *src) | 806 | const struct property_entry *src) |
| 743 | { | 807 | { |
| 808 | const void *pointer = property_get_pointer(src); | ||
| 809 | const void *new; | ||
| 744 | int error; | 810 | int error; |
| 745 | 811 | ||
| 746 | if (src->is_array) { | 812 | if (src->is_array) { |
| 747 | if (!src->length) | 813 | if (!src->length) |
| 748 | return -ENODATA; | 814 | return -ENODATA; |
| 749 | 815 | ||
| 750 | if (src->is_string) { | 816 | if (src->type == DEV_PROP_STRING) { |
| 751 | error = property_copy_string_array(dst, src); | 817 | error = property_copy_string_array(dst, src); |
| 752 | if (error) | 818 | if (error) |
| 753 | return error; | 819 | return error; |
| 820 | new = dst->pointer.str; | ||
| 754 | } else { | 821 | } else { |
| 755 | dst->pointer.raw_data = kmemdup(src->pointer.raw_data, | 822 | new = kmemdup(pointer, src->length, GFP_KERNEL); |
| 756 | src->length, GFP_KERNEL); | 823 | if (!new) |
| 757 | if (!dst->pointer.raw_data) | ||
| 758 | return -ENOMEM; | 824 | return -ENOMEM; |
| 759 | } | 825 | } |
| 760 | } else if (src->is_string) { | 826 | } else if (src->type == DEV_PROP_STRING) { |
| 761 | dst->value.str = kstrdup(src->value.str, GFP_KERNEL); | 827 | new = kstrdup(src->value.str, GFP_KERNEL); |
| 762 | if (!dst->value.str && src->value.str) | 828 | if (!new && src->value.str) |
| 763 | return -ENOMEM; | 829 | return -ENOMEM; |
| 764 | } else { | 830 | } else { |
| 765 | dst->value.raw_data = src->value.raw_data; | 831 | new = pointer; |
| 766 | } | 832 | } |
| 767 | 833 | ||
| 768 | dst->length = src->length; | 834 | dst->length = src->length; |
| 769 | dst->is_array = src->is_array; | 835 | dst->is_array = src->is_array; |
| 770 | dst->is_string = src->is_string; | 836 | dst->type = src->type; |
| 837 | |||
| 838 | property_set_pointer(dst, new); | ||
| 771 | 839 | ||
| 772 | dst->name = kstrdup(src->name, GFP_KERNEL); | 840 | dst->name = kstrdup(src->name, GFP_KERNEL); |
| 773 | if (!dst->name) | 841 | if (!dst->name) |
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index adaa9a3714b9..60a95719ecb8 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c | |||
| @@ -13,6 +13,9 @@ | |||
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * | ||
| 17 | * Note, all properties are considered as u8 arrays. | ||
| 18 | * To get a value of any of them the caller must use device_property_read_u8_array(). | ||
| 16 | */ | 19 | */ |
| 17 | 20 | ||
| 18 | #define pr_fmt(fmt) "apple-properties: " fmt | 21 | #define pr_fmt(fmt) "apple-properties: " fmt |
| @@ -96,12 +99,13 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, | |||
| 96 | entry[i].name = key; | 99 | entry[i].name = key; |
| 97 | entry[i].length = val_len - sizeof(val_len); | 100 | entry[i].length = val_len - sizeof(val_len); |
| 98 | entry[i].is_array = !!entry[i].length; | 101 | entry[i].is_array = !!entry[i].length; |
| 99 | entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len); | 102 | entry[i].type = DEV_PROP_U8; |
| 103 | entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len); | ||
| 100 | 104 | ||
| 101 | if (dump_properties) { | 105 | if (dump_properties) { |
| 102 | dev_info(dev, "property: %s\n", entry[i].name); | 106 | dev_info(dev, "property: %s\n", entry[i].name); |
| 103 | print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, | 107 | print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, |
| 104 | 16, 1, entry[i].pointer.raw_data, | 108 | 16, 1, entry[i].pointer.u8_data, |
| 105 | entry[i].length, true); | 109 | entry[i].length, true); |
| 106 | } | 110 | } |
| 107 | 111 | ||
diff --git a/include/linux/property.h b/include/linux/property.h index 2eea4b310fc2..ac8a1ebc4c1b 100644 --- a/include/linux/property.h +++ b/include/linux/property.h | |||
| @@ -178,7 +178,7 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode, | |||
| 178 | * @name: Name of the property. | 178 | * @name: Name of the property. |
| 179 | * @length: Length of data making up the value. | 179 | * @length: Length of data making up the value. |
| 180 | * @is_array: True when the property is an array. | 180 | * @is_array: True when the property is an array. |
| 181 | * @is_string: True when property is a string. | 181 | * @type: Type of the data in unions. |
| 182 | * @pointer: Pointer to the property (an array of items of the given type). | 182 | * @pointer: Pointer to the property (an array of items of the given type). |
| 183 | * @value: Value of the property (when it is a single item of the given type). | 183 | * @value: Value of the property (when it is a single item of the given type). |
| 184 | */ | 184 | */ |
| @@ -186,10 +186,9 @@ struct property_entry { | |||
| 186 | const char *name; | 186 | const char *name; |
| 187 | size_t length; | 187 | size_t length; |
| 188 | bool is_array; | 188 | bool is_array; |
| 189 | bool is_string; | 189 | enum dev_prop_type type; |
| 190 | union { | 190 | union { |
| 191 | union { | 191 | union { |
| 192 | const void *raw_data; | ||
| 193 | const u8 *u8_data; | 192 | const u8 *u8_data; |
| 194 | const u16 *u16_data; | 193 | const u16 *u16_data; |
| 195 | const u32 *u32_data; | 194 | const u32 *u32_data; |
| @@ -197,7 +196,6 @@ struct property_entry { | |||
| 197 | const char * const *str; | 196 | const char * const *str; |
| 198 | } pointer; | 197 | } pointer; |
| 199 | union { | 198 | union { |
| 200 | unsigned long long raw_data; | ||
| 201 | u8 u8_data; | 199 | u8 u8_data; |
| 202 | u16 u16_data; | 200 | u16 u16_data; |
| 203 | u32 u32_data; | 201 | u32 u32_data; |
| @@ -213,55 +211,55 @@ struct property_entry { | |||
| 213 | * and structs. | 211 | * and structs. |
| 214 | */ | 212 | */ |
| 215 | 213 | ||
| 216 | #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ | 214 | #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_) \ |
| 217 | (struct property_entry) { \ | 215 | (struct property_entry) { \ |
| 218 | .name = _name_, \ | 216 | .name = _name_, \ |
| 219 | .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ | 217 | .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ |
| 220 | .is_array = true, \ | 218 | .is_array = true, \ |
| 221 | .is_string = false, \ | 219 | .type = DEV_PROP_##_Type_, \ |
| 222 | { .pointer = { ._type_##_data = _val_ } }, \ | 220 | { .pointer = { ._type_##_data = _val_ } }, \ |
| 223 | } | 221 | } |
| 224 | 222 | ||
| 225 | #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ | 223 | #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ |
| 226 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) | 224 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_) |
| 227 | #define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ | 225 | #define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ |
| 228 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) | 226 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_) |
| 229 | #define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ | 227 | #define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ |
| 230 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) | 228 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_) |
| 231 | #define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ | 229 | #define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ |
| 232 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) | 230 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_) |
| 233 | 231 | ||
| 234 | #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ | 232 | #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ |
| 235 | (struct property_entry) { \ | 233 | (struct property_entry) { \ |
| 236 | .name = _name_, \ | 234 | .name = _name_, \ |
| 237 | .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ | 235 | .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ |
| 238 | .is_array = true, \ | 236 | .is_array = true, \ |
| 239 | .is_string = true, \ | 237 | .type = DEV_PROP_STRING, \ |
| 240 | { .pointer = { .str = _val_ } }, \ | 238 | { .pointer = { .str = _val_ } }, \ |
| 241 | } | 239 | } |
| 242 | 240 | ||
| 243 | #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ | 241 | #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \ |
| 244 | (struct property_entry) { \ | 242 | (struct property_entry) { \ |
| 245 | .name = _name_, \ | 243 | .name = _name_, \ |
| 246 | .length = sizeof(_type_), \ | 244 | .length = sizeof(_type_), \ |
| 247 | .is_string = false, \ | 245 | .type = DEV_PROP_##_Type_, \ |
| 248 | { .value = { ._type_##_data = _val_ } }, \ | 246 | { .value = { ._type_##_data = _val_ } }, \ |
| 249 | } | 247 | } |
| 250 | 248 | ||
| 251 | #define PROPERTY_ENTRY_U8(_name_, _val_) \ | 249 | #define PROPERTY_ENTRY_U8(_name_, _val_) \ |
| 252 | PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) | 250 | PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_) |
| 253 | #define PROPERTY_ENTRY_U16(_name_, _val_) \ | 251 | #define PROPERTY_ENTRY_U16(_name_, _val_) \ |
| 254 | PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) | 252 | PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_) |
| 255 | #define PROPERTY_ENTRY_U32(_name_, _val_) \ | 253 | #define PROPERTY_ENTRY_U32(_name_, _val_) \ |
| 256 | PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) | 254 | PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_) |
| 257 | #define PROPERTY_ENTRY_U64(_name_, _val_) \ | 255 | #define PROPERTY_ENTRY_U64(_name_, _val_) \ |
| 258 | PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) | 256 | PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_) |
| 259 | 257 | ||
| 260 | #define PROPERTY_ENTRY_STRING(_name_, _val_) \ | 258 | #define PROPERTY_ENTRY_STRING(_name_, _val_) \ |
| 261 | (struct property_entry) { \ | 259 | (struct property_entry) { \ |
| 262 | .name = _name_, \ | 260 | .name = _name_, \ |
| 263 | .length = sizeof(_val_), \ | 261 | .length = sizeof(_val_), \ |
| 264 | .is_string = true, \ | 262 | .type = DEV_PROP_STRING, \ |
| 265 | { .value = { .str = _val_ } }, \ | 263 | { .value = { .str = _val_ } }, \ |
| 266 | } | 264 | } |
| 267 | 265 | ||
