From 45204ebce7219dc786de5b07b0341360321177a7 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 15 Jun 2015 15:29:05 +0200 Subject: state: uint8: use %u as format string Cc: Jan Luebbe Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- common/state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/state.c b/common/state.c index 7076f5764d..e30f726607 100644 --- a/common/state.c +++ b/common/state.c @@ -172,7 +172,7 @@ static struct state_variable *state_uint8_create(struct state *state, su32 = xzalloc(sizeof(*su32)); param = dev_add_param_int(&state->dev, name, state_set_dirty, - NULL, &su32->value, "%d", state); + NULL, &su32->value, "%u", state); if (IS_ERR(param)) { free(su32); return ERR_CAST(param); -- cgit v1.2.3 From 23c1e105b554384f16ae6b6b29a1296183254620 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 15 Jun 2015 15:29:06 +0200 Subject: state: uint8: add range check for uint8 Bail out, if the user tries to set a value > 255. Cc: Jan Luebbe Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- common/state.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/common/state.c b/common/state.c index e30f726607..8fa027a847 100644 --- a/common/state.c +++ b/common/state.c @@ -113,6 +113,7 @@ static int state_set_dirty(struct param_d *p, void *priv) struct state_uint32 { struct state_variable var; struct param_d *param; + struct state *state; uint32_t value; uint32_t value_default; }; @@ -163,6 +164,17 @@ static int state_uint32_import(struct state_variable *sv, return 0; } +static int state_uint8_set(struct param_d *p, void *priv) +{ + struct state_uint32 *su32 = priv; + struct state *state = su32->state; + + if (su32->value > 255) + return -ERANGE; + + return state_set_dirty(p, state); +} + static struct state_variable *state_uint8_create(struct state *state, const char *name, struct device_node *node) { @@ -171,8 +183,8 @@ static struct state_variable *state_uint8_create(struct state *state, su32 = xzalloc(sizeof(*su32)); - param = dev_add_param_int(&state->dev, name, state_set_dirty, - NULL, &su32->value, "%u", state); + param = dev_add_param_int(&state->dev, name, state_uint8_set, + NULL, &su32->value, "%u", su32); if (IS_ERR(param)) { free(su32); return ERR_CAST(param); @@ -185,6 +197,7 @@ static struct state_variable *state_uint8_create(struct state *state, #else su32->var.raw = &su32->value + 3; #endif + su32->state = state; return &su32->var; } -- cgit v1.2.3 From 48751b1aa94ad2dd40e06a7d6a89fb9e786d9cf7 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 17 Jun 2015 22:47:00 +0200 Subject: parameter: allow setting of string parameters of zero length Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- lib/parameter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parameter.c b/lib/parameter.c index 865ad9f431..09559b637e 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -225,7 +225,7 @@ static int param_string_set(struct device_d *dev, struct param_d *p, const char char *value_save = *ps->value; if (!val) - return -EINVAL; + val = ""; *ps->value = xstrdup(val); -- cgit v1.2.3 From daeb9d8d76e353eaee45545e8f4e83df92af035c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 17 Jun 2015 22:47:01 +0200 Subject: xfuncs: import xstrndup() from busybox This function is needed for the fixed length string feature in the state framework. Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- include/xfuncs.h | 1 + lib/xfuncs.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/xfuncs.h b/include/xfuncs.h index 8efc99dbc4..940a1d67ed 100644 --- a/include/xfuncs.h +++ b/include/xfuncs.h @@ -7,6 +7,7 @@ void *xmalloc(size_t size); void *xrealloc(void *ptr, size_t size); void *xzalloc(size_t size); char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t size); void* xmemalign(size_t alignment, size_t bytes); void* xmemdup(const void *orig, size_t size); diff --git a/lib/xfuncs.c b/lib/xfuncs.c index 0e78b670a5..f0219c43a5 100644 --- a/lib/xfuncs.c +++ b/lib/xfuncs.c @@ -63,6 +63,28 @@ char *xstrdup(const char *s) } EXPORT_SYMBOL(xstrdup); +char *xstrndup(const char *s, size_t n) +{ + int m; + char *t; + + /* We can just xmalloc(n+1) and strncpy into it, */ + /* but think about xstrndup("abc", 10000) wastage! */ + m = n; + t = (char*) s; + while (m) { + if (!*t) break; + m--; + t++; + } + n -= m; + t = xmalloc(n + 1); + t[n] = '\0'; + + return memcpy(t, s, n); +} +EXPORT_SYMBOL(xstrndup); + void* xmemalign(size_t alignment, size_t bytes) { void *p = memalign(alignment, bytes); -- cgit v1.2.3 From 69cec37e2c9992f622d476ebed3522429b111c29 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 17 Jun 2015 22:47:02 +0200 Subject: state: struct variable_type::import: remove const from node argument This patch removes the const qualifier of the node argument from struct variable_type::import. This is a preparation patch to support fixed strings in state. Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- common/state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/state.c b/common/state.c index 8fa027a847..8a7a7680bc 100644 --- a/common/state.c +++ b/common/state.c @@ -90,7 +90,7 @@ struct variable_type { struct list_head list; int (*export)(struct state_variable *, struct device_node *, enum state_convert); - int (*import)(struct state_variable *, const struct device_node *); + int (*import)(struct state_variable *, struct device_node *); struct state_variable *(*create)(struct state *state, const char *name, struct device_node *); }; @@ -153,7 +153,7 @@ static int state_uint32_export(struct state_variable *var, } static int state_uint32_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_uint32 *su32 = to_state_uint32(sv); @@ -278,7 +278,7 @@ static int state_enum32_export(struct state_variable *var, } static int state_enum32_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_enum32 *enum32 = to_state_enum32(sv); int len; @@ -373,7 +373,7 @@ static int state_mac_export(struct state_variable *var, } static int state_mac_import(struct state_variable *sv, - const struct device_node *node) + struct device_node *node) { struct state_mac *mac = to_state_mac(sv); -- cgit v1.2.3 From 9116aba49aed0bdb909419b9d9f8472effda40df Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 17 Jun 2015 22:47:03 +0200 Subject: state: add support for fixed length strings Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- .../devicetree/bindings/barebox/barebox,state.rst | 19 ++- common/state.c | 152 +++++++++++++++++++++ 2 files changed, 167 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index 3d664f1f02..4c5b06db47 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -40,8 +40,8 @@ variable. The node name may end with ``@
``, but the suffix is sripped from the variable name. State variables have a type. Currenty supported types are: ``uint8``, -``uint32``, ``enum32`` and ``mac`` address. Fixed length strings are -planned but not implemented. Variable length strings are not planned. +``uint32``, ``enum32``, ``mac`` address or ``string``. Variable length +strings are not planned. Required properties: @@ -49,8 +49,8 @@ Required properties: ``#size-cells = <1>``. Defines the ``offset`` and ``size`` of the variable in the ``raw`` backend. ``size`` must fit the node ``type``. Variables are not allowed to overlap. -* ``type``: Should be ``uint8``, ``uint32``, ``enum32`` or ``mac`` for - the type of the variable +* ``type``: Should be ``uint8``, ``uint32``, ``enum32``, ``mac`` or + ``string`` for the type of the variable * ``names``: For ``enum32`` values only, this specifies the values possible for ``enum32``. @@ -82,6 +82,17 @@ Example:: }; }; +Variable Types +-------------- + +* ``uint8``: +* ``uint32``: +* ``enum32``: The ``default`` value is an integer representing an + offset into the names array. +* ``mac``: +* ``string``: The length of the string excluding the trailing 0 is + determined by the length given in the ``reg`` property. + Backends -------- diff --git a/common/state.c b/common/state.c index 8a7a7680bc..b3e1bdf342 100644 --- a/common/state.c +++ b/common/state.c @@ -64,6 +64,7 @@ enum state_variable_type { STATE_TYPE_U8, STATE_TYPE_U32, STATE_TYPE_MAC, + STATE_TYPE_STRING, }; /* instance of a single variable */ @@ -410,6 +411,151 @@ out: return ERR_PTR(ret); } +/* + * string + */ +struct state_string { + struct state_variable var; + struct param_d *param; + struct state *state; + char *value; + const char *value_default; + char raw[]; +}; + +static inline struct state_string *to_state_string(struct state_variable *s) +{ + return container_of(s, struct state_string, var); +} + +static int state_string_export(struct state_variable *var, + struct device_node *node, enum state_convert conv) +{ + struct state_string *string = to_state_string(var); + int ret = 0; + + if (string->value_default) { + ret = of_set_property(node, "default", string->value_default, + strlen(string->value_default) + 1, 1); + + if (ret) + return ret; + } + + if (conv == STATE_CONVERT_FIXUP) + return 0; + + if (string->value) + ret = of_set_property(node, "value", string->value, + strlen(string->value) + 1, 1); + + return ret; +} + +static int state_string_copy_to_raw(struct state_string *string, + const char *src) +{ + size_t len; + + len = strlen(src); + if (len > string->var.size) + return -EILSEQ; + + /* copy string and clear remaining contents of buffer */ + memcpy(string->raw, src, len); + memset(string->raw + len, 0x0, string->var.size - len); + + return 0; +} + +static int state_string_import(struct state_variable *sv, + struct device_node *node) +{ + struct state_string *string = to_state_string(sv); + const char *value = NULL; + size_t len; + int ret; + + of_property_read_string(node, "default", &string->value_default); + if (string->value_default) { + len = strlen(string->value_default); + if (len > string->var.size) + return -EILSEQ; + } + + ret = of_property_read_string(node, "value", &value); + if (ret) + value = string->value_default; + + if (value) + return state_string_copy_to_raw(string, value); + + return 0; +} + +static int state_string_set(struct param_d *p, void *priv) +{ + struct state_string *string = priv; + struct state *state = string->state; + int ret; + + ret = state_string_copy_to_raw(string, string->value); + if (ret) + return ret; + + return state_set_dirty(p, state); +} + +static int state_string_get(struct param_d *p, void *priv) +{ + struct state_string *string = priv; + + free(string->value); + if (string->raw[0]) + string->value = xstrndup(string->raw, string->var.size); + else + string->value = xstrdup(""); + + return 0; +} + +static struct state_variable *state_string_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_string *string; + u32 start_size[2]; + int ret; + + ret = of_property_read_u32_array(node, "reg", start_size, + ARRAY_SIZE(start_size)); + if (ret) { + dev_err(&state->dev, + "%s: reg property not found\n", name); + return ERR_PTR(ret); + } + + /* limit to arbitrary len of 4k */ + if (start_size[1] > 4096) + return ERR_PTR(-EILSEQ); + + string = xzalloc(sizeof(*string) + start_size[1]); + string->var.size = start_size[1]; + string->var.raw = &string->raw; + string->state = state; + + string->param = dev_add_param_string(&state->dev, name, state_string_set, + state_string_get, &string->value, string); + if (IS_ERR(string->param)) { + ret = PTR_ERR(string->param); + goto out; + } + + return &string->var; +out: + free(string); + return ERR_PTR(ret); +} + static struct variable_type types[] = { { .type = STATE_TYPE_U8, @@ -435,6 +581,12 @@ static struct variable_type types[] = { .export = state_mac_export, .import = state_mac_import, .create = state_mac_create, + }, { + .type = STATE_TYPE_STRING, + .type_name = "string", + .export = state_string_export, + .import = state_string_import, + .create = state_string_create, }, }; -- cgit v1.2.3 From 179b75aaca4767901a8e6527b509307f7e5d7259 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 25 Jun 2015 14:47:09 +0200 Subject: state: fixup: only export default value during fixup if set Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- common/state.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/common/state.c b/common/state.c index b3e1bdf342..1243320226 100644 --- a/common/state.c +++ b/common/state.c @@ -143,13 +143,16 @@ static int state_uint32_export(struct state_variable *var, struct state_uint32 *su32 = to_state_uint32(var); int ret; - if (su32->value_default || conv == STATE_CONVERT_FIXUP) { + if (su32->value_default) { ret = of_property_write_u32(node, "default", su32->value_default); - if (ret || conv == STATE_CONVERT_FIXUP) + if (ret) return ret; } + if (conv == STATE_CONVERT_FIXUP) + return 0; + return of_property_write_u32(node, "value", su32->value); } @@ -249,13 +252,16 @@ static int state_enum32_export(struct state_variable *var, int ret, i, len; char *prop, *str; - if (enum32->value_default || conv == STATE_CONVERT_FIXUP) { + if (enum32->value_default) { ret = of_property_write_u32(node, "default", enum32->value_default); - if (ret || conv == STATE_CONVERT_FIXUP) + if (ret) return ret; } + if (conv == STATE_CONVERT_FIXUP) + return 0; + ret = of_property_write_u32(node, "value", enum32->value); if (ret) return ret; @@ -364,10 +370,15 @@ static int state_mac_export(struct state_variable *var, struct state_mac *mac = to_state_mac(var); int ret; - ret = of_property_write_u8_array(node, "default", mac->value_default, - ARRAY_SIZE(mac->value_default)); - if (ret || conv == STATE_CONVERT_FIXUP) - return ret; + if (!is_zero_ether_addr(mac->value_default)) { + ret = of_property_write_u8_array(node, "default", mac->value_default, + ARRAY_SIZE(mac->value_default)); + if (ret) + return ret; + } + + if (conv == STATE_CONVERT_FIXUP) + return 0; return of_property_write_u8_array(node, "value", mac->value, ARRAY_SIZE(mac->value)); -- cgit v1.2.3