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