xref: /OK3568_Linux_fs/u-boot/common/hwconfig.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * An inteface for configuring a hardware via u-boot environment.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (c) 2009  MontaVista Software, Inc.
5*4882a593Smuzhiyun  * Copyright 2011 Freescale Semiconductor, Inc.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #ifndef HWCONFIG_TEST
13*4882a593Smuzhiyun #include <config.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <exports.h>
16*4882a593Smuzhiyun #include <hwconfig.h>
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/string.h>
19*4882a593Smuzhiyun #else
20*4882a593Smuzhiyun #include <stdio.h>
21*4882a593Smuzhiyun #include <stdlib.h>
22*4882a593Smuzhiyun #include <string.h>
23*4882a593Smuzhiyun #include <assert.h>
24*4882a593Smuzhiyun #define min(a, b) (((a) < (b)) ? (a) : (b))
25*4882a593Smuzhiyun #endif /* HWCONFIG_TEST */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
28*4882a593Smuzhiyun 
hwconfig_parse(const char * opts,size_t maxlen,const char * opt,char * stopchs,char eqch,size_t * arglen)29*4882a593Smuzhiyun static const char *hwconfig_parse(const char *opts, size_t maxlen,
30*4882a593Smuzhiyun 				  const char *opt, char *stopchs, char eqch,
31*4882a593Smuzhiyun 				  size_t *arglen)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	size_t optlen = strlen(opt);
34*4882a593Smuzhiyun 	char *str;
35*4882a593Smuzhiyun 	const char *start = opts;
36*4882a593Smuzhiyun 	const char *end;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun next:
39*4882a593Smuzhiyun 	str = strstr(opts, opt);
40*4882a593Smuzhiyun 	end = str + optlen;
41*4882a593Smuzhiyun 	if (end - start > maxlen)
42*4882a593Smuzhiyun 		return NULL;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (str && (str == opts || strpbrk(str - 1, stopchs) == str - 1) &&
45*4882a593Smuzhiyun 			(strpbrk(end, stopchs) == end || *end == eqch ||
46*4882a593Smuzhiyun 			 *end == '\0')) {
47*4882a593Smuzhiyun 		const char *arg_end;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 		if (!arglen)
50*4882a593Smuzhiyun 			return str;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 		if (*end != eqch)
53*4882a593Smuzhiyun 			return NULL;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 		arg_end = strpbrk(str, stopchs);
56*4882a593Smuzhiyun 		if (!arg_end)
57*4882a593Smuzhiyun 			*arglen = min(maxlen, strlen(str)) - optlen - 1;
58*4882a593Smuzhiyun 		else
59*4882a593Smuzhiyun 			*arglen = arg_end - end - 1;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		return end + 1;
62*4882a593Smuzhiyun 	} else if (str) {
63*4882a593Smuzhiyun 		opts = end;
64*4882a593Smuzhiyun 		goto next;
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 	return NULL;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun const char cpu_hwconfig[] __attribute__((weak)) = "";
70*4882a593Smuzhiyun const char board_hwconfig[] __attribute__((weak)) = "";
71*4882a593Smuzhiyun 
__hwconfig(const char * opt,size_t * arglen,const char * env_hwconfig)72*4882a593Smuzhiyun static const char *__hwconfig(const char *opt, size_t *arglen,
73*4882a593Smuzhiyun 			      const char *env_hwconfig)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	const char *ret;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/* if we are passed a buffer use it, otherwise try the environment */
78*4882a593Smuzhiyun 	if (!env_hwconfig) {
79*4882a593Smuzhiyun 		if (!(gd->flags & GD_FLG_ENV_READY)) {
80*4882a593Smuzhiyun 			printf("WARNING: Calling __hwconfig without a buffer "
81*4882a593Smuzhiyun 					"and before environment is ready\n");
82*4882a593Smuzhiyun 			return NULL;
83*4882a593Smuzhiyun 		}
84*4882a593Smuzhiyun 		env_hwconfig = env_get("hwconfig");
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (env_hwconfig) {
88*4882a593Smuzhiyun 		ret = hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
89*4882a593Smuzhiyun 				      opt, ";", ':', arglen);
90*4882a593Smuzhiyun 		if (ret)
91*4882a593Smuzhiyun 			return ret;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	ret = hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
95*4882a593Smuzhiyun 			opt, ";", ':', arglen);
96*4882a593Smuzhiyun 	if (ret)
97*4882a593Smuzhiyun 		return ret;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
100*4882a593Smuzhiyun 			opt, ";", ':', arglen);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * hwconfig_f - query if a particular hwconfig option is specified
105*4882a593Smuzhiyun  * @opt:	a string representing an option
106*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * This call can be used to find out whether U-Boot should configure
109*4882a593Smuzhiyun  * a particular hardware option.
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * Returns non-zero value if the hardware option can be used and thus
112*4882a593Smuzhiyun  * should be configured, 0 otherwise.
113*4882a593Smuzhiyun  *
114*4882a593Smuzhiyun  * This function also returns non-zero value if CONFIG_HWCONFIG is
115*4882a593Smuzhiyun  * undefined.
116*4882a593Smuzhiyun  *
117*4882a593Smuzhiyun  * Returning non-zero value without CONFIG_HWCONFIG has its crucial
118*4882a593Smuzhiyun  * purpose: the hwconfig() call should be a "transparent" interface,
119*4882a593Smuzhiyun  * e.g. if a board doesn't need hwconfig facility, then we assume
120*4882a593Smuzhiyun  * that the board file only calls things that are actually used, so
121*4882a593Smuzhiyun  * hwconfig() will always return true result.
122*4882a593Smuzhiyun  */
hwconfig_f(const char * opt,char * buf)123*4882a593Smuzhiyun int hwconfig_f(const char *opt, char *buf)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	return !!__hwconfig(opt, NULL, buf);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /*
129*4882a593Smuzhiyun  * hwconfig_arg_f - get hwconfig option's argument
130*4882a593Smuzhiyun  * @opt:	a string representing an option
131*4882a593Smuzhiyun  * @arglen:	a pointer to an allocated size_t variable
132*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
133*4882a593Smuzhiyun  *
134*4882a593Smuzhiyun  * Unlike hwconfig_f() function, this function returns a pointer to the
135*4882a593Smuzhiyun  * start of the hwconfig arguments, if option is not found or it has
136*4882a593Smuzhiyun  * no specified arguments, the function returns NULL pointer.
137*4882a593Smuzhiyun  *
138*4882a593Smuzhiyun  * If CONFIG_HWCONFIG is undefined, the function returns "", and
139*4882a593Smuzhiyun  * arglen is set to 0.
140*4882a593Smuzhiyun  */
hwconfig_arg_f(const char * opt,size_t * arglen,char * buf)141*4882a593Smuzhiyun const char *hwconfig_arg_f(const char *opt, size_t *arglen, char *buf)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	return __hwconfig(opt, arglen, buf);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun  * hwconfig_arg_cmp_f - compare hwconfig option's argument
148*4882a593Smuzhiyun  * @opt:	a string representing an option
149*4882a593Smuzhiyun  * @arg:	a string for comparing an option's argument
150*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
151*4882a593Smuzhiyun  *
152*4882a593Smuzhiyun  * This call is similar to hwconfig_arg_f, but instead of returning
153*4882a593Smuzhiyun  * hwconfig argument and its length, it is comparing it to @arg.
154*4882a593Smuzhiyun  *
155*4882a593Smuzhiyun  * Returns non-zero value if @arg matches, 0 otherwise.
156*4882a593Smuzhiyun  *
157*4882a593Smuzhiyun  * If CONFIG_HWCONFIG is undefined, the function returns a non-zero
158*4882a593Smuzhiyun  * value, i.e. the argument matches.
159*4882a593Smuzhiyun  */
hwconfig_arg_cmp_f(const char * opt,const char * arg,char * buf)160*4882a593Smuzhiyun int hwconfig_arg_cmp_f(const char *opt, const char *arg, char *buf)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	const char *argstr;
163*4882a593Smuzhiyun 	size_t arglen;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	argstr = hwconfig_arg_f(opt, &arglen, buf);
166*4882a593Smuzhiyun 	if (!argstr || arglen != strlen(arg))
167*4882a593Smuzhiyun 		return 0;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return !strncmp(argstr, arg, arglen);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun  * hwconfig_sub_f - query if a particular hwconfig sub-option is specified
174*4882a593Smuzhiyun  * @opt:	a string representing an option
175*4882a593Smuzhiyun  * @subopt:	a string representing a sub-option
176*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
177*4882a593Smuzhiyun  *
178*4882a593Smuzhiyun  * This call is similar to hwconfig_f(), except that it takes additional
179*4882a593Smuzhiyun  * argument @subopt. In this example:
180*4882a593Smuzhiyun  * 	"dr_usb:mode=peripheral"
181*4882a593Smuzhiyun  * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its
182*4882a593Smuzhiyun  * argument.
183*4882a593Smuzhiyun  */
hwconfig_sub_f(const char * opt,const char * subopt,char * buf)184*4882a593Smuzhiyun int hwconfig_sub_f(const char *opt, const char *subopt, char *buf)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	size_t arglen;
187*4882a593Smuzhiyun 	const char *arg;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	arg = __hwconfig(opt, &arglen, buf);
190*4882a593Smuzhiyun 	if (!arg)
191*4882a593Smuzhiyun 		return 0;
192*4882a593Smuzhiyun 	return !!hwconfig_parse(arg, arglen, subopt, ",;", '=', NULL);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun /*
196*4882a593Smuzhiyun  * hwconfig_subarg_f - get hwconfig sub-option's argument
197*4882a593Smuzhiyun  * @opt:	a string representing an option
198*4882a593Smuzhiyun  * @subopt:	a string representing a sub-option
199*4882a593Smuzhiyun  * @subarglen:	a pointer to an allocated size_t variable
200*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
201*4882a593Smuzhiyun  *
202*4882a593Smuzhiyun  * This call is similar to hwconfig_arg_f(), except that it takes an
203*4882a593Smuzhiyun  * additional argument @subopt, and so works with sub-options.
204*4882a593Smuzhiyun  */
hwconfig_subarg_f(const char * opt,const char * subopt,size_t * subarglen,char * buf)205*4882a593Smuzhiyun const char *hwconfig_subarg_f(const char *opt, const char *subopt,
206*4882a593Smuzhiyun 			      size_t *subarglen, char *buf)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	size_t arglen;
209*4882a593Smuzhiyun 	const char *arg;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	arg = __hwconfig(opt, &arglen, buf);
212*4882a593Smuzhiyun 	if (!arg)
213*4882a593Smuzhiyun 		return NULL;
214*4882a593Smuzhiyun 	return hwconfig_parse(arg, arglen, subopt, ",;", '=', subarglen);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun /*
218*4882a593Smuzhiyun  * hwconfig_arg_cmp_f - compare hwconfig sub-option's argument
219*4882a593Smuzhiyun  * @opt:	a string representing an option
220*4882a593Smuzhiyun  * @subopt:	a string representing a sub-option
221*4882a593Smuzhiyun  * @subarg:	a string for comparing an sub-option's argument
222*4882a593Smuzhiyun  * @buf:	if non-NULL use this buffer to parse, otherwise try env
223*4882a593Smuzhiyun  *
224*4882a593Smuzhiyun  * This call is similar to hwconfig_arg_cmp_f, except that it takes an
225*4882a593Smuzhiyun  * additional argument @subopt, and so works with sub-options.
226*4882a593Smuzhiyun  */
hwconfig_subarg_cmp_f(const char * opt,const char * subopt,const char * subarg,char * buf)227*4882a593Smuzhiyun int hwconfig_subarg_cmp_f(const char *opt, const char *subopt,
228*4882a593Smuzhiyun 			  const char *subarg, char *buf)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	const char *argstr;
231*4882a593Smuzhiyun 	size_t arglen;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	argstr = hwconfig_subarg_f(opt, subopt, &arglen, buf);
234*4882a593Smuzhiyun 	if (!argstr || arglen != strlen(subarg))
235*4882a593Smuzhiyun 		return 0;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	return !strncmp(argstr, subarg, arglen);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun #ifdef HWCONFIG_TEST
main()241*4882a593Smuzhiyun int main()
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	const char *ret;
244*4882a593Smuzhiyun 	size_t len;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	env_set("hwconfig", "key1:subkey1=value1,subkey2=value2;key2:value3;;;;"
247*4882a593Smuzhiyun 			   "key3;:,:=;key4", 1);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	ret = hwconfig_arg("key1", &len);
250*4882a593Smuzhiyun 	printf("%zd %.*s\n", len, (int)len, ret);
251*4882a593Smuzhiyun 	assert(len == 29);
252*4882a593Smuzhiyun 	assert(hwconfig_arg_cmp("key1", "subkey1=value1,subkey2=value2"));
253*4882a593Smuzhiyun 	assert(!strncmp(ret, "subkey1=value1,subkey2=value2", len));
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	ret = hwconfig_subarg("key1", "subkey1", &len);
256*4882a593Smuzhiyun 	printf("%zd %.*s\n", len, (int)len, ret);
257*4882a593Smuzhiyun 	assert(len == 6);
258*4882a593Smuzhiyun 	assert(hwconfig_subarg_cmp("key1", "subkey1", "value1"));
259*4882a593Smuzhiyun 	assert(!strncmp(ret, "value1", len));
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	ret = hwconfig_subarg("key1", "subkey2", &len);
262*4882a593Smuzhiyun 	printf("%zd %.*s\n", len, (int)len, ret);
263*4882a593Smuzhiyun 	assert(len == 6);
264*4882a593Smuzhiyun 	assert(hwconfig_subarg_cmp("key1", "subkey2", "value2"));
265*4882a593Smuzhiyun 	assert(!strncmp(ret, "value2", len));
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	ret = hwconfig_arg("key2", &len);
268*4882a593Smuzhiyun 	printf("%zd %.*s\n", len, (int)len, ret);
269*4882a593Smuzhiyun 	assert(len == 6);
270*4882a593Smuzhiyun 	assert(hwconfig_arg_cmp("key2", "value3"));
271*4882a593Smuzhiyun 	assert(!strncmp(ret, "value3", len));
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	assert(hwconfig("key3"));
274*4882a593Smuzhiyun 	assert(hwconfig_arg("key4", &len) == NULL);
275*4882a593Smuzhiyun 	assert(hwconfig_arg("bogus", &len) == NULL);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	unenv_set("hwconfig");
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	assert(hwconfig(NULL) == 0);
280*4882a593Smuzhiyun 	assert(hwconfig("") == 0);
281*4882a593Smuzhiyun 	assert(hwconfig("key3") == 0);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	return 0;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun #endif /* HWCONFIG_TEST */
286