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