]> Git Repo - J-u-boot.git/blob - boot/expo_build.c
Restore patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"
[J-u-boot.git] / boot / expo_build.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Building an expo from an FDT description
4  *
5  * Copyright 2022 Google LLC
6  * Written by Simon Glass <[email protected]>
7  */
8
9 #define LOG_CATEGORY    LOGC_EXPO
10
11 #include <expo.h>
12 #include <fdtdec.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <dm/ofnode.h>
16 #include <linux/libfdt.h>
17
18 /**
19  * struct build_info - Information to use when building
20  *
21  * @str_for_id: String for each ID in use, NULL if empty. The string is NULL
22  *      if there is nothing for this ID. Since ID 0 is never used, the first
23  *      element of this array is always NULL
24  * @str_count: Number of entries in @str_for_id
25  * @err_node: Node being processed (for error reporting)
26  * @err_prop: Property being processed (for error reporting)
27  */
28 struct build_info {
29         const char **str_for_id;
30         int str_count;
31         ofnode err_node;
32         const char *err_prop;
33 };
34
35 /**
36  * add_txt_str - Add a string or lookup its ID, then add to expo
37  *
38  * @info: Build information
39  * @node: Node describing scene
40  * @scn: Scene to add to
41  * @find_name: Name to look for (e.g. "title"). This will find a property called
42  * "title" if it exists, else will look up the string for "title-id"
43  * Return: ID of added string, or -ve on error
44  */
45 int add_txt_str(struct build_info *info, ofnode node, struct scene *scn,
46                 const char *find_name, uint obj_id)
47 {
48         const char *text;
49         uint str_id;
50         int ret;
51
52         info->err_prop = find_name;
53         text = ofnode_read_string(node, find_name);
54         if (!text) {
55                 char name[40];
56                 u32 id;
57
58                 snprintf(name, sizeof(name), "%s-id", find_name);
59                 ret = ofnode_read_u32(node, name, &id);
60                 if (ret)
61                         return log_msg_ret("id", -ENOENT);
62
63                 if (id >= info->str_count)
64                         return log_msg_ret("id", -E2BIG);
65                 text = info->str_for_id[id];
66                 if (!text)
67                         return log_msg_ret("id", -EINVAL);
68         }
69
70         ret = expo_str(scn->expo, find_name, 0, text);
71         if (ret < 0)
72                 return log_msg_ret("add", ret);
73         str_id = ret;
74
75         ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL);
76         if (ret < 0)
77                 return log_msg_ret("add", ret);
78
79         return ret;
80 }
81
82 /**
83  * add_txt_str_list - Add a list string or lookup its ID, then add to expo
84  *
85  * @info: Build information
86  * @node: Node describing scene
87  * @scn: Scene to add to
88  * @find_name: Name to look for (e.g. "title"). This will find a string-list
89  * property called "title" if it exists, else will look up the string in the
90  * "title-id" string list.
91  * Return: ID of added string, or -ve on error
92  */
93 int add_txt_str_list(struct build_info *info, ofnode node, struct scene *scn,
94                      const char *find_name, int index, uint obj_id)
95 {
96         const char *text;
97         uint str_id;
98         int ret;
99
100         ret = ofnode_read_string_index(node, find_name, index, &text);
101         if (ret) {
102                 char name[40];
103                 u32 id;
104
105                 snprintf(name, sizeof(name), "%s-id", find_name);
106                 ret = ofnode_read_u32_index(node, name, index, &id);
107                 if (ret)
108                         return log_msg_ret("id", -ENOENT);
109
110                 if (id >= info->str_count)
111                         return log_msg_ret("id", -E2BIG);
112                 text = info->str_for_id[id];
113                 if (!text)
114                         return log_msg_ret("id", -EINVAL);
115         }
116
117         ret = expo_str(scn->expo, find_name, 0, text);
118         if (ret < 0)
119                 return log_msg_ret("add", ret);
120         str_id = ret;
121
122         ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL);
123         if (ret < 0)
124                 return log_msg_ret("add", ret);
125
126         return ret;
127 }
128
129 /*
130  * build_element() - Handle creating a text object from a label
131  *
132  * Look up a property called @label or @label-id and create a string for it
133  */
134 int build_element(void *ldtb, int node, const char *label)
135 {
136         return 0;
137 }
138
139 /**
140  * read_strings() - Read in the list of strings
141  *
142  * Read the strings into an ID-indexed list, so they can be used for building
143  * an expo. The strings are in a /strings node and each has its own subnode
144  * containing the ID and the string itself:
145  *
146  * example {
147  *    id = <123>;
148  *    value = "This is a test";
149  * };
150  *
151  * Future work may add support for unicode and multiple languages
152  *
153  * @info: Build information
154  * @root: Root node to read from
155  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
156  * error
157  */
158 static int read_strings(struct build_info *info, ofnode root)
159 {
160         ofnode strings, node;
161
162         strings = ofnode_find_subnode(root, "strings");
163         if (!ofnode_valid(strings))
164                 return log_msg_ret("str", -EINVAL);
165
166         ofnode_for_each_subnode(node, strings) {
167                 const char *val;
168                 int ret;
169                 u32 id;
170
171                 info->err_node = node;
172                 ret = ofnode_read_u32(node, "id", &id);
173                 if (ret)
174                         return log_msg_ret("id", -ENOENT);
175                 val = ofnode_read_string(node, "value");
176                 if (!val)
177                         return log_msg_ret("val", -EINVAL);
178
179                 if (id >= info->str_count) {
180                         int new_count = info->str_count + 20;
181                         void *new_arr;
182
183                         new_arr = realloc(info->str_for_id,
184                                           new_count * sizeof(char *));
185                         if (!new_arr)
186                                 return log_msg_ret("id", -ENOMEM);
187                         memset(new_arr + info->str_count, '\0',
188                                (new_count - info->str_count) * sizeof(char *));
189                         info->str_for_id = new_arr;
190                         info->str_count = new_count;
191                 }
192
193                 info->str_for_id[id] = val;
194         }
195
196         return 0;
197 }
198
199 /**
200  * list_strings() - List the available strings with their IDs
201  *
202  * @info: Build information
203  */
204 static void list_strings(struct build_info *info)
205 {
206         int i;
207
208         for (i = 0; i < info->str_count; i++) {
209                 if (info->str_for_id[i])
210                         printf("%3d %s\n", i, info->str_for_id[i]);
211         }
212 }
213
214 /**
215  * menu_build() - Build a menu and add it to a scene
216  *
217  * See doc/develop/expo.rst for a description of the format
218  *
219  * @info: Build information
220  * @node: Node containing the menu description
221  * @scn: Scene to add the menu to
222  * @id: ID for the menu
223  * @objp: Returns the object pointer
224  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
225  * error, -ENOENT if there is a references to a non-existent string
226  */
227 static int menu_build(struct build_info *info, ofnode node, struct scene *scn,
228                       uint id, struct scene_obj **objp)
229 {
230         struct scene_obj_menu *menu;
231         uint title_id, menu_id;
232         const u32 *item_ids;
233         int ret, size, i;
234         const char *name;
235
236         name = ofnode_get_name(node);
237
238         ret = scene_menu(scn, name, id, &menu);
239         if (ret < 0)
240                 return log_msg_ret("men", ret);
241         menu_id = ret;
242
243         /* Set the title */
244         ret = add_txt_str(info, node, scn, "title", 0);
245         if (ret < 0)
246                 return log_msg_ret("tit", ret);
247         title_id = ret;
248         ret = scene_menu_set_title(scn, menu_id, title_id);
249         if (ret)
250                 return log_msg_ret("set", ret);
251
252         item_ids = ofnode_read_prop(node, "item-id", &size);
253         if (!item_ids)
254                 return log_msg_ret("itm", -EINVAL);
255         if (!size || size % sizeof(u32))
256                 return log_msg_ret("isz", -EINVAL);
257         size /= sizeof(u32);
258
259         for (i = 0; i < size; i++) {
260                 struct scene_menitem *item;
261                 uint label, key, desc;
262
263                 ret = add_txt_str_list(info, node, scn, "item-label", i, 0);
264                 if (ret < 0 && ret != -ENOENT)
265                         return log_msg_ret("lab", ret);
266                 label = max(0, ret);
267
268                 ret = add_txt_str_list(info, node, scn, "key-label", i, 0);
269                 if (ret < 0 && ret != -ENOENT)
270                         return log_msg_ret("key", ret);
271                 key = max(0, ret);
272
273                 ret = add_txt_str_list(info, node, scn, "desc-label", i, 0);
274                 if (ret < 0  && ret != -ENOENT)
275                         return log_msg_ret("lab", ret);
276                 desc = max(0, ret);
277
278                 ret = scene_menuitem(scn, menu_id, simple_xtoa(i),
279                                      fdt32_to_cpu(item_ids[i]), key, label,
280                                      desc, 0, 0, &item);
281                 if (ret < 0)
282                         return log_msg_ret("mi", ret);
283         }
284         *objp = &menu->obj;
285
286         return 0;
287 }
288
289 static int textline_build(struct build_info *info, ofnode node,
290                           struct scene *scn, uint id, struct scene_obj **objp)
291 {
292         struct scene_obj_textline *ted;
293         uint ted_id, edit_id;
294         const char *name;
295         u32 max_chars;
296         int ret;
297
298         name = ofnode_get_name(node);
299
300         info->err_prop = "max-chars";
301         ret = ofnode_read_u32(node, "max-chars", &max_chars);
302         if (ret)
303                 return log_msg_ret("max", -ENOENT);
304
305         ret = scene_textline(scn, name, id, max_chars, &ted);
306         if (ret < 0)
307                 return log_msg_ret("ted", ret);
308         ted_id = ret;
309
310         /* Set the title */
311         ret = add_txt_str(info, node, scn, "title", 0);
312         if (ret < 0)
313                 return log_msg_ret("tit", ret);
314         ted->label_id = ret;
315
316         /* Setup the editor */
317         info->err_prop = "edit-id";
318         ret = ofnode_read_u32(node, "edit-id", &id);
319         if (ret)
320                 return log_msg_ret("id", -ENOENT);
321         edit_id = ret;
322
323         ret = scene_txt_str(scn, "edit", edit_id, 0, abuf_data(&ted->buf),
324                             NULL);
325         if (ret < 0)
326                 return log_msg_ret("add", ret);
327         ted->edit_id = ret;
328
329         return 0;
330 }
331
332 /**
333  * obj_build() - Build an expo object and add it to a scene
334  *
335  * See doc/develop/expo.rst for a description of the format
336  *
337  * @info: Build information
338  * @node: Node containing the object description
339  * @scn: Scene to add the object to
340  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
341  * error, -ENOENT if there is a references to a non-existent string
342  */
343 static int obj_build(struct build_info *info, ofnode node, struct scene *scn)
344 {
345         struct scene_obj *obj;
346         const char *type;
347         u32 id, val;
348         int ret;
349
350         log_debug("- object %s\n", ofnode_get_name(node));
351         ret = ofnode_read_u32(node, "id", &id);
352         if (ret)
353                 return log_msg_ret("id", -ENOENT);
354
355         type = ofnode_read_string(node, "type");
356         if (!type)
357                 return log_msg_ret("typ", -EINVAL);
358
359         if (!strcmp("menu", type))
360                 ret = menu_build(info, node, scn, id, &obj);
361         else if (!strcmp("textline", type))
362                 ret = textline_build(info, node, scn, id, &obj);
363         else
364                 ret = -EOPNOTSUPP;
365         if (ret)
366                 return log_msg_ret("bld", ret);
367
368         if (!ofnode_read_u32(node, "start-bit", &val))
369                 obj->start_bit = val;
370         if (!ofnode_read_u32(node, "bit-length", &val))
371                 obj->bit_length = val;
372
373         return 0;
374 }
375
376 /**
377  * scene_build() - Build a scene and all its objects
378  *
379  * See doc/develop/expo.rst for a description of the format
380  *
381  * @info: Build information
382  * @node: Node containing the scene description
383  * @scn: Scene to add the object to
384  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
385  * error, -ENOENT if there is a references to a non-existent string
386  */
387 static int scene_build(struct build_info *info, ofnode scn_node,
388                        struct expo *exp)
389 {
390         const char *name;
391         struct scene *scn;
392         uint id, title_id;
393         ofnode node;
394         int ret;
395
396         info->err_node = scn_node;
397         name = ofnode_get_name(scn_node);
398         log_debug("Building scene %s\n", name);
399         ret = ofnode_read_u32(scn_node, "id", &id);
400         if (ret)
401                 return log_msg_ret("id", -ENOENT);
402
403         ret = scene_new(exp, name, id, &scn);
404         if (ret < 0)
405                 return log_msg_ret("scn", ret);
406
407         ret = add_txt_str(info, scn_node, scn, "title", 0);
408         if (ret < 0)
409                 return log_msg_ret("tit", ret);
410         title_id = ret;
411         scene_title_set(scn, title_id);
412
413         ret = add_txt_str(info, scn_node, scn, "prompt", 0);
414         if (ret < 0)
415                 return log_msg_ret("pr", ret);
416
417         ofnode_for_each_subnode(node, scn_node) {
418                 info->err_node = node;
419                 ret = obj_build(info, node, scn);
420                 if (ret < 0)
421                         return log_msg_ret("mit", ret);
422         }
423
424         return 0;
425 }
426
427 int build_it(struct build_info *info, ofnode root, struct expo **expp)
428 {
429         ofnode scenes, node;
430         struct expo *exp;
431         u32 dyn_start;
432         int ret;
433
434         ret = read_strings(info, root);
435         if (ret)
436                 return log_msg_ret("str", ret);
437         if (_DEBUG)
438                 list_strings(info);
439         info->err_node = root;
440
441         ret = expo_new("name", NULL, &exp);
442         if (ret)
443                 return log_msg_ret("exp", ret);
444
445         if (!ofnode_read_u32(root, "dynamic-start", &dyn_start))
446                 expo_set_dynamic_start(exp, dyn_start);
447
448         scenes = ofnode_find_subnode(root, "scenes");
449         if (!ofnode_valid(scenes))
450                 return log_msg_ret("sno", -EINVAL);
451
452         ofnode_for_each_subnode(node, scenes) {
453                 ret = scene_build(info, node, exp);
454                 if (ret < 0)
455                         return log_msg_ret("scn", ret);
456         }
457         *expp = exp;
458
459         return 0;
460 }
461
462 int expo_build(ofnode root, struct expo **expp)
463 {
464         struct build_info info;
465         struct expo *exp;
466         int ret;
467
468         memset(&info, '\0', sizeof(info));
469         ret = build_it(&info, root, &exp);
470         if (ret) {
471                 char buf[120];
472                 int node_ret;
473
474                 node_ret = ofnode_get_path(info.err_node, buf, sizeof(buf));
475                 log_warning("Build failed at node %s, property %s\n",
476                             node_ret ? ofnode_get_name(info.err_node) : buf,
477                             info.err_prop);
478
479                 return log_msg_ret("bui", ret);
480         }
481         *expp = exp;
482
483         return 0;
484 }
This page took 0.051905 seconds and 4 git commands to generate.