diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-05-06 09:30:50 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2013-05-06 09:30:50 +0200 |
commit | c19efab88606a974c050aa6caa9ec1803f88bdc9 (patch) | |
tree | 552a1520368f3d1500f7ad7d519e8e0d7758f367 /lib | |
parent | da1ada40d27c734ec51f1da924b2ecbbd28115c1 (diff) | |
parent | 2f24a5c33c9b9034e412b52ec88c1019307c14f0 (diff) | |
download | barebox-c19efab88606a974c050aa6caa9ec1803f88bdc9.tar.gz barebox-c19efab88606a974c050aa6caa9ec1803f88bdc9.tar.xz |
Merge branch 'for-next/param'
Conflicts:
drivers/mci/mci-core.c
Diffstat (limited to 'lib')
-rw-r--r-- | lib/parameter.c | 302 |
1 files changed, 263 insertions, 39 deletions
diff --git a/lib/parameter.c b/lib/parameter.c index c00b82438d..e47e8b9148 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -27,6 +27,7 @@ #include <net.h> #include <malloc.h> #include <driver.h> +#include <linux/err.h> struct param_d *get_param_by_name(struct device_d *dev, const char *name) { @@ -58,23 +59,6 @@ const char *dev_get_param(struct device_d *dev, const char *name) return param->get(dev, param); } -#ifdef CONFIG_NET -IPaddr_t dev_get_param_ip(struct device_d *dev, char *name) -{ - IPaddr_t ip; - - if (string_to_ip(dev_get_param(dev, name), &ip)) - return 0; - - return ip; -} - -int dev_set_param_ip(struct device_d *dev, char *name, IPaddr_t ip) -{ - return dev_set_param(dev, name, ip_to_string(ip)); -} -#endif - /** * dev_set_param - set a parameter of a device to a new value * @param dev The device @@ -139,14 +123,13 @@ static const char *param_get_generic(struct device_d *dev, struct param_d *p) return p->value ? p->value : ""; } -static struct param_d *__dev_add_param(struct device_d *dev, const char *name, +static int __dev_add_param(struct param_d *param, struct device_d *dev, const char *name, int (*set)(struct device_d *dev, struct param_d *p, const char *val), const char *(*get)(struct device_d *dev, struct param_d *p), unsigned long flags) { - struct param_d *param; - - param = xzalloc(sizeof(*param)); + if (get_param_by_name(dev, name)) + return -EEXIST; if (set) param->set = set; @@ -159,9 +142,10 @@ static struct param_d *__dev_add_param(struct device_d *dev, const char *name, param->name = strdup(name); param->flags = flags; + param->dev = dev; list_add_tail(¶m->list, &dev->parameters); - return param; + return 0; } /** @@ -183,14 +167,15 @@ int dev_add_param(struct device_d *dev, const char *name, unsigned long flags) { struct param_d *param; + int ret; - param = get_param_by_name(dev, name); - if (param) - return -EEXIST; + param = xzalloc(sizeof(*param)); - param = __dev_add_param(dev, name, set, get, flags); + ret = __dev_add_param(param, dev, name, set, get, flags); + if (ret) + free(param); - return param ? 0 : -EINVAL; + return ret; } /** @@ -202,32 +187,271 @@ int dev_add_param(struct device_d *dev, const char *name, int dev_add_param_fixed(struct device_d *dev, char *name, char *value) { struct param_d *param; + int ret; - param = __dev_add_param(dev, name, NULL, NULL, PARAM_FLAG_RO); - if (!param) - return -EINVAL; + param = xzalloc(sizeof(*param)); + + ret = __dev_add_param(param, dev, name, NULL, NULL, PARAM_FLAG_RO); + if (ret) { + free(param); + return ret; + } param->value = strdup(value); return 0; } +struct param_int { + struct param_d param; + int *value; + const char *format; +#define PARAM_INT_FLAG_BOOL (1 << 0) + unsigned flags; + int (*set)(struct param_d *p, void *priv); + int (*get)(struct param_d *p, void *priv); +}; + +static inline struct param_int *to_param_int(struct param_d *p) +{ + return container_of(p, struct param_int, param); +} + +static int param_int_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_int *pi = to_param_int(p); + int value_save = *pi->value; + int ret; + + if (!val) + return -EINVAL; + + *pi->value = simple_strtol(val, NULL, 0); + + if (pi->flags & PARAM_INT_FLAG_BOOL) + *pi->value = !!*pi->value; + + if (!pi->set) + return 0; + + ret = pi->set(p, p->driver_priv); + if (ret) + *pi->value = value_save; + + return ret; +} + +static const char *param_int_get(struct device_d *dev, struct param_d *p) +{ + struct param_int *pi = to_param_int(p); + int ret; + + if (pi->get) { + ret = pi->get(p, p->driver_priv); + if (ret) + return NULL; + } + + free(p->value); + p->value = asprintf(pi->format, *pi->value); + + return p->value; +} + /** - * dev_remove_param - remove a parameter from a device and free its - * memory + * dev_add_param_int - add an integer parameter to a device * @param dev The device * @param name The name of the parameter + * @param set set function + * @param get get function + * @param value pointer to the integer containing the value of the parameter + * @param format the printf format used to print the value + * @param priv user private data, will be passed to get/set + * + * The get function can be used as a notifier when the variable is about + * to be read. + * The set function can be used as a notifer when the variable is about + * to be written. Can also be used to limit the value. */ -void dev_remove_param(struct device_d *dev, char *name) +struct param_d *dev_add_param_int(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + int *value, const char *format, void *priv) { - struct param_d *p = get_param_by_name(dev, name); + struct param_int *pi; + struct param_d *p; + int ret; - if (p) { - p->set(dev, p, NULL); - list_del(&p->list); - free(p->name); - free(p); + pi = xzalloc(sizeof(*pi)); + pi->value = value; + pi->format = format; + pi->set = set; + pi->get = get; + p = &pi->param; + p->driver_priv = priv; + + ret = __dev_add_param(p, dev, name, param_int_set, param_int_get, 0); + if (ret) { + free(pi); + return ERR_PTR(ret); + } + + return &pi->param; +} + +/** + * dev_add_param_bool - add an boolean parameter to a device + * @param dev The device + * @param name The name of the parameter + * @param set set function + * @param get get function + * @param value pointer to the integer containing the value of the parameter + * @param priv user private data, will be passed to get/set + * + * The get function can be used as a notifier when the variable is about + * to be read. + * The set function can be used as a notifer when the variable is about + * to be written. Can also be used to limit the value. + */ +struct param_d *dev_add_param_bool(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + int *value, void *priv) +{ + struct param_int *pi; + struct param_d *p; + + p = dev_add_param_int(dev, name, set, get, value, "%d", priv); + if (IS_ERR(p)) + return p; + + pi = to_param_int(p); + pi->flags |= PARAM_INT_FLAG_BOOL; + + return p; +} + +struct param_int_ro { + struct param_d param; + char *value; +}; + +/** + * dev_add_param_int_ro - add a read only integer parameter to a device + * @param dev The device + * @param name The name of the parameter + * @param value The value of the parameter + * @param format the printf format used to print the value + */ +struct param_d *dev_add_param_int_ro(struct device_d *dev, const char *name, + int value, const char *format) +{ + struct param_int *piro; + int ret; + + piro = xzalloc(sizeof(*piro)); + + ret = __dev_add_param(&piro->param, dev, name, NULL, NULL, 0); + if (ret) { + free(piro); + return ERR_PTR(ret); } + + piro->param.value = asprintf(format, value); + + return &piro->param; +} + +#ifdef CONFIG_NET +struct param_ip { + struct param_d param; + IPaddr_t *ip; + const char *format; + int (*set)(struct param_d *p, void *priv); + int (*get)(struct param_d *p, void *priv); +}; + +static inline struct param_ip *to_param_ip(struct param_d *p) +{ + return container_of(p, struct param_ip, param); +} + +static int param_ip_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_ip *pi = to_param_ip(p); + IPaddr_t ip_save = *pi->ip; + int ret; + + if (!val) + return -EINVAL; + + ret = string_to_ip(val, pi->ip); + if (ret) + return ret; + + if (!pi->set) + return 0; + + ret = pi->set(p, p->driver_priv); + if (ret) + *pi->ip = ip_save; + + return ret; +} + +static const char *param_ip_get(struct device_d *dev, struct param_d *p) +{ + struct param_ip *pi = to_param_ip(p); + int ret; + + if (pi->get) { + ret = pi->get(p, p->driver_priv); + if (ret) + return NULL; + } + + free(p->value); + p->value = xstrdup(ip_to_string(*pi->ip)); + + return p->value; +} + +struct param_d *dev_add_param_ip(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + IPaddr_t *ip, void *priv) +{ + struct param_ip *pi; + int ret; + + pi = xzalloc(sizeof(*pi)); + pi->ip = ip; + pi->set = set; + pi->get = get; + pi->param.driver_priv = priv; + + ret = __dev_add_param(&pi->param, dev, name, + param_ip_set, param_ip_get, 0); + if (ret) { + free(pi); + return ERR_PTR(ret); + } + + return &pi->param; +} +#endif + +/** + * dev_remove_param - remove a parameter from a device and free its + * memory + * @param p The parameter + */ +void dev_remove_param(struct param_d *p) +{ + p->set(p->dev, p, NULL); + list_del(&p->list); + free(p->name); + free(p); } /** |