Blame view

common/hwconfig.c 7.75 KB
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
1
2
3
4
  /*
   * An inteface for configuring a hardware via u-boot environment.
   *
   * Copyright (c) 2009  MontaVista Software, Inc.
dd50af251   Kumar Gala   powerpc/8xxx: Add...
5
   * Copyright 2011 Freescale Semiconductor, Inc.
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
6
7
8
   *
   * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
9
   * SPDX-License-Identifier:	GPL-2.0+
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
10
   */
3bf74a418   Anton Vorontsov   hwconfig: Add som...
11
  #ifndef HWCONFIG_TEST
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
12
13
14
15
16
17
  #include <config.h>
  #include <common.h>
  #include <exports.h>
  #include <hwconfig.h>
  #include <linux/types.h>
  #include <linux/string.h>
3bf74a418   Anton Vorontsov   hwconfig: Add som...
18
19
20
21
22
23
24
  #else
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <assert.h>
  #define min(a, b) (((a) < (b)) ? (a) : (b))
  #endif /* HWCONFIG_TEST */
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
25

c4b115f53   Kumar Gala   hwconfig: Utilize...
26
  DECLARE_GLOBAL_DATA_PTR;
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
27
  static const char *hwconfig_parse(const char *opts, size_t maxlen,
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
28
  				  const char *opt, char *stopchs, char eqch,
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
29
30
31
32
33
34
35
36
37
38
39
40
  				  size_t *arglen)
  {
  	size_t optlen = strlen(opt);
  	char *str;
  	const char *start = opts;
  	const char *end;
  
  next:
  	str = strstr(opts, opt);
  	end = str + optlen;
  	if (end - start > maxlen)
  		return NULL;
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
41
42
43
  	if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) &&
  			(strpbrk(end, stopchs) == end || *end == eqch ||
  			 *end == '\0')) {
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
44
45
46
47
48
49
50
  		const char *arg_end;
  
  		if (!arglen)
  			return str;
  
  		if (*end != eqch)
  			return NULL;
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
51
  		arg_end = strpbrk(str, stopchs);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
52
53
54
55
56
57
58
59
60
61
62
63
  		if (!arg_end)
  			*arglen = min(maxlen, strlen(str)) - optlen - 1;
  		else
  			*arglen = arg_end - end - 1;
  
  		return end + 1;
  	} else if (str) {
  		opts = end;
  		goto next;
  	}
  	return NULL;
  }
b194577b2   Kumar Gala   hwconfig: Fix dum...
64
65
  const char cpu_hwconfig[] __attribute__((weak)) = "";
  const char board_hwconfig[] __attribute__((weak)) = "";
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
66

dd50af251   Kumar Gala   powerpc/8xxx: Add...
67
68
  static const char *__hwconfig(const char *opt, size_t *arglen,
  			      const char *env_hwconfig)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
69
  {
dd50af251   Kumar Gala   powerpc/8xxx: Add...
70
  	const char *ret;
c4b115f53   Kumar Gala   hwconfig: Utilize...
71

dd50af251   Kumar Gala   powerpc/8xxx: Add...
72
73
74
75
  	/* if we are passed a buffer use it, otherwise try the environment */
  	if (!env_hwconfig) {
  		if (!(gd->flags & GD_FLG_ENV_READY)) {
  			printf("WARNING: Calling __hwconfig without a buffer "
d1a24f061   Wolfgang Denk   Minor Coding Styl...
76
77
78
  					"and before environment is ready
  ");
  			return NULL;
dd50af251   Kumar Gala   powerpc/8xxx: Add...
79
  		}
00caae6d4   Simon Glass   env: Rename geten...
80
  		env_hwconfig = env_get("hwconfig");
c4b115f53   Kumar Gala   hwconfig: Utilize...
81
  	}
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
82

bb141079d   Kumar Gala   hwconfig: Fix han...
83
84
  	if (env_hwconfig) {
  		ret = hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
85
  				      opt, ";", ':', arglen);
bb141079d   Kumar Gala   hwconfig: Fix han...
86
87
88
  		if (ret)
  			return ret;
  	}
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
89

bb141079d   Kumar Gala   hwconfig: Fix han...
90
  	ret = hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
b194577b2   Kumar Gala   hwconfig: Fix dum...
91
  			opt, ";", ':', arglen);
bb141079d   Kumar Gala   hwconfig: Fix han...
92
93
  	if (ret)
  		return ret;
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
94

