uboot/common/env_callback.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2012
   3 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <environment.h>
  26
  27#if defined(CONFIG_NEEDS_MANUAL_RELOC)
  28DECLARE_GLOBAL_DATA_PTR;
  29#endif
  30
  31/*
  32 * Look up a callback function pointer by name
  33 */
  34static struct env_clbk_tbl *find_env_callback(const char *name)
  35{
  36        struct env_clbk_tbl *clbkp;
  37        int i;
  38        int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
  39
  40        if (name == NULL)
  41                return NULL;
  42
  43        /* look up the callback in the linker-list */
  44        for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
  45             i < num_callbacks;
  46             i++, clbkp++) {
  47                if (strcmp(name, clbkp->name) == 0)
  48                        return clbkp;
  49        }
  50
  51        return NULL;
  52}
  53
  54/*
  55 * Look for a possible callback for a newly added variable
  56 * This is called specifically when the variable did not exist in the hash
  57 * previously, so the blanket update did not find this variable.
  58 */
  59void env_callback_init(ENTRY *var_entry)
  60{
  61        const char *var_name = var_entry->key;
  62        const char *callback_list = getenv(ENV_CALLBACK_VAR);
  63        char callback_name[256] = "";
  64        struct env_clbk_tbl *clbkp;
  65        int ret = 1;
  66
  67        /* look in the ".callbacks" var for a reference to this variable */
  68        if (callback_list != NULL)
  69                ret = env_attr_lookup(callback_list, var_name, callback_name);
  70
  71        /* only if not found there, look in the static list */
  72        if (ret)
  73                ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
  74                        callback_name);
  75
  76        /* if an association was found, set the callback pointer */
  77        if (!ret && strlen(callback_name)) {
  78                clbkp = find_env_callback(callback_name);
  79                if (clbkp != NULL)
  80#if defined(CONFIG_NEEDS_MANUAL_RELOC)
  81                        var_entry->callback = clbkp->callback + gd->reloc_off;
  82#else
  83                        var_entry->callback = clbkp->callback;
  84#endif
  85        }
  86}
  87
  88/*
  89 * Called on each existing env var prior to the blanket update since removing
  90 * a callback association should remove its callback.
  91 */
  92static int clear_callback(ENTRY *entry)
  93{
  94        entry->callback = NULL;
  95
  96        return 0;
  97}
  98
  99/*
 100 * Call for each element in the list that associates variables to callbacks
 101 */
 102static int set_callback(const char *name, const char *value)
 103{
 104        ENTRY e, *ep;
 105        struct env_clbk_tbl *clbkp;
 106
 107        e.key   = name;
 108        e.data  = NULL;
 109        hsearch_r(e, FIND, &ep, &env_htab, 0);
 110
 111        /* does the env variable actually exist? */
 112        if (ep != NULL) {
 113                /* the assocaition delares no callback, so remove the pointer */
 114                if (value == NULL || strlen(value) == 0)
 115                        ep->callback = NULL;
 116                else {
 117                        /* assign the requested callback */
 118                        clbkp = find_env_callback(value);
 119                        if (clbkp != NULL)
 120#if defined(CONFIG_NEEDS_MANUAL_RELOC)
 121                                ep->callback = clbkp->callback + gd->reloc_off;
 122#else
 123                                ep->callback = clbkp->callback;
 124#endif
 125                }
 126        }
 127
 128        return 0;
 129}
 130
 131static int on_callbacks(const char *name, const char *value, enum env_op op,
 132        int flags)
 133{
 134        /* remove all callbacks */
 135        hwalk_r(&env_htab, clear_callback);
 136
 137        /* configure any static callback bindings */
 138        env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
 139        /* configure any dynamic callback bindings */
 140        env_attr_walk(value, set_callback);
 141
 142        return 0;
 143}
 144U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
 145