summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2010-06-03 10:13:29 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2010-06-17 08:28:25 +0200
commitc3789cd49b43ec1c414ba1b0e9f48e8ccc19f8e1 (patch)
tree8df082be53b5f2538956daf5e3c0295eff58de23 /lib
parent57e1fc33bda4f4f215bdaa7ebb2a79cc5aac3799 (diff)
downloadbarebox-c3789cd49b43ec1c414ba1b0e9f48e8ccc19f8e1.tar.gz
barebox-c3789cd49b43ec1c414ba1b0e9f48e8ccc19f8e1.tar.xz
rework device parameters
Change device parameters so that the memory management is in generic code. This also removes the need of storing statically initialized parameters as they are stored in a struct list_head for each device. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'lib')
-rw-r--r--lib/driver.c12
-rw-r--r--lib/parameter.c195
2 files changed, 128 insertions, 79 deletions
diff --git a/lib/driver.c b/lib/driver.c
index f433c3e9bf..b60074511f 100644
--- a/lib/driver.c
+++ b/lib/driver.c
@@ -107,6 +107,7 @@ int register_device(struct device_d *new_device)
list_add_tail(&new_device->list, &device_list);
INIT_LIST_HEAD(&new_device->children);
INIT_LIST_HEAD(&new_device->cdevs);
+ INIT_LIST_HEAD(&new_device->parameters);
for_each_driver(drv) {
if (!match(drv, new_device))
@@ -313,16 +314,11 @@ static int do_devinfo(struct command *cmdtp, int argc, char *argv[])
if (dev->driver)
dev->driver->info(dev);
- param = dev->param;
+ printf("%s\n", list_empty(&dev->parameters) ?
+ "no parameters available" : "Parameters:");
- printf("%s\n", param ?
- "Parameters:" : "no parameters available");
-
- while (param) {
+ list_for_each_entry(param, &dev->parameters, list)
printf("%16s = %s\n", param->name, param->value);
- param = param->next;
- }
-
}
return 0;
diff --git a/lib/parameter.c b/lib/parameter.c
index 6b32207cd5..0aa4193431 100644
--- a/lib/parameter.c
+++ b/lib/parameter.c
@@ -33,17 +33,22 @@
struct param_d *get_param_by_name(struct device_d *dev, const char *name)
{
- struct param_d *param = dev->param;
+ struct param_d *p;
- while (param) {
- if (!strcmp(param->name, name))
- return param;
- param = param->next;
+ list_for_each_entry(p, &dev->parameters, list) {
+ if (!strcmp(p->name, name))
+ return p;
}
return NULL;
}
+/**
+ * dev_get_param - get the value of a parameter
+ * @param dev The device
+ * @param name The name of the parameter
+ * @return The value
+ */
const char *dev_get_param(struct device_d *dev, const char *name)
{
struct param_d *param = get_param_by_name(dev, name);
@@ -53,10 +58,7 @@ const char *dev_get_param(struct device_d *dev, const char *name)
return NULL;
}
- if (param->get)
- return param->get(dev, param);
-
- return param->value;
+ return param->get(dev, param);
}
#ifdef CONFIG_NET
@@ -80,6 +82,12 @@ int dev_set_param_ip(struct device_d *dev, char *name, IPaddr_t ip)
}
#endif
+/**
+ * dev_set_param - set a parameter of a device to a new value
+ * @param dev The device
+ * @param name The name of the parameter
+ * @param value The new value of the parameter
+ */
int dev_set_param(struct device_d *dev, const char *name, const char *val)
{
struct param_d *param;
@@ -101,35 +109,124 @@ int dev_set_param(struct device_d *dev, const char *name, const char *val)
return -EACCES;
}
- if (param->set) {
- errno = param->set(dev, param, val);
- return errno;
+ errno = param->set(dev, param, val);
+ return errno;
+}
+
+/**
+ * dev_param_set_generic - generic setter function for a parameter
+ * @param dev The device
+ * @param p the parameter
+ * @param val The new value
+ *
+ * If used the value of a parameter is a string allocated with
+ * malloc and freed with free. If val is NULL the value is freed. This is
+ * used during deregistration of the parameter to free the alloctated
+ * memory.
+ */
+int dev_param_set_generic(struct device_d *dev, struct param_d *p,
+ const char *val)
+{
+ if (p->value)
+ free(p->value);
+ if (!val) {
+ p->value = NULL;
+ return 0;
}
+ p->value = strdup(val);
+ return 0;
+}
- if (param->value)
- free(param->value);
+static char *param_get_generic(struct device_d *dev, struct param_d *p)
+{
+ return p->value;
+}
- param->value = strdup(val);
- return 0;
+static struct param_d *__dev_add_param(struct device_d *dev, char *name,
+ int (*set)(struct device_d *dev, struct param_d *p, const char *val),
+ char *(*get)(struct device_d *dev, struct param_d *p),
+ unsigned long flags)
+{
+ struct param_d *param;
+
+ param = xzalloc(sizeof(*param));
+
+ if (set)
+ param->set = set;
+ else
+ param->set = dev_param_set_generic;
+ if (get)
+ param->get = get;
+ else
+ param->get = param_get_generic;
+
+ param->name = strdup(name);
+ param->flags = flags;
+ list_add_tail(&param->list, &dev->parameters);
+
+ return param;
}
-int dev_add_param(struct device_d *dev, struct param_d *newparam)
+/**
+ * dev_add_param - add a parameter to a device
+ * @param dev The device
+ * @param name The name of the parameter
+ * @param set setter function for the parameter
+ * @param get getter function for the parameter
+ * @param flags
+ *
+ * This function adds a new parameter to a device. The get/set functions can
+ * be zero in which case the generic functions are used. The generic functions
+ * expect the parameter value to be a string which can be freed with free(). Do
+ * not use static arrays when using the generic functions.
+ */
+int dev_add_param(struct device_d *dev, char *name,
+ int (*set)(struct device_d *dev, struct param_d *p, const char *val),
+ char *(*get)(struct device_d *dev, struct param_d *param),
+ unsigned long flags)
{
- struct param_d *param = dev->param;
+ struct param_d *param;
- newparam->next = NULL;
+ param = __dev_add_param(dev, name, set, get, flags);
- if (param) {
- while (param->next)
- param = param->next;
- param->next = newparam;
- } else {
- dev->param = newparam;
- }
+ return param ? 0 : -EINVAL;
+}
+
+/**
+ * dev_add_param_fixed - add a readonly parameter to a device
+ * @param dev The device
+ * @param name The name of the parameter
+ * @param value The value of the parameter
+ */
+int dev_add_param_fixed(struct device_d *dev, char *name, char *value)
+{
+ struct param_d *param;
+
+ param = __dev_add_param(dev, name, NULL, NULL, PARAM_FLAG_RO);
+ if (!param)
+ return -EINVAL;
+
+ param->value = strdup(value);
return 0;
}
+/**
+ * dev_remove_parameters - remove all parameters from a device and free their
+ * memory
+ * @param dev The device
+ */
+void dev_remove_parameters(struct device_d *dev)
+{
+ struct param_d *p, *n;
+
+ list_for_each_entry_safe(p, n, &dev->parameters, list) {
+ p->set(dev, p, NULL);
+ list_del(&p->list);
+ free(p);
+ }
+}
+
/** @page dev_params Device parameters
@section params_devices Devices can have several parameters.
@@ -145,50 +242,6 @@ IP address of the first ethernet device is a matter of typing
devices currently present. If called with a device id as parameter it shows the
parameters available for a device.
-@section params_programming Device parameters programming API
-
-@code
-struct param_d {
- char* (*get)(struct device_d *, struct param_d *param);
- int (*set)(struct device_d *, struct param_d *param, const char *val);
- ulong flags;
- char *name;
- struct param_d *next;
- char *value;
-};
-@endcode
-
-@code
-int dev_add_param(struct device_d *dev, struct param_d *newparam);
-@endcode
-
-This function adds a new parameter to a device. At least the name field in
-the new parameter struct has to be initialized. The 'get' and 'set' fields
-can be set to NULL in which case the framework handles them. It is also
-allowed to implement only one of the get/set functions. Care must be taken
-with the initial value of the parameter. If the framework handles the set
-function it will try to free the value of the parameter. If this is a
-static array bad things will happen. A parameter can have the flag
-PARAM_FLAG_RO which means that the parameter is readonly. It is perfectly ok
-then to point the value to a static array.
-
-@code
-const char *dev_get_param(struct device_d *dev, const char *name);
-@endcode
-
-This function returns a pointer to the value of the parameter specified
-with dev and name.
-If the framework handles the get/set functions the parameter value strings
-are alloceted with malloc and freed with free when another value is set for
-this parameter. Drivers implementing set/get themselves are allowed to
-return values in static arrays. This means that the pointers returned from
-dev_get_param() are only valid until the next call to dev_get_param. If this
-is not long enough strdup() or similar must be used.
-
-@code
-int dev_set_param(struct device_d *dev, const char *name, const char *val);
-@endcode
-
-Set the value of a parameter.
+See the individual functions for parameter programming.
*/