summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-06-07 22:16:48 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-07-06 10:09:29 +0200
commit699b4f80254de45a6ff45dff0a863e457dea7d89 (patch)
tree13e6a7184f2b9c56d19eb18636e588d59c98d603 /common
parentb17973f8ba8e246628ac62fca9873bf8226a61cf (diff)
downloadbarebox-699b4f80254de45a6ff45dff0a863e457dea7d89.tar.gz
barebox-699b4f80254de45a6ff45dff0a863e457dea7d89.tar.xz
Introduce non volatile device variables
Non volatile device variables are used to make device parameters persistent. They are like normal non volatile variables, but set the values of the device parameters with the corresponding name. Every nv variable beginning with nv.dev is a non volatile device variable. They have the form nv.dev.<devname>.<paramname> and act on the parameter <paramname> of the device named <devname>. The non volatile device variables are designated for example for video modes, ethernet device ip addresses or mtd partitioning. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common')
-rw-r--r--common/globalvar.c137
1 files changed, 127 insertions, 10 deletions
diff --git a/common/globalvar.c b/common/globalvar.c
index 6687b03bf0..c0958e11ea 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -68,17 +68,115 @@ static int nv_save(const char *name, const char *val)
return 0;
}
+/**
+ * dev_param_init_from_nv - initialize a device parameter from nv variable
+ * @dev: The device
+ * @name: The parameter name
+ *
+ * This function initializes a newly created device parameter from the corresponding
+ * nv.dev.<devname>.<paramname> variable.
+ */
+void dev_param_init_from_nv(struct device_d *dev, const char *name)
+{
+ char *nvname;
+ const char *val;
+ int ret = 0;
+
+ if (dev == &nv_device)
+ return;
+ if (dev == &global_device)
+ return;
+
+ nvname = basprintf("dev.%s.%s", dev_name(dev), name);
+ val = dev_get_param(&nv_device, nvname);
+ if (val) {
+ ret = dev_set_param(dev, name, val);
+ if (ret)
+ pr_err("Cannot init param from nv: %s.%s=%s: %s\n",
+ dev_name(dev), name, val, strerror(-ret));
+ }
+
+ free(nvname);
+}
+
+/**
+ * nvvar_device_dispatch - dispatch dev.<dev>.<param> name into device and parameter name
+ * @name: The incoming name in the form dev.<dev>.<param>
+ * @dev: The returned device_d * belonging to <dev>
+ * @pname: the parameter name
+ *
+ * Given a dev.<dev>.<param> string this function finds the device_d * belonging to
+ * <dev> and the parameter name from <param>.
+ *
+ * Return: When incoming string does not belong to the device namespace (does not begin
+ * with "dev." this function returns 0. A value > 0 is returned when the incoming string
+ * is in the device namespace and the string can be dispatched into a device_d * and a
+ * parameter name. A negative error code is returned when the incoming string belongs to
+ * the device namespace, but cannot be dispatched.
+ */
+static int nvvar_device_dispatch(const char *name, struct device_d **dev,
+ const char **pname)
+{
+ char *devname;
+ const char *dot;
+ int dotpos;
+
+ *dev = NULL;
+
+ if (strncmp(name, "dev.", 4))
+ return 0;
+
+ name += 4;
+
+ dot = strchr(name, '.');
+ if (!dot)
+ return -EINVAL;
+
+ dotpos = dot - name;
+
+ devname = xstrndup(name, dotpos);
+ *dev = get_device_by_name(devname);
+ free(devname);
+
+ if (*dev == &nv_device || *dev == &global_device)
+ return -EINVAL;
+
+ *pname = dot + 1;
+
+ return 1;
+}
+
static int nv_set(struct device_d *dev, struct param_d *p, const char *val)
{
int ret;
+ int devspace;
+ struct device_d *rdev;
+ const char *pname;
if (!val)
val = "";
- ret = dev_set_param(&global_device, p->name, val);
- if (ret)
+ ret = nvvar_device_dispatch(p->name, &rdev, &pname);
+ if (ret < 0)
return ret;
+ devspace = ret;
+
+ if (devspace) {
+ if (rdev) {
+ ret = dev_set_param(rdev, pname, val);
+ if (ret) {
+ pr_err("Cannot init param from nv: %s.%s=%s: %s\n",
+ dev_name(rdev), pname, val, strerror(-ret));
+ return ret;
+ }
+ }
+ } else {
+ ret = dev_set_param(&global_device, p->name, val);
+ if (ret)
+ return ret;
+ }
+
free(p->value);
p->value = xstrdup(val);
@@ -94,15 +192,26 @@ int nvvar_add(const char *name, const char *value)
{
struct param_d *p, *gp;
int ret;
+ int devspace;
+ struct device_d *dev;
+ const char *pname;
if (!IS_ENABLED(CONFIG_NVVAR))
return -ENOSYS;
+ ret = nvvar_device_dispatch(name, &dev, &pname);
+ if (ret < 0)
+ return ret;
+
+ devspace = ret;
+
gp = get_param_by_name(&nv_device, name);
if (gp) {
- ret = dev_set_param(&global_device, name, value);
- if (ret)
- return ret;
+ if (!devspace) {
+ ret = dev_set_param(&global_device, name, value);
+ if (ret)
+ return ret;
+ }
ret = dev_set_param(&nv_device, name, value);
if (ret)
@@ -111,16 +220,24 @@ int nvvar_add(const char *name, const char *value)
return 0;
}
- ret = globalvar_add_simple(name, value);
- if (ret && ret != -EEXIST)
- return ret;
+ if (!devspace) {
+ ret = globalvar_add_simple(name, value);
+ if (ret && ret != -EEXIST)
+ return ret;
+ }
p = dev_add_param(&nv_device, name, nv_set, nv_get, 0);
if (IS_ERR(p))
return PTR_ERR(p);
- if (!value)
- value = dev_get_param(&global_device, name);
+ if (!value) {
+ if (devspace) {
+ if (dev)
+ value = dev_get_param(dev, pname);
+ } else {
+ value = dev_get_param(&global_device, name);
+ }
+ }
return nv_set(&nv_device, p, value);
}