]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/hwconfig.c
OMAP3: Zoom2: Fix ARM relocation support
[karo-tx-uboot.git] / common / hwconfig.c
index e5c60ba7a40a415d5bf10447f697336affd24058..3c9759fc557547fa8a2f0bc16fa87658fa166e23 100644 (file)
  * the License, or (at your option) any later version.
  */
 
+#ifndef HWCONFIG_TEST
 #include <config.h>
 #include <common.h>
 #include <exports.h>
 #include <hwconfig.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* HWCONFIG_TEST */
+
+DECLARE_GLOBAL_DATA_PTR;
 
 static const char *hwconfig_parse(const char *opts, size_t maxlen,
-                                 const char *opt, char stopch, char eqch,
+                                 const char *opt, char *stopchs, char eqch,
                                  size_t *arglen)
 {
        size_t optlen = strlen(opt);
@@ -33,8 +43,9 @@ next:
        if (end - start > maxlen)
                return NULL;
 
-       if (str && (str == opts || str[-1] == stopch) &&
-                       (*end == stopch || *end == eqch || *end == '\0')) {
+       if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) &&
+                       (strpbrk(end, stopchs) == end || *end == eqch ||
+                        *end == '\0')) {
                const char *arg_end;
 
                if (!arglen)
@@ -43,7 +54,7 @@ next:
                if (*end != eqch)
                        return NULL;
 
-               arg_end = strchr(str, stopch);
+               arg_end = strpbrk(str, stopchs);
                if (!arg_end)
                        *arglen = min(maxlen, strlen(str)) - optlen - 1;
                else
@@ -60,21 +71,38 @@ next:
 const char *cpu_hwconfig __attribute__((weak));
 const char *board_hwconfig __attribute__((weak));
 
+#define HWCONFIG_PRE_RELOC_BUF_SIZE    128
+
 static const char *__hwconfig(const char *opt, size_t *arglen)
 {
-       const char *env_hwconfig = getenv("hwconfig");
+       const char *env_hwconfig = NULL;
+       char buf[HWCONFIG_PRE_RELOC_BUF_SIZE];
+
+       if (gd->flags & GD_FLG_ENV_READY) {
+               env_hwconfig = getenv("hwconfig");
+       } else {
+               /*
+                * Use our own on stack based buffer before relocation to allow
+                * accessing longer hwconfig strings that might be in the
+                * environment before we've relocated.  This is pretty fragile
+                * on both the use of stack and if the buffer is big enough.
+                * However we will get a warning from getenv_f for the later.
+                */
+               if ((getenv_f("hwconfig", buf, sizeof(buf))) > 0)
+                       env_hwconfig = buf;
+       }
 
        if (env_hwconfig)
                return hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
-                                     opt, ';', ':', arglen);
+                                     opt, ";", ':', arglen);
 
        if (board_hwconfig)
                return hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
-                                     opt, ';', ':', arglen);
+                                     opt, ";", ':', arglen);
 
        if (cpu_hwconfig)
                return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
-                                     opt, ';', ':', arglen);
+                                     opt, ";", ':', arglen);
 
        return NULL;
 }
@@ -164,7 +192,7 @@ int hwconfig_sub(const char *opt, const char *subopt)
        arg = __hwconfig(opt, &arglen);
        if (!arg)
                return 0;
-       return !!hwconfig_parse(arg, arglen, subopt, ',', '=', NULL);
+       return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL);
 }
 
 /*
@@ -185,7 +213,7 @@ const char *hwconfig_subarg(const char *opt, const char *subopt,
        arg = __hwconfig(opt, &arglen);
        if (!arg)
                return NULL;
-       return hwconfig_parse(arg, arglen, subopt, ',', '=', subarglen);
+       return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen);
 }
 
 /*
@@ -208,3 +236,50 @@ int hwconfig_subarg_cmp(const char *opt, const char *subopt, const char *subarg)
 
        return !strncmp(argstr, subarg, arglen);
 }
+
+#ifdef HWCONFIG_TEST
+int main()
+{
+       const char *ret;
+       size_t len;
+
+       setenv("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;"
+                          "key3;:,:=;key4", 1);
+
+       ret = hwconfig_arg("key1", &len);
+       printf("%zd %.*s\n", len, (int)len, ret);
+       assert(len == 29);
+       assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2"));
+       assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len));
+
+       ret = hwconfig_subarg("key1", "subkey1", &len);
+       printf("%zd %.*s\n", len, (int)len, ret);
+       assert(len == 6);
+       assert(hwconfig_subarg_cmp("key1", "subkey1", "value1"));
+       assert(!strncmp(ret, "value1", len));
+
+       ret = hwconfig_subarg("key1", "subkey2", &len);
+       printf("%zd %.*s\n", len, (int)len, ret);
+       assert(len == 6);
+       assert(hwconfig_subarg_cmp("key1", "subkey2", "value2"));
+       assert(!strncmp(ret, "value2", len));
+
+       ret = hwconfig_arg("key2", &len);
+       printf("%zd %.*s\n", len, (int)len, ret);
+       assert(len == 6);
+       assert(hwconfig_arg_cmp("key2", "value3"));
+       assert(!strncmp(ret, "value3", len));
+
+       assert(hwconfig("key3"));
+       assert(hwconfig_arg("key4", &len) == NULL);
+       assert(hwconfig_arg("bogus", &len) == NULL);
+
+       unsetenv("hwconfig");
+
+       assert(hwconfig(NULL) == 0);
+       assert(hwconfig("") == 0);
+       assert(hwconfig("key3") == 0);
+
+       return 0;
+}
+#endif /* HWCONFIG_TEST */