xref: /openbmc/u-boot/common/hwconfig.c (revision a380279b)
1 /*
2  * An inteface for configuring a hardware via u-boot environment.
3  *
4  * Copyright (c) 2009  MontaVista Software, Inc.
5  *
6  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  */
13 
14 #include <config.h>
15 #include <common.h>
16 #include <exports.h>
17 #include <hwconfig.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 
21 static const char *hwconfig_parse(const char *opts, size_t maxlen,
22 				  const char *opt, char stopch, char eqch,
23 				  size_t *arglen)
24 {
25 	size_t optlen = strlen(opt);
26 	char *str;
27 	const char *start = opts;
28 	const char *end;
29 
30 next:
31 	str = strstr(opts, opt);
32 	end = str + optlen;
33 	if (end - start > maxlen)
34 		return NULL;
35 
36 	if (str && (str == opts || str[-1] == stopch) &&
37 			(*end == stopch || *end == eqch || *end == '\0')) {
38 		const char *arg_end;
39 
40 		if (!arglen)
41 			return str;
42 
43 		if (*end != eqch)
44 			return NULL;
45 
46 		arg_end = strchr(str, stopch);
47 		if (!arg_end)
48 			*arglen = min(maxlen, strlen(str)) - optlen - 1;
49 		else
50 			*arglen = arg_end - end - 1;
51 
52 		return end + 1;
53 	} else if (str) {
54 		opts = end;
55 		goto next;
56 	}
57 	return NULL;
58 }
59 
60 const char *cpu_hwconfig __attribute__((weak));
61 const char *board_hwconfig __attribute__((weak));
62 
63 static const char *__hwconfig(const char *opt, size_t *arglen)
64 {
65 	const char *env_hwconfig = getenv("hwconfig");
66 
67 	if (env_hwconfig)
68 		return hwconfig_parse(env_hwconfig, strlen(env_hwconfig),
69 				      opt, ';', ':', arglen);
70 
71 	if (board_hwconfig)
72 		return hwconfig_parse(board_hwconfig, strlen(board_hwconfig),
73 				      opt, ';', ':', arglen);
74 
75 	if (cpu_hwconfig)
76 		return hwconfig_parse(cpu_hwconfig, strlen(cpu_hwconfig),
77 				      opt, ';', ':', arglen);
78 
79 	return NULL;
80 }
81 
82 /*
83  * hwconfig - query if a particular hwconfig option is specified
84  * @opt:	a string representing an option
85  *
86  * This call can be used to find out whether U-Boot should configure
87  * a particular hardware option.
88  *
89  * Returns non-zero value if the hardware option can be used and thus
90  * should be configured, 0 otherwise.
91  *
92  * This function also returns non-zero value if CONFIG_HWCONFIG is
93  * undefined.
94  *
95  * Returning non-zero value without CONFIG_HWCONFIG has its crucial
96  * purpose: the hwconfig() call should be a "transparent" interface,
97  * e.g. if a board doesn't need hwconfig facility, then we assume
98  * that the board file only calls things that are actually used, so
99  * hwconfig() will always return true result.
100  */
101 int hwconfig(const char *opt)
102 {
103 	return !!__hwconfig(opt, NULL);
104 }
105 
106 /*
107  * hwconfig_arg - get hwconfig option's argument
108  * @opt:	a string representing an option
109  * @arglen:	a pointer to an allocated size_t variable
110  *
111  * Unlike hwconfig() function, this function returns a pointer to the
112  * start of the hwconfig arguments, if option is not found or it has
113  * no specified arguments, the function returns NULL pointer.
114  *
115  * If CONFIG_HWCONFIG is undefined, the function returns "", and
116  * arglen is set to 0.
117  */
118 const char *hwconfig_arg(const char *opt, size_t *arglen)
119 {
120 	return __hwconfig(opt, arglen);
121 }
122 
123 /*
124  * hwconfig_arg_cmp - compare hwconfig option's argument
125  * @opt:	a string representing an option
126  * @arg:	a string for comparing an option's argument
127  *
128  * This call is similar to hwconfig_arg, but instead of returning
129  * hwconfig argument and its length, it is comparing it to @arg.
130  *
131  * Returns non-zero value if @arg matches, 0 otherwise.
132  *
133  * If CONFIG_HWCONFIG is undefined, the function returns a non-zero
134  * value, i.e. the argument matches.
135  */
136 int hwconfig_arg_cmp(const char *opt, const char *arg)
137 {
138 	const char *argstr;
139 	size_t arglen;
140 
141 	argstr = hwconfig_arg(opt, &arglen);
142 	if (!argstr || arglen != strlen(arg))
143 		return 0;
144 
145 	return !strncmp(argstr, arg, arglen);
146 }
147 
148 /*
149  * hwconfig_sub - query if a particular hwconfig sub-option is specified
150  * @opt:	a string representing an option
151  * @subopt:	a string representing a sub-option
152  *
153  * This call is similar to hwconfig(), except that it takes additional
154  * argument @subopt. In this example:
155  * 	"dr_usb:mode=peripheral"
156  * "dr_usb" is an option, "mode" is a sub-option, and "peripheral" is its
157  * argument.
158  */
159 int hwconfig_sub(const char *opt, const char *subopt)
160 {
161 	size_t arglen;
162 	const char *arg;
163 
164 	arg = __hwconfig(opt, &arglen);
165 	if (!arg)
166 		return 0;
167 	return !!hwconfig_parse(arg, arglen, subopt, ',', '=', NULL);
168 }
169 
170 /*
171  * hwconfig_subarg - get hwconfig sub-option's argument
172  * @opt:	a string representing an option
173  * @subopt:	a string representing a sub-option
174  * @subarglen:	a pointer to an allocated size_t variable
175  *
176  * This call is similar to hwconfig_arg(), except that it takes an additional
177  * argument @subopt, and so works with sub-options.
178  */
179 const char *hwconfig_subarg(const char *opt, const char *subopt,
180 			    size_t *subarglen)
181 {
182 	size_t arglen;
183 	const char *arg;
184 
185 	arg = __hwconfig(opt, &arglen);
186 	if (!arg)
187 		return NULL;
188 	return hwconfig_parse(arg, arglen, subopt, ',', '=', subarglen);
189 }
190 
191 /*
192  * hwconfig_arg_cmp - compare hwconfig sub-option's argument
193  * @opt:	a string representing an option
194  * @subopt:	a string representing a sub-option
195  * @subarg:	a string for comparing an sub-option's argument
196  *
197  * This call is similar to hwconfig_arg_cmp, except that it takes an additional
198  * argument @subopt, and so works with sub-options.
199  */
200 int hwconfig_subarg_cmp(const char *opt, const char *subopt, const char *subarg)
201 {
202 	const char *argstr;
203 	size_t arglen;
204 
205 	argstr = hwconfig_subarg(opt, subopt, &arglen);
206 	if (!argstr || arglen != strlen(subarg))
207 		return 0;
208 
209 	return !strncmp(argstr, subarg, arglen);
210 }
211