193f9dcf9SAnton Vorontsov /* 293f9dcf9SAnton Vorontsov * An inteface for configuring a hardware via u-boot environment. 393f9dcf9SAnton Vorontsov * 493f9dcf9SAnton Vorontsov * Copyright (c) 2009 MontaVista Software, Inc. 5*dd50af25SKumar Gala * Copyright 2011 Freescale Semiconductor, Inc. 693f9dcf9SAnton Vorontsov * 793f9dcf9SAnton Vorontsov * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 893f9dcf9SAnton Vorontsov * 993f9dcf9SAnton Vorontsov * This program is free software; you can redistribute it and/or 1093f9dcf9SAnton Vorontsov * modify it under the terms of the GNU General Public License as 1193f9dcf9SAnton Vorontsov * published by the Free Software Foundation; either version 2 of 1293f9dcf9SAnton Vorontsov * the License, or (at your option) any later version. 1393f9dcf9SAnton Vorontsov */ 1493f9dcf9SAnton Vorontsov 153bf74a41SAnton Vorontsov #ifndef HWCONFIG_TEST 1693f9dcf9SAnton Vorontsov #include <config.h> 1793f9dcf9SAnton Vorontsov #include <common.h> 1893f9dcf9SAnton Vorontsov #include <exports.h> 1993f9dcf9SAnton Vorontsov #include <hwconfig.h> 2093f9dcf9SAnton Vorontsov #include <linux/types.h> 2193f9dcf9SAnton Vorontsov #include <linux/string.h> 223bf74a41SAnton Vorontsov #else 233bf74a41SAnton Vorontsov #include <stdio.h> 243bf74a41SAnton Vorontsov #include <stdlib.h> 253bf74a41SAnton Vorontsov #include <string.h> 263bf74a41SAnton Vorontsov #include <assert.h> 273bf74a41SAnton Vorontsov #define min(a, b) (((a) < (b)) ? (a) : (b)) 283bf74a41SAnton Vorontsov #endif /* HWCONFIG_TEST */ 2993f9dcf9SAnton Vorontsov 30c4b115f5SKumar Gala DECLARE_GLOBAL_DATA_PTR; 31c4b115f5SKumar Gala 3293f9dcf9SAnton Vorontsov static const char *hwconfig_parse(const char *opts, size_t maxlen, 3381f8d3b0SAnton Vorontsov const char *opt, char *stopchs, char eqch, 3493f9dcf9SAnton Vorontsov size_t *arglen) 3593f9dcf9SAnton Vorontsov { 3693f9dcf9SAnton Vorontsov size_t optlen = strlen(opt); 3793f9dcf9SAnton Vorontsov char *str; 3893f9dcf9SAnton Vorontsov const char *start = opts; 3993f9dcf9SAnton Vorontsov const char *end; 4093f9dcf9SAnton Vorontsov 4193f9dcf9SAnton Vorontsov next: 4293f9dcf9SAnton Vorontsov str = strstr(opts, opt); 4393f9dcf9SAnton Vorontsov end = str + optlen; 4493f9dcf9SAnton Vorontsov if (end - start > maxlen) 4593f9dcf9SAnton Vorontsov return NULL; 4693f9dcf9SAnton Vorontsov 4781f8d3b0SAnton Vorontsov if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) && 4881f8d3b0SAnton Vorontsov (strpbrk(end, stopchs) == end || *end == eqch || 4981f8d3b0SAnton Vorontsov *end == '\0')) { 5093f9dcf9SAnton Vorontsov const char *arg_end; 5193f9dcf9SAnton Vorontsov 5293f9dcf9SAnton Vorontsov if (!arglen) 5393f9dcf9SAnton Vorontsov return str; 5493f9dcf9SAnton Vorontsov 5593f9dcf9SAnton Vorontsov if (*end != eqch) 5693f9dcf9SAnton Vorontsov return NULL; 5793f9dcf9SAnton Vorontsov 5881f8d3b0SAnton Vorontsov arg_end = strpbrk(str, stopchs); 5993f9dcf9SAnton Vorontsov if (!arg_end) 6093f9dcf9SAnton Vorontsov *arglen = min(maxlen, strlen(str)) - optlen - 1; 6193f9dcf9SAnton Vorontsov else 6293f9dcf9SAnton Vorontsov *arglen = arg_end - end - 1; 6393f9dcf9SAnton Vorontsov 6493f9dcf9SAnton Vorontsov return end + 1; 6593f9dcf9SAnton Vorontsov } else if (str) { 6693f9dcf9SAnton Vorontsov opts = end; 6793f9dcf9SAnton Vorontsov goto next; 6893f9dcf9SAnton Vorontsov } 6993f9dcf9SAnton Vorontsov return NULL; 7093f9dcf9SAnton Vorontsov } 7193f9dcf9SAnton Vorontsov 72b194577bSKumar Gala const char cpu_hwconfig[] __attribute__((weak)) = ""; 73b194577bSKumar Gala const char board_hwconfig[] __attribute__((weak)) = ""; 7493f9dcf9SAnton Vorontsov 75*dd50af25SKumar Gala static const char *__hwconfig(const char *opt, size_t *arglen, 76*dd50af25SKumar Gala const char *env_hwconfig) 7793f9dcf9SAnton Vorontsov { 78*dd50af25SKumar Gala const char *ret; 79c4b115f5SKumar Gala 80*dd50af25SKumar Gala /* if we are passed a buffer use it, otherwise try the environment */ 81*dd50af25SKumar Gala if (!env_hwconfig) { 82*dd50af25SKumar Gala if (!(gd->flags & GD_FLG_ENV_READY)) { 83*dd50af25SKumar Gala printf("WARNING: Calling __hwconfig without a buffer " 84*dd50af25SKumar Gala "and before environment is ready\n"); 85*dd50af25SKumar Gala return NULL; 86*dd50af25SKumar Gala } 87c4b115f5SKumar Gala env_hwconfig = getenv("hwconfig"); 88c4b115f5SKumar Gala } 8993f9dcf9SAnton Vorontsov 90bb141079SKumar Gala if (env_hwconfig) { 91bb141079SKumar Gala ret = hwconfig_parse(env_hwconfig, strlen(env_hwconfig), 9281f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 93bb141079SKumar Gala if (ret) 94bb141079SKumar Gala return ret; 95bb141079SKumar Gala } 9693f9dcf9SAnton Vorontsov 97bb141079SKumar Gala ret = hwconfig_parse(board_hwconfig, strlen(board_hwconfig), 9881f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 99bb141079SKumar Gala if (ret) 100bb141079SKumar Gala return ret; 10193f9dcf9SAnton Vorontsov 10293f9dcf9SAnton Vorontsov return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig), 10381f8d3b0SAnton Vorontsov opt, ";", ':', arglen); 10493f9dcf9SAnton Vorontsov } 10593f9dcf9SAnton Vorontsov 10693f9dcf9SAnton Vorontsov /* 107*dd50af25SKumar Gala * hwconfig_f - query if a particular hwconfig option is specified 10893f9dcf9SAnton Vorontsov * @opt: a string representing an option 109*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 11093f9dcf9SAnton Vorontsov * 11193f9dcf9SAnton Vorontsov * This call can be used to find out whether U-Boot should configure 11293f9dcf9SAnton Vorontsov * a particular hardware option. 11393f9dcf9SAnton Vorontsov * 11493f9dcf9SAnton Vorontsov * Returns non-zero value if the hardware option can be used and thus 11593f9dcf9SAnton Vorontsov * should be configured, 0 otherwise. 11693f9dcf9SAnton Vorontsov * 11793f9dcf9SAnton Vorontsov * This function also returns non-zero value if CONFIG_HWCONFIG is 11893f9dcf9SAnton Vorontsov * undefined. 11993f9dcf9SAnton Vorontsov * 12093f9dcf9SAnton Vorontsov * Returning non-zero value without CONFIG_HWCONFIG has its crucial 12193f9dcf9SAnton Vorontsov * purpose: the hwconfig() call should be a "transparent" interface, 12293f9dcf9SAnton Vorontsov * e.g. if a board doesn't need hwconfig facility, then we assume 12393f9dcf9SAnton Vorontsov * that the board file only calls things that are actually used, so 12493f9dcf9SAnton Vorontsov * hwconfig() will always return true result. 12593f9dcf9SAnton Vorontsov */ 126*dd50af25SKumar Gala int hwconfig_f(const char *opt, char *buf) 12793f9dcf9SAnton Vorontsov { 128*dd50af25SKumar Gala return !!__hwconfig(opt, NULL, buf); 12993f9dcf9SAnton Vorontsov } 13093f9dcf9SAnton Vorontsov 13193f9dcf9SAnton Vorontsov /* 132*dd50af25SKumar Gala * hwconfig_arg_f - get hwconfig option's argument 13393f9dcf9SAnton Vorontsov * @opt: a string representing an option 13493f9dcf9SAnton Vorontsov * @arglen: a pointer to an allocated size_t variable 135*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 13693f9dcf9SAnton Vorontsov * 137*dd50af25SKumar Gala * Unlike hwconfig_f() 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 */ 144*dd50af25SKumar Gala const char *hwconfig_arg_f(const char *opt, size_t *arglen, char *buf) 14593f9dcf9SAnton Vorontsov { 146*dd50af25SKumar Gala return __hwconfig(opt, arglen, buf); 14793f9dcf9SAnton Vorontsov } 14893f9dcf9SAnton Vorontsov 14993f9dcf9SAnton Vorontsov /* 150*dd50af25SKumar Gala * hwconfig_arg_cmp_f - compare hwconfig option's argument 15193f9dcf9SAnton Vorontsov * @opt: a string representing an option 15293f9dcf9SAnton Vorontsov * @arg: a string for comparing an option's argument 153*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 15493f9dcf9SAnton Vorontsov * 155*dd50af25SKumar Gala * This call is similar to hwconfig_arg_f, but instead of returning 15693f9dcf9SAnton Vorontsov * hwconfig argument and its length, it is comparing it to @arg. 15793f9dcf9SAnton Vorontsov * 15893f9dcf9SAnton Vorontsov * Returns non-zero value if @arg matches, 0 otherwise. 15993f9dcf9SAnton Vorontsov * 16093f9dcf9SAnton Vorontsov * If CONFIG_HWCONFIG is undefined, the function returns a non-zero 16193f9dcf9SAnton Vorontsov * value, i.e. the argument matches. 16293f9dcf9SAnton Vorontsov */ 163*dd50af25SKumar Gala int hwconfig_arg_cmp_f(const char *opt, const char *arg, char *buf) 16493f9dcf9SAnton Vorontsov { 16593f9dcf9SAnton Vorontsov const char *argstr; 16693f9dcf9SAnton Vorontsov size_t arglen; 16793f9dcf9SAnton Vorontsov 168*dd50af25SKumar Gala argstr = hwconfig_arg_f(opt, &arglen, buf); 16993f9dcf9SAnton Vorontsov if (!argstr || arglen != strlen(arg)) 17093f9dcf9SAnton Vorontsov return 0; 17193f9dcf9SAnton Vorontsov 17293f9dcf9SAnton Vorontsov return !strncmp(argstr, arg, arglen); 17393f9dcf9SAnton Vorontsov } 17493f9dcf9SAnton Vorontsov 17593f9dcf9SAnton Vorontsov /* 176*dd50af25SKumar Gala * hwconfig_sub_f - query if a particular hwconfig sub-option is specified 17793f9dcf9SAnton Vorontsov * @opt: a string representing an option 17893f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 179*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 18093f9dcf9SAnton Vorontsov * 181*dd50af25SKumar Gala * This call is similar to hwconfig_f(), except that it takes additional 18293f9dcf9SAnton Vorontsov * argument @subopt. In this example: 18393f9dcf9SAnton Vorontsov * "dr_usb:mode=peripheral" 18493f9dcf9SAnton Vorontsov * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its 18593f9dcf9SAnton Vorontsov * argument. 18693f9dcf9SAnton Vorontsov */ 187*dd50af25SKumar Gala int hwconfig_sub_f(const char *opt, const char *subopt, char *buf) 18893f9dcf9SAnton Vorontsov { 18993f9dcf9SAnton Vorontsov size_t arglen; 19093f9dcf9SAnton Vorontsov const char *arg; 19193f9dcf9SAnton Vorontsov 192*dd50af25SKumar Gala arg = __hwconfig(opt, &arglen, buf); 19393f9dcf9SAnton Vorontsov if (!arg) 19493f9dcf9SAnton Vorontsov return 0; 19581f8d3b0SAnton Vorontsov return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL); 19693f9dcf9SAnton Vorontsov } 19793f9dcf9SAnton Vorontsov 19893f9dcf9SAnton Vorontsov /* 199*dd50af25SKumar Gala * hwconfig_subarg_f - get hwconfig sub-option's argument 20093f9dcf9SAnton Vorontsov * @opt: a string representing an option 20193f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 20293f9dcf9SAnton Vorontsov * @subarglen: a pointer to an allocated size_t variable 203*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 20493f9dcf9SAnton Vorontsov * 205*dd50af25SKumar Gala * This call is similar to hwconfig_arg_f(), except that it takes an 206*dd50af25SKumar Gala * additional argument @subopt, and so works with sub-options. 20793f9dcf9SAnton Vorontsov */ 208*dd50af25SKumar Gala const char *hwconfig_subarg_f(const char *opt, const char *subopt, 209*dd50af25SKumar Gala size_t *subarglen, char *buf) 21093f9dcf9SAnton Vorontsov { 21193f9dcf9SAnton Vorontsov size_t arglen; 21293f9dcf9SAnton Vorontsov const char *arg; 21393f9dcf9SAnton Vorontsov 214*dd50af25SKumar Gala arg = __hwconfig(opt, &arglen, buf); 21593f9dcf9SAnton Vorontsov if (!arg) 21693f9dcf9SAnton Vorontsov return NULL; 21781f8d3b0SAnton Vorontsov return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen); 21893f9dcf9SAnton Vorontsov } 21993f9dcf9SAnton Vorontsov 22093f9dcf9SAnton Vorontsov /* 221*dd50af25SKumar Gala * hwconfig_arg_cmp_f - compare hwconfig sub-option's argument 22293f9dcf9SAnton Vorontsov * @opt: a string representing an option 22393f9dcf9SAnton Vorontsov * @subopt: a string representing a sub-option 22493f9dcf9SAnton Vorontsov * @subarg: a string for comparing an sub-option's argument 225*dd50af25SKumar Gala * @buf: if non-NULL use this buffer to parse, otherwise try env 22693f9dcf9SAnton Vorontsov * 227*dd50af25SKumar Gala * This call is similar to hwconfig_arg_cmp_f, except that it takes an 228*dd50af25SKumar Gala * additional argument @subopt, and so works with sub-options. 22993f9dcf9SAnton Vorontsov */ 230*dd50af25SKumar Gala int hwconfig_subarg_cmp_f(const char *opt, const char *subopt, 231*dd50af25SKumar Gala const char *subarg, char *buf) 23293f9dcf9SAnton Vorontsov { 23393f9dcf9SAnton Vorontsov const char *argstr; 23493f9dcf9SAnton Vorontsov size_t arglen; 23593f9dcf9SAnton Vorontsov 236*dd50af25SKumar Gala argstr = hwconfig_subarg_f(opt, subopt, &arglen, buf); 23793f9dcf9SAnton Vorontsov if (!argstr || arglen != strlen(subarg)) 23893f9dcf9SAnton Vorontsov return 0; 23993f9dcf9SAnton Vorontsov 24093f9dcf9SAnton Vorontsov return !strncmp(argstr, subarg, arglen); 24193f9dcf9SAnton Vorontsov } 2423bf74a41SAnton Vorontsov 2433bf74a41SAnton Vorontsov #ifdef HWCONFIG_TEST 2443bf74a41SAnton Vorontsov int main() 2453bf74a41SAnton Vorontsov { 2463bf74a41SAnton Vorontsov const char *ret; 2473bf74a41SAnton Vorontsov size_t len; 2483bf74a41SAnton Vorontsov 2493bf74a41SAnton Vorontsov setenv("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;" 2503bf74a41SAnton Vorontsov "key3;:,:=;key4", 1); 2513bf74a41SAnton Vorontsov 2523bf74a41SAnton Vorontsov ret = hwconfig_arg("key1", &len); 2533bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2543bf74a41SAnton Vorontsov assert(len == 29); 2553bf74a41SAnton Vorontsov assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2")); 2563bf74a41SAnton Vorontsov assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len)); 2573bf74a41SAnton Vorontsov 2583bf74a41SAnton Vorontsov ret = hwconfig_subarg("key1", "subkey1", &len); 2593bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2603bf74a41SAnton Vorontsov assert(len == 6); 2613bf74a41SAnton Vorontsov assert(hwconfig_subarg_cmp("key1", "subkey1", "value1")); 2623bf74a41SAnton Vorontsov assert(!strncmp(ret, "value1", len)); 2633bf74a41SAnton Vorontsov 2643bf74a41SAnton Vorontsov ret = hwconfig_subarg("key1", "subkey2", &len); 2653bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2663bf74a41SAnton Vorontsov assert(len == 6); 2673bf74a41SAnton Vorontsov assert(hwconfig_subarg_cmp("key1", "subkey2", "value2")); 2683bf74a41SAnton Vorontsov assert(!strncmp(ret, "value2", len)); 2693bf74a41SAnton Vorontsov 2703bf74a41SAnton Vorontsov ret = hwconfig_arg("key2", &len); 2713bf74a41SAnton Vorontsov printf("%zd %.*s\n", len, (int)len, ret); 2723bf74a41SAnton Vorontsov assert(len == 6); 2733bf74a41SAnton Vorontsov assert(hwconfig_arg_cmp("key2", "value3")); 2743bf74a41SAnton Vorontsov assert(!strncmp(ret, "value3", len)); 2753bf74a41SAnton Vorontsov 2763bf74a41SAnton Vorontsov assert(hwconfig("key3")); 2773bf74a41SAnton Vorontsov assert(hwconfig_arg("key4", &len) == NULL); 2783bf74a41SAnton Vorontsov assert(hwconfig_arg("bogus", &len) == NULL); 2793bf74a41SAnton Vorontsov 2803bf74a41SAnton Vorontsov unsetenv("hwconfig"); 2813bf74a41SAnton Vorontsov 2823bf74a41SAnton Vorontsov assert(hwconfig(NULL) == 0); 2833bf74a41SAnton Vorontsov assert(hwconfig("") == 0); 2843bf74a41SAnton Vorontsov assert(hwconfig("key3") == 0); 2853bf74a41SAnton Vorontsov 2863bf74a41SAnton Vorontsov return 0; 2873bf74a41SAnton Vorontsov } 2883bf74a41SAnton Vorontsov #endif /* HWCONFIG_TEST */ 289