uboot/common/env_callback.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2012
   3 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <environment.h>
  10
  11#if defined(CONFIG_NEEDS_MANUAL_RELOC)
  12DECLARE_GLOBAL_DATA_PTR;
  13#endif
  14
  15/*
  16 * Look up a callback function pointer by name
  17 */
  18static struct env_clbk_tbl *find_env_callback(const char *name)
  19{
  20        struct env_clbk_tbl *clbkp;
  21        int i;
  22        int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
  23
  24        if (name == NULL)
  25                return NULL;
  26
  27        /* look up the callback in the linker-list */
  28        for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
  29             i < num_callbacks;
  30             i++, clbkp++) {
  31                if (strcmp(name, clbkp->name) == 0)
  32                        return clbkp;
  33        }
  34
  35        return NULL;
  36}
  37
  38static int first_call = 1;
  39static const char *callback_list;
  40
  41/*
  42 * Look for a possible callback for a newly added variable
  43 * This is called specifically when the variable did not exist in the hash
  44 * previously, so the blanket update did not find this variable.
  45 */
  46void env_callback_init(ENTRY *var_entry)
  47{
  48        const char *var_name = var_entry->key;
  49        char callback_name[256] = "";
  50        struct env_clbk_tbl *clbkp;
  51        int ret = 1;
  52
  53        if (first_call) {
  54                callback_list = getenv(ENV_CALLBACK_VAR);
  55                first_call = 0;
  56        }
  57
  58        /* look in the ".callbacks" var for a reference to this variable */
  59        if (callback_list != NULL)
  60                ret = env_attr_lookup(callback_list, var_name, callback_name);
  61
  62        /* only if not found there, look in the static list */
  63        if (ret)
  64                ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
  65                        callback_name);
  66
  67        /* if an association was found, set the callback pointer */
  68        if (!ret && strlen(callback_name)) {
  69                clbkp = find_env_callback(callback_name);
  70                if (clbkp != NULL)
  71#if defined(CONFIG_NEEDS_MANUAL_RELOC)
  72                        var_entry->callback = clbkp->callback + gd->reloc_off;
  73#else
  74                        var_entry->callback = clbkp->callback;
  75#endif
  76        }
  77}
  78
  79/*
  80 * Called on each existing env var prior to the blanket update since removing
  81 * a callback association should remove its callback.
  82 */
  83static int clear_callback(ENTRY *entry)
  84{
  85        entry->callback = NULL;
  86
  87        return 0;
  88}
  89
  90/*
  91 * Call for each element in the list that associates variables to callbacks
  92 */
  93static int set_callback(const char *name, const char *value, void *priv)
  94{
  95        ENTRY e, *ep;
  96        struct env_clbk_tbl *clbkp;
  97
  98        e.key   = name;
  99        e.data  = NULL;
 100        e.callback = NULL;
 101        hsearch_r(e, FIND, &ep, &env_htab, 0);
 102
 103        /* does the env variable actually exist? */
 104        if (ep != NULL) {
 105                /* the assocaition delares no callback, so remove the pointer */
 106                if (value == NULL || strlen(value) == 0)
 107                        ep->callback = NULL;
 108                else {
 109                        /* assign the requested callback */
 110                        clbkp = find_env_callback(value);
 111                        if (clbkp != NULL)
 112#if defined(CONFIG_NEEDS_MANUAL_RELOC)
 113                                ep->callback = clbkp->callback + gd->reloc_off;
 114#else
 115                                ep->callback = clbkp->callback;
 116#endif
 117                }
 118        }
 119
 120        return 0;
 121}
 122
 123static int on_callbacks(const char *name, const char *value, enum env_op op,
 124        int flags)
 125{
 126        /* remove all callbacks */
 127        hwalk_r(&env_htab, clear_callback);
 128
 129        /* configure any static callback bindings */
 130        env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback, NULL);
 131        /* configure any dynamic callback bindings */
 132        env_attr_walk(value, set_callback, NULL);
 133
 134        return 0;
 135}
 136U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
 137