193f9dcf9SAnton Vorontsov /* 293f9dcf9SAnton Vorontsov * An inteface for configuring a hardware via u-boot environment. 393f9dcf9SAnton Vorontsov * 493f9dcf9SAnton Vorontsov * Copyright (c) 2009 MontaVista Software, Inc. 593f9dcf9SAnton Vorontsov * 693f9dcf9SAnton Vorontsov * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 793f9dcf9SAnton Vorontsov * 893f9dcf9SAnton Vorontsov * This program is free software; you can redistribute it and/or 993f9dcf9SAnton Vorontsov * modify it under the terms of the GNU General Public License as 1093f9dcf9SAnton Vorontsov * published by the Free Software Foundation; either version 2 of 1193f9dcf9SAnton Vorontsov * the License, or (at your option) any later version. 1293f9dcf9SAnton Vorontsov */ 1393f9dcf9SAnton Vorontsov 143bf74a41SAnton Vorontsov #ifndef HWCONFIG_TEST 1593f9dcf9SAnton Vorontsov #include <config.h> 1693f9dcf9SAnton Vorontsov #include <common.h> 1793f9dcf9SAnton Vorontsov #include <exports.h> 1893f9dcf9SAnton Vorontsov #include <hwconfig.h> 1993f9dcf9SAnton Vorontsov #include <linux/types.h> 2093f9dcf9SAnton Vorontsov #include <linux/string.h> 213bf74a41SAnton Vorontsov #else 223bf74a41SAnton Vorontsov #include <stdio.h> 233bf74a41SAnton Vorontsov #include <stdlib.h> 243bf74a41SAnton Vorontsov #include <string.h> 253bf74a41SAnton Vorontsov #include <assert.h> 263bf74a41SAnton Vorontsov #define min(a, b) (((a) < (b)) ? (a) : (b)) 273bf74a41SAnton Vorontsov #endif /* HWCONFIG_TEST */ 2893f9dcf9SAnton Vorontsov 29c4b115f5SKumar Gala DECLARE_GLOBAL_DATA_PTR; 30c4b115f5SKumar Gala 3193f9dcf9SAnton Vorontsov static const char *hwconfig_parse(const char *opts, size_t maxlen, 3281f8d3b0SAnton Vorontsov const char *opt, char *stopchs, char eqch, 3393f9dcf9SAnton Vorontsov size_t *arglen) 3493f9dcf9SAnton Vorontsov { 3593f9dcf9SAnton Vorontsov size_t optlen = strlen(opt); 3693f9dcf9SAnton Vorontsov char *str; 3793f9dcf9SAnton Vorontsov const char *start = opts; 3893f9dcf9SAnton Vorontsov const char *end; 3993f9dcf9SAnton Vorontsov 4093f9dcf9SAnton Vorontsov next: 4193f9dcf9SAnton Vorontsov str = strstr(opts, opt); 4293f9dcf9SAnton Vorontsov end = str + optlen; 4393f9dcf9SAnton Vorontsov if (end - start > maxlen) 4493f9dcf9SAnton Vorontsov return NULL; 4593f9dcf9SAnton Vorontsov 4681f8d3b0SAnton Vorontsov if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) && 4781f8d3b0SAnton Vorontsov (strpbrk(end, stopchs) == end || *end == eqch || 4881f8d3b0SAnton Vorontsov *end == '\0')) { 4993f9dcf9SAnton Vorontsov const char *arg_end; 5093f9dcf9SAnton Vorontsov 5193f9dcf9SAnton Vorontsov if (!arglen) 5293f9dcf9SAnton Vorontsov return str; 5393f9dcf9SAnton Vorontsov 5493f9dcf9SAnton Vorontsov if (*end != eqch) 5593f9dcf9SAnton Vorontsov return NULL; 5693f9dcf9SAnton Vorontsov 5781f8d3b0SAnton Vorontsov arg_end = strpbrk(str, stopchs); 5893f9dcf9SAnton Vorontsov if (!arg_end) 5993f9dcf9SAnton Vorontsov *arglen = min(maxlen, strlen(str)) - optlen - 1; 6093f9dcf9SAnton Vorontsov else 6193f9dcf9SAnton Vorontsov *arglen = arg_end - end - 1; 6293f9dcf9SAnton Vorontsov 6393f9dcf9SAnton Vorontsov return end + 1; 6493f9dcf9SAnton Vorontsov } else if (str) { 6593f9dcf9SAnton Vorontsov opts = end; 6693f9dcf9SAnton Vorontsov goto next; 6793f9dcf9SAnton Vorontsov } 6893f9dcf9SAnton Vorontsov return NULL; 6993f9dcf9SAnton Vorontsov } 7093f9dcf9SAnton Vorontsov 71*b194577bSKumar Gala const char cpu_hwconfig[] __attribute__((weak)) = ""; 72*b194577bSKumar Gala const char board_hwconfig[] __attribute__((weak)) = ""; 7393f9dcf9SAnton Vorontsov 74c4b115f5SKumar Gala #define HWCONFIG_PRE_RELOC_BUF_SIZE 128 75c4b115f5SKumar Gala 7693f9dcf9SAnton Vorontsov static const char *__hwconfig(const char *opt, size_t *arglen) 7793f9dcf9SAnton Vorontsov { 78c4b115f5SKumar Gala const char *env_hwconfig = NULL; 79c4b115f5SKumar Gala char buf[HWCONFIG_PRE_RELOC_BUF_SIZE]; 80c4b115f5SKumar Gala 81c4b115f5SKumar Gala if (gd->flags & GD_FLG_ENV_READY) { 82c4b115f5SKumar Gala env_hwconfig = getenv("hwconfig"); 83c4b115f5SKumar Gala } else { 84c4b115f5SKumar Gala /* 85c4b115f5SKumar Gala * Use our own on stack based buffer before relocation to allow 86c4b115f5SKumar Gala * accessing longer hwconfig strings that might be in the 87c4b115f5SKumar Gala * environment before we've relocated. This is pretty fragile 88c4b115f5SKumar Gala * on both the use of stack and if the buffer is big enough. 89c4b115f5SKumar Gala * However we will get a warning from getenv_f for the later. 90c4b115f5SKumar Gala */ 91c4b115f5SKumar Gala if ((getenv_f("hwconfig", buf, sizeof(buf))) > 0) 92c4b115f5SKumar Gala env_hwconfig = buf; 93c4b115f5SKumar Gala } 9493f9dcf9SAnton Vorontsov 9593f9dcf9SAnton Vorontsov if (env_hwconfig) 9693f9dcf9SAnton Vorontsov return hwconfig_parse(env_hwconfig, strlen(env_hwconfig), 9781f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 9893f9dcf9SAnton Vorontsov 9993f9dcf9SAnton Vorontsov return hwconfig_parse(board_hwconfig, strlen(board_hwconfig), 10081f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 10193f9dcf9SAnton Vorontsov 10293f9dcf9SAnton Vorontsov return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig), 10381f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 10493f9dcf9SAnton Vorontsov 10593f9dcf9SAnton Vorontsov return NULL; 10693f9dcf9SAnton Vorontsov } 10793f9dcf9SAnton Vorontsov 10893f9dcf9SAnton Vorontsov /* 10993f9dcf9SAnton Vorontsov * hwconfig - query if a particular hwconfig option is specified 11093f9dcf9SAnton Vorontsov * @opt: a string representing an option 11193f9dcf9SAnton Vorontsov * 11293f9dcf9SAnton Vorontsov * This call can be used to find out whether U-Boot should configure 11393f9dcf9SAnton Vorontsov * a particular hardware option. 11493f9dcf9SAnton Vorontsov * 11593f9dcf9SAnton Vorontsov * Returns non-zero value if the hardware option can be used and thus 11693f9dcf9SAnton Vorontsov * should be configured, 0 otherwise. 11793f9dcf9SAnton Vorontsov * 11893f9dcf9SAnton Vorontsov * This function also returns non-zero value if CONFIG_HWCONFIG is 11993f9dcf9SAnton Vorontsov * undefined. 12093f9dcf9SAnton Vorontsov * 12193f9dcf9SAnton Vorontsov * Returning non-zero value without CONFIG_HWCONFIG has its crucial 12293f9dcf9SAnton Vorontsov * purpose: the hwconfig() call should be a "transparent" interface, 12393f9dcf9SAnton Vorontsov * e.g. if a board doesn't need hwconfig facility, then we assume 12493f9dcf9SAnton Vorontsov * that the board file only calls things that are actually used, so 12593f9dcf9SAnton Vorontsov * hwconfig() will always return true result. 12693f9dcf9SAnton Vorontsov */ 12793f9dcf9SAnton Vorontsov int hwconfig(const char *opt) 12893f9dcf9SAnton Vorontsov { 12993f9dcf9SAnton Vorontsov return !!__hwconfig(opt, NULL); 13093f9dcf9SAnton Vorontsov } 13193f9dcf9SAnton Vorontsov 13293f9dcf9SAnton Vorontsov /* 13393f9dcf9SAnton Vorontsov * hwconfig_arg - get hwconfig option's argument 13493f9dcf9SAnton Vorontsov * @opt: a string representing an option 13593f9dcf9SAnton Vorontsov * @arglen: a pointer to an allocated size_t variable 13693f9dcf9SAnton Vorontsov * 13793f9dcf9SAnton Vorontsov * Unlike hwconfig() function, this function returns a pointer to the 13893f9dcf9SAnton Vorontsov * start of the hwconfig arguments, if option is not found or it has 13993f9dcf9SAnton Vorontsov * no specified arguments, the function returns NULL pointer. 14093f9dcf9SAnton Vorontsov * 14193f9dcf9SAnton Vorontsov * If CONFIG_HWCONFIG is undefined, the function returns "", and 14293f9dcf9SAnton Vorontsov * arglen is set to 0. 14393f9dcf9SAnton Vorontsov */ 14493f9dcf9SAnton Vorontsov const char *hwconfig_arg(const char *opt, size_t *arglen) 14593f9dcf9SAnton Vorontsov { 14693f9dcf9SAnton Vorontsov return __hwconfig(opt, arglen); 14793f9dcf9SAnton Vorontsov } 14893f9dcf9SAnton Vorontsov 14993f9dcf9SAnton Vorontsov /* 15093f9dcf9SAnton Vorontsov * hwconfig_arg_cmp - compare hwconfig option's argument 15193f9dcf9SAnton Vorontsov * @opt: a string representing an option 15293f9dcf9SAnton Vorontsov * @arg: a string for comparing an option's argument 15393f9dcf9SAnton Vorontsov * 15493f9dcf9SAnton Vorontsov * This call is similar to hwconfig_arg, but instead of returning 15593f9dcf9SAnton Vorontsov * hwconfig argument and its length, it is comparing it to @arg. 15693f9dcf9SAnton Vorontsov * 15793f9dcf9SAnton Vorontsov * Returns non-zero value if @arg matches, 0 otherwise. 15893f9dcf9SAnton Vorontsov * 15993f9dcf9SAnton Vorontsov * If CONFIG_HWCONFIG is undefined, the function returns a non-zero 16093f9dcf9SAnton Vorontsov * value, i.e. the argument matches. 16193f9dcf9SAnton Vorontsov */ 16293f9dcf9SAnton Vorontsov int hwconfig_arg_cmp(const char *opt, const char *arg) 16393f9dcf9SAnton Vorontsov { 16493f9dcf9SAnton Vorontsov const char *argstr; 16593f9dcf9SAnton Vorontsov size_t arglen; 16693f9dcf9SAnton Vorontsov 16793f9dcf9SAnton Vorontsov argstr = hwconfig_arg(opt, &arglen); 16893f9dcf9SAnton Vorontsov if (!argstr || arglen != strlen(arg)) 16993f9dcf9SAnton Vorontsov return 0; 17093f9dcf9SAnton Vorontsov 17193f9dcf9SAnton Vorontsov return !strncmp(argstr, arg, arglen); 17293f9dcf9SAnton Vorontsov } 17393f9dcf9SAnton Vorontsov 17493f9dcf9SAnton Vorontsov /* 17593f9dcf9SAnton Vorontsov * hwconfig_sub - query if a particular hwconfig sub-option is specified 17693f9dcf9SAnton Vorontsov * @opt: a string representing an option 17793f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 17893f9dcf9SAnton Vorontsov * 17993f9dcf9SAnton Vorontsov * This call is similar to hwconfig(), except that it takes additional 18093f9dcf9SAnton Vorontsov * argument @subopt. In this example: 18193f9dcf9SAnton Vorontsov * "dr_usb:mode=peripheral" 18293f9dcf9SAnton Vorontsov * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its 18393f9dcf9SAnton Vorontsov * argument. 18493f9dcf9SAnton Vorontsov */ 18593f9dcf9SAnton Vorontsov int hwconfig_sub(const char *opt, const char *subopt) 18693f9dcf9SAnton Vorontsov { 18793f9dcf9SAnton Vorontsov size_t arglen; 18893f9dcf9SAnton Vorontsov const char *arg; 18993f9dcf9SAnton Vorontsov 19093f9dcf9SAnton Vorontsov arg = __hwconfig(opt, &arglen); 19193f9dcf9SAnton Vorontsov if (!arg) 19293f9dcf9SAnton Vorontsov return 0; 19381f8d3b0SAnton Vorontsov return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL); 19493f9dcf9SAnton Vorontsov } 19593f9dcf9SAnton Vorontsov 19693f9dcf9SAnton Vorontsov /* 19793f9dcf9SAnton Vorontsov * hwconfig_subarg - get hwconfig sub-option's argument 19893f9dcf9SAnton Vorontsov * @opt: a string representing an option 19993f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 20093f9dcf9SAnton Vorontsov * @subarglen: a pointer to an allocated size_t variable 20193f9dcf9SAnton Vorontsov * 20293f9dcf9SAnton Vorontsov * This call is similar to hwconfig_arg(), except that it takes an additional 20393f9dcf9SAnton Vorontsov * argument @subopt, and so works with sub-options. 20493f9dcf9SAnton Vorontsov */ 20593f9dcf9SAnton Vorontsov const char *hwconfig_subarg(const char *opt, const char *subopt, 20693f9dcf9SAnton Vorontsov size_t *subarglen) 20793f9dcf9SAnton Vorontsov { 20893f9dcf9SAnton Vorontsov size_t arglen; 20993f9dcf9SAnton Vorontsov const char *arg; 21093f9dcf9SAnton Vorontsov 21193f9dcf9SAnton Vorontsov arg = __hwconfig(opt, &arglen); 21293f9dcf9SAnton Vorontsov if (!arg) 21393f9dcf9SAnton Vorontsov return NULL; 21481f8d3b0SAnton Vorontsov return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen); 21593f9dcf9SAnton Vorontsov } 21693f9dcf9SAnton Vorontsov 21793f9dcf9SAnton Vorontsov /* 21893f9dcf9SAnton Vorontsov * hwconfig_arg_cmp - compare hwconfig sub-option's argument 21993f9dcf9SAnton Vorontsov * @opt: a string representing an option 22093f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 22193f9dcf9SAnton Vorontsov * @subarg: a string for comparing an sub-option's argument 22293f9dcf9SAnton Vorontsov * 22393f9dcf9SAnton Vorontsov * This call is similar to hwconfig_arg_cmp, except that it takes an additional 22493f9dcf9SAnton Vorontsov * argument @subopt, and so works with sub-options. 22593f9dcf9SAnton Vorontsov */ 22693f9dcf9SAnton Vorontsov int hwconfig_subarg_cmp(const char *opt, const char *subopt, const char *subarg) 22793f9dcf9SAnton Vorontsov { 22893f9dcf9SAnton Vorontsov const char *argstr; 22993f9dcf9SAnton Vorontsov size_t arglen; 23093f9dcf9SAnton Vorontsov 23193f9dcf9SAnton Vorontsov argstr = hwconfig_subarg(opt, subopt, &arglen); 23293f9dcf9SAnton Vorontsov if (!argstr || arglen != strlen(subarg)) 23393f9dcf9SAnton Vorontsov return 0; 23493f9dcf9SAnton Vorontsov 23593f9dcf9SAnton Vorontsov return !strncmp(argstr, subarg, arglen); 23693f9dcf9SAnton Vorontsov } 2373bf74a41SAnton Vorontsov 2383bf74a41SAnton Vorontsov #ifdef HWCONFIG_TEST 2393bf74a41SAnton Vorontsov int main() 2403bf74a41SAnton Vorontsov { 2413bf74a41SAnton Vorontsov const char *ret; 2423bf74a41SAnton Vorontsov size_t len; 2433bf74a41SAnton Vorontsov 2443bf74a41SAnton Vorontsov setenv("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;" 2453bf74a41SAnton Vorontsov "key3;:,:=;key4", 1); 2463bf74a41SAnton Vorontsov 2473bf74a41SAnton Vorontsov ret = hwconfig_arg("key1", &len); 2483bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2493bf74a41SAnton Vorontsov assert(len == 29); 2503bf74a41SAnton Vorontsov assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2")); 2513bf74a41SAnton Vorontsov assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len)); 2523bf74a41SAnton Vorontsov 2533bf74a41SAnton Vorontsov ret = hwconfig_subarg("key1", "subkey1", &len); 2543bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2553bf74a41SAnton Vorontsov assert(len == 6); 2563bf74a41SAnton Vorontsov assert(hwconfig_subarg_cmp("key1", "subkey1", "value1")); 2573bf74a41SAnton Vorontsov assert(!strncmp(ret, "value1", len)); 2583bf74a41SAnton Vorontsov 2593bf74a41SAnton Vorontsov ret = hwconfig_subarg("key1", "subkey2", &len); 2603bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2613bf74a41SAnton Vorontsov assert(len == 6); 2623bf74a41SAnton Vorontsov assert(hwconfig_subarg_cmp("key1", "subkey2", "value2")); 2633bf74a41SAnton Vorontsov assert(!strncmp(ret, "value2", len)); 2643bf74a41SAnton Vorontsov 2653bf74a41SAnton Vorontsov ret = hwconfig_arg("key2", &len); 2663bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2673bf74a41SAnton Vorontsov assert(len == 6); 2683bf74a41SAnton Vorontsov assert(hwconfig_arg_cmp("key2", "value3")); 2693bf74a41SAnton Vorontsov assert(!strncmp(ret, "value3", len)); 2703bf74a41SAnton Vorontsov 2713bf74a41SAnton Vorontsov assert(hwconfig("key3")); 2723bf74a41SAnton Vorontsov assert(hwconfig_arg("key4", &len) == NULL); 2733bf74a41SAnton Vorontsov assert(hwconfig_arg("bogus", &len) == NULL); 2743bf74a41SAnton Vorontsov 2753bf74a41SAnton Vorontsov unsetenv("hwconfig"); 2763bf74a41SAnton Vorontsov 2773bf74a41SAnton Vorontsov assert(hwconfig(NULL) == 0); 2783bf74a41SAnton Vorontsov assert(hwconfig("") == 0); 2793bf74a41SAnton Vorontsov assert(hwconfig("key3") == 0); 2803bf74a41SAnton Vorontsov 2813bf74a41SAnton Vorontsov return 0; 2823bf74a41SAnton Vorontsov } 2833bf74a41SAnton Vorontsov #endif /* HWCONFIG_TEST */ 284