b194577b2   Kumar Gala   hwconfig: Fix dum...
95
96
  	return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
  			opt, ";", ':', arglen);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
97
98
99
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
100
   * hwconfig_f - query if a particular hwconfig option is specified
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
101
   * @opt:	a string representing an option
dd50af251   Kumar Gala   powerpc/8xxx: Add...
102
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
   *
   * This call can be used to find out whether U-Boot should configure
   * a particular hardware option.
   *
   * Returns non-zero value if the hardware option can be used and thus
   * should be configured, 0 otherwise.
   *
   * This function also returns non-zero value if CONFIG_HWCONFIG is
   * undefined.
   *
   * Returning non-zero value without CONFIG_HWCONFIG has its crucial
   * purpose: the hwconfig() call should be a "transparent" interface,
   * e.g. if a board doesn't need hwconfig facility, then we assume
   * that the board file only calls things that are actually used, so
   * hwconfig() will always return true result.
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
119
  int hwconfig_f(const char *opt, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
120
  {
dd50af251   Kumar Gala   powerpc/8xxx: Add...
121
  	return !!__hwconfig(opt, NULL, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
122
123
124
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
125
   * hwconfig_arg_f - get hwconfig option's argument
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
126
127
   * @opt:	a string representing an option
   * @arglen:	a pointer to an allocated size_t variable
dd50af251   Kumar Gala   powerpc/8xxx: Add...
128
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
129
   *
dd50af251   Kumar Gala   powerpc/8xxx: Add...
130
   * Unlike hwconfig_f() function, this function returns a pointer to the
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
131
132
133
134
135
136
   * start of the hwconfig arguments, if option is not found or it has
   * no specified arguments, the function returns NULL pointer.
   *
   * If CONFIG_HWCONFIG is undefined, the function returns "", and
   * arglen is set to 0.
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
137
  const char *hwconfig_arg_f(const char *opt, size_t *arglen, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
138
  {
dd50af251   Kumar Gala   powerpc/8xxx: Add...
139
  	return __hwconfig(opt, arglen, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
140
141
142
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
143
   * hwconfig_arg_cmp_f - compare hwconfig option's argument
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
144
145
   * @opt:	a string representing an option
   * @arg:	a string for comparing an option's argument
dd50af251   Kumar Gala   powerpc/8xxx: Add...
146
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
147
   *
dd50af251   Kumar Gala   powerpc/8xxx: Add...
148
   * This call is similar to hwconfig_arg_f, but instead of returning
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
149
150
151
152
153
154
155
   * hwconfig argument and its length, it is comparing it to @arg.
   *
   * Returns non-zero value if @arg matches, 0 otherwise.
   *
   * If CONFIG_HWCONFIG is undefined, the function returns a non-zero
   * value, i.e. the argument matches.
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
156
  int hwconfig_arg_cmp_f(const char *opt, const char *arg, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
157
158
159
  {
  	const char *argstr;
  	size_t arglen;
dd50af251   Kumar Gala   powerpc/8xxx: Add...
160
  	argstr = hwconfig_arg_f(opt, &arglen, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
161
162
163
164
165
166
167
  	if (!argstr || arglen != strlen(arg))
  		return 0;
  
  	return !strncmp(argstr, arg, arglen);
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
168
   * hwconfig_sub_f - query if a particular hwconfig sub-option is specified
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
169
170
   * @opt:	a string representing an option
   * @subopt:	a string representing a sub-option
dd50af251   Kumar Gala   powerpc/8xxx: Add...
171
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
172
   *
dd50af251   Kumar Gala   powerpc/8xxx: Add...
173
   * This call is similar to hwconfig_f(), except that it takes additional
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
174
175
176
177
178
   * argument @subopt. In this example:
   * 	"dr_usb:mode=peripheral"
   * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its
   * argument.
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
179
  int hwconfig_sub_f(const char *opt, const char *subopt, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
180
181
182
  {
  	size_t arglen;
  	const char *arg;
dd50af251   Kumar Gala   powerpc/8xxx: Add...
183
  	arg = __hwconfig(opt, &arglen, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
184
185
  	if (!arg)
  		return 0;
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
186
  	return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
187
188
189
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
190
   * hwconfig_subarg_f - get hwconfig sub-option's argument
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
191
192
193
   * @opt:	a string representing an option
   * @subopt:	a string representing a sub-option
   * @subarglen:	a pointer to an allocated size_t variable
dd50af251   Kumar Gala   powerpc/8xxx: Add...
194
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
195
   *
dd50af251   Kumar Gala   powerpc/8xxx: Add...
196
197
   * This call is similar to hwconfig_arg_f(), except that it takes an
   * additional argument @subopt, and so works with sub-options.
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
198
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
199
200
  const char *hwconfig_subarg_f(const char *opt, const char *subopt,
  			      size_t *subarglen, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
201
202
203
  {
  	size_t arglen;
  	const char *arg;
dd50af251   Kumar Gala   powerpc/8xxx: Add...
204
  	arg = __hwconfig(opt, &arglen, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
205
206
  	if (!arg)
  		return NULL;
81f8d3b02   Anton Vorontsov   hwconfig: Fix sto...
207
  	return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
208
209
210
  }
  
  /*
dd50af251   Kumar Gala   powerpc/8xxx: Add...
211
   * hwconfig_arg_cmp_f - compare hwconfig sub-option's argument
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
212
213
214
   * @opt:	a string representing an option
   * @subopt:	a string representing a sub-option
   * @subarg:	a string for comparing an sub-option's argument
dd50af251   Kumar Gala   powerpc/8xxx: Add...
215
   * @buf:	if non-NULL use this buffer to parse, otherwise try env
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
216
   *
dd50af251   Kumar Gala   powerpc/8xxx: Add...
217
218
   * This call is similar to hwconfig_arg_cmp_f, except that it takes an
   * additional argument @subopt, and so works with sub-options.
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
219
   */
dd50af251   Kumar Gala   powerpc/8xxx: Add...
220
221
  int hwconfig_subarg_cmp_f(const char *opt, const char *subopt,
  			  const char *subarg, char *buf)
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
222
223
224
  {
  	const char *argstr;
  	size_t arglen;
dd50af251   Kumar Gala   powerpc/8xxx: Add...
225
  	argstr = hwconfig_subarg_f(opt, subopt, &arglen, buf);
93f9dcf9e   Anton Vorontsov   Add simple hwconf...
226
227
228
229
230
  	if (!argstr || arglen != strlen(subarg))
  		return 0;
  
  	return !strncmp(argstr, subarg, arglen);
  }
3bf74a418   Anton Vorontsov   hwconfig: Add som...
231
232
233
234
235
236
  
  #ifdef HWCONFIG_TEST
  int main()
  {
  	const char *ret;
  	size_t len;
382bee57f   Simon Glass   env: Rename seten...
237
  	env_set("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;"
3bf74a418   Anton Vorontsov   hwconfig: Add som...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  			   "key3;:,:=;key4", 1);
  
  	ret = hwconfig_arg("key1", &len);
  	printf("%zd %.*s
  ", len, (int)len, ret);
  	assert(len == 29);
  	assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2"));
  	assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len));
  
  	ret = hwconfig_subarg("key1", "subkey1", &len);
  	printf("%zd %.*s
  ", len, (int)len, ret);
  	assert(len == 6);
  	assert(hwconfig_subarg_cmp("key1", "subkey1", "value1"));
  	assert(!strncmp(ret, "value1", len));
  
  	ret = hwconfig_subarg("key1", "subkey2", &len);
  	printf("%zd %.*s
  ", len, (int)len, ret);
  	assert(len == 6);
  	assert(hwconfig_subarg_cmp("key1", "subkey2", "value2"));
  	assert(!strncmp(ret, "value2", len));
  
  	ret = hwconfig_arg("key2", &len);
  	printf("%zd %.*s
  ", len, (int)len, ret);
  	assert(len == 6);
  	assert(hwconfig_arg_cmp("key2", "value3"));
  	assert(!strncmp(ret, "value3", len));
  
  	assert(hwconfig("key3"));
  	assert(hwconfig_arg("key4", &len) == NULL);
  	assert(hwconfig_arg("bogus", &len) == NULL);
382bee57f   Simon Glass   env: Rename seten...
271
  	unenv_set("hwconfig");
3bf74a418   Anton Vorontsov   hwconfig: Add som...
272
273
274
275
276
277
278
279
  
  	assert(hwconfig(NULL) == 0);
  	assert(hwconfig("") == 0);
  	assert(hwconfig("key3") == 0);
  
  	return 0;
  }
  #endif /* HWCONFIG_TEST */