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