157580Smjacob// SPDX-License-Identifier: GPL-2.0+ 257580Smjacob/* 357580Smjacob * (C) Copyright 2012 457580Smjacob * Joe Hershberger, National Instruments, joe.hershberger@ni.com 557580Smjacob */ 657580Smjacob 757580Smjacob#include <common.h> 857580Smjacob#include <env.h> 957580Smjacob#include <env_internal.h> 1057580Smjacob#include <asm/global_data.h> 1157580Smjacob 1257580Smjacob/* 1357580Smjacob * Look up a callback function pointer by name 1457580Smjacob */ 1557580Smjacobstatic struct env_clbk_tbl *find_env_callback(const char *name) 1657580Smjacob{ 1757580Smjacob struct env_clbk_tbl *clbkp; 1857580Smjacob int i; 1957580Smjacob int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); 2057580Smjacob 2157580Smjacob if (name == NULL) 2257580Smjacob return NULL; 2357580Smjacob 2457580Smjacob /* look up the callback in the linker-list */ 2557580Smjacob for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); 2657580Smjacob i < num_callbacks; 2757580Smjacob i++, clbkp++) { 2857580Smjacob if (strcmp(name, clbkp->name) == 0) 2957580Smjacob return clbkp; 3057580Smjacob } 3157580Smjacob 3257580Smjacob return NULL; 3357580Smjacob} 3457580Smjacob 35293865Sallanjudestatic int first_call = 1; 36293865Sallanjudestatic const char *callback_list; 37293865Sallanjude 38293865Sallanjude/* 39293865Sallanjude * Look for a possible callback for a newly added variable 4057580Smjacob * This is called specifically when the variable did not exist in the hash 41235911Smav * previously, so the blanket update did not find this variable. 42235911Smav */ 4357580Smjacobvoid env_callback_init(struct env_entry *var_entry) 4457580Smjacob{ 4557580Smjacob const char *var_name = var_entry->key; 46235911Smav char callback_name[256] = ""; 47235911Smav struct env_clbk_tbl *clbkp; 4857580Smjacob int ret = 1; 49198934Sdelphij 50198934Sdelphij if (first_call) { 51293865Sallanjude callback_list = env_get(ENV_CALLBACK_VAR); 52293865Sallanjude first_call = 0; 53293865Sallanjude } 54293865Sallanjude 55293865Sallanjude var_entry->callback = NULL; 56293865Sallanjude 57293865Sallanjude /* look in the ".callbacks" var for a reference to this variable */ 5857580Smjacob if (callback_list != NULL) 59198934Sdelphij ret = env_attr_lookup(callback_list, var_name, callback_name); 6057580Smjacob 6157580Smjacob /* only if not found there, look in the static list */ 6257580Smjacob if (ret) 6357580Smjacob ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, 64235911Smav callback_name); 6557580Smjacob 6657580Smjacob /* if an association was found, set the callback pointer */ 67235911Smav if (!ret && strlen(callback_name)) { 68235911Smav clbkp = find_env_callback(callback_name); 6957580Smjacob if (clbkp != NULL) 70235911Smav var_entry->callback = clbkp->callback; 71235911Smav } 7257580Smjacob} 73235911Smav 74235911Smav/* 7557580Smjacob * Called on each existing env var prior to the blanket update since removing 76235911Smav * a callback association should remove its callback. 77235911Smav */ 7857580Smjacobstatic int clear_callback(struct env_entry *entry) 79235911Smav{ 8057580Smjacob entry->callback = NULL; 8157580Smjacob 82235911Smav return 0; 8357580Smjacob} 8457580Smjacob 85235911Smav/* 86242621Smav * Call for each element in the list that associates variables to callbacks 8757580Smjacob */ 88235911Smavstatic int set_callback(const char *name, const char *value, void *priv) 89235911Smav{ 9057580Smjacob struct env_entry e, *ep; 91235911Smav struct env_clbk_tbl *clbkp; 92235911Smav 9357580Smjacob e.key = name; 94235911Smav e.data = NULL; 95235911Smav e.callback = NULL; 9657580Smjacob hsearch_r(e, ENV_FIND, &ep, &env_htab, 0); 97235911Smav 98235911Smav /* does the env variable actually exist? */ 99235911Smav if (ep != NULL) { 100235911Smav /* the assocaition delares no callback, so remove the pointer */ 10157580Smjacob if (value == NULL || strlen(value) == 0) 10257580Smjacob ep->callback = NULL; 103235911Smav else { 104235911Smav /* assign the requested callback */ 10557580Smjacob clbkp = find_env_callback(value); 106235911Smav if (clbkp != NULL) 107222336Smav ep->callback = clbkp->callback; 108222336Smav } 109235911Smav } 110235911Smav 11157580Smjacob return 0; 112235911Smav} 11357580Smjacob 11457580Smjacobstatic int on_callbacks(const char *name, const char *value, enum env_op op, 115235911Smav int flags) 11657580Smjacob{ 11757580Smjacob /* remove all callbacks */ 118235911Smav hwalk_r(&env_htab, clear_callback); 11957580Smjacob 12057580Smjacob /* configure any static callback bindings */ 121235911Smav env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback, NULL); 12257580Smjacob /* configure any dynamic callback bindings */ 12357580Smjacob env_attr_walk(value, set_callback, NULL); 124235911Smav 125235911Smav return 0; 12657580Smjacob} 127235911SmavU_BOOT_ENV_CALLBACK(callbacks, on_callbacks); 128235911Smav