blob: f1a9ee7ce201a4c1c5a18b582ae3494024fcfb58 [file] [log] [blame]
Simon Glassc8925112023-06-01 10:23:02 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Implementation of configuration editor
4 *
5 * Copyright 2023 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glass6a5af5f2023-08-14 16:40:27 -06009#define LOG_CATEGORY LOGC_EXPO
10
Simon Glass28bf4352023-08-14 16:40:33 -060011#include <abuf.h>
Simon Glass8df4a4e2023-08-14 16:40:25 -060012#include <cedit.h>
Simon Glassc8925112023-06-01 10:23:02 -060013#include <cli.h>
14#include <dm.h>
Simon Glass237f3752023-08-14 16:40:35 -060015#include <env.h>
Simon Glassc8925112023-06-01 10:23:02 -060016#include <expo.h>
Simon Glass2b91ca62023-08-14 16:40:37 -060017#include <malloc.h>
Simon Glassc8925112023-06-01 10:23:02 -060018#include <menu.h>
Simon Glass2b91ca62023-08-14 16:40:37 -060019#include <rtc.h>
Simon Glassc8925112023-06-01 10:23:02 -060020#include <video.h>
21#include <linux/delay.h>
22#include "scene_internal.h"
Rasmus Villemoesf741c232024-10-03 23:28:01 +020023#include <u-boot/schedule.h>
Simon Glassc8925112023-06-01 10:23:02 -060024
Simon Glass2b91ca62023-08-14 16:40:37 -060025enum {
26 CMOS_MAX_BITS = 2048,
27 CMOS_MAX_BYTES = CMOS_MAX_BITS / 8,
28};
29
30#define CMOS_BYTE(bit) ((bit) / 8)
31#define CMOS_BIT(bit) ((bit) % 8)
32
Simon Glass28bf4352023-08-14 16:40:33 -060033/**
34 * struct cedit_iter_priv - private data for cedit operations
35 *
36 * @buf: Buffer to use when writing settings to the devicetree
Simon Glassb1cd32b2023-08-14 16:40:34 -060037 * @node: Node to read from when reading settings from devicetree
Simon Glass237f3752023-08-14 16:40:35 -060038 * @verbose: true to show writing to environment variables
Simon Glass2b91ca62023-08-14 16:40:37 -060039 * @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it
40 * will be written
41 * @value: Value bits for CMOS RAM. This is the actual value written
Simon Glass4462fa32023-08-14 16:40:38 -060042 * @dev: RTC device to write to
Simon Glass28bf4352023-08-14 16:40:33 -060043 */
44struct cedit_iter_priv {
45 struct abuf *buf;
Simon Glassb1cd32b2023-08-14 16:40:34 -060046 ofnode node;
Simon Glass237f3752023-08-14 16:40:35 -060047 bool verbose;
Simon Glass2b91ca62023-08-14 16:40:37 -060048 u8 *mask;
49 u8 *value;
Simon Glass4462fa32023-08-14 16:40:38 -060050 struct udevice *dev;
Simon Glass28bf4352023-08-14 16:40:33 -060051};
52
Simon Glassc8925112023-06-01 10:23:02 -060053int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
54{
Simon Glass377f18e2024-10-14 16:31:55 -060055 struct expo_arrange_info arr;
Simon Glassc8925112023-06-01 10:23:02 -060056 struct scene_obj_txt *txt;
57 struct scene_obj *obj;
58 struct scene *scn;
Simon Glass377f18e2024-10-14 16:31:55 -060059 int y, ret;
Simon Glassc8925112023-06-01 10:23:02 -060060
61 scn = expo_lookup_scene_id(exp, scene_id);
62 if (!scn)
63 return log_msg_ret("scn", -ENOENT);
64
65 txt = scene_obj_find_by_name(scn, "prompt");
66 if (txt)
67 scene_obj_set_pos(scn, txt->obj.id, 0, vpriv->ysize - 50);
68
69 txt = scene_obj_find_by_name(scn, "title");
70 if (txt)
71 scene_obj_set_pos(scn, txt->obj.id, 200, 10);
72
Simon Glass377f18e2024-10-14 16:31:55 -060073 memset(&arr, '\0', sizeof(arr));
74 ret = scene_calc_arrange(scn, &arr);
75 if (ret < 0)
76 return log_msg_ret("arr", ret);
77
Simon Glassc8925112023-06-01 10:23:02 -060078 y = 100;
79 list_for_each_entry(obj, &scn->obj_head, sibling) {
Simon Glassb7a64532023-10-01 19:13:24 -060080 switch (obj->type) {
81 case SCENEOBJT_NONE:
82 case SCENEOBJT_IMAGE:
83 case SCENEOBJT_TEXT:
84 break;
85 case SCENEOBJT_MENU:
Simon Glassc8925112023-06-01 10:23:02 -060086 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060087 scene_menu_arrange(scn, &arr,
88 (struct scene_obj_menu *)obj);
Simon Glassc8925112023-06-01 10:23:02 -060089 y += 50;
Simon Glassb7a64532023-10-01 19:13:24 -060090 break;
Simon Glass23c3eb42023-10-01 19:13:37 -060091 case SCENEOBJT_TEXTLINE:
92 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060093 scene_textline_arrange(scn, &arr,
Simon Glass23c3eb42023-10-01 19:13:37 -060094 (struct scene_obj_textline *)obj);
95 y += 50;
96 break;
Simon Glassc8925112023-06-01 10:23:02 -060097 }
98 }
99
100 return 0;
101}
102
Simon Glass6a5af5f2023-08-14 16:40:27 -0600103int cedit_prepare(struct expo *exp, struct video_priv **vid_privp,
104 struct scene **scnp)
Simon Glassc8925112023-06-01 10:23:02 -0600105{
Simon Glassc8925112023-06-01 10:23:02 -0600106 struct video_priv *vid_priv;
Simon Glassc8925112023-06-01 10:23:02 -0600107 struct udevice *dev;
108 struct scene *scn;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600109 uint scene_id;
Simon Glassc8925112023-06-01 10:23:02 -0600110 int ret;
111
Simon Glassc8925112023-06-01 10:23:02 -0600112 /* For now we only support a video console */
113 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
114 if (ret)
115 return log_msg_ret("vid", ret);
116 ret = expo_set_display(exp, dev);
117 if (ret)
118 return log_msg_ret("dis", ret);
119
120 ret = expo_first_scene_id(exp);
121 if (ret < 0)
122 return log_msg_ret("scn", ret);
123 scene_id = ret;
124
125 ret = expo_set_scene_id(exp, scene_id);
126 if (ret)
127 return log_msg_ret("sid", ret);
128
129 exp->popup = true;
130
131 /* This is not supported for now */
132 if (0)
133 expo_set_text_mode(exp, true);
134
135 vid_priv = dev_get_uclass_priv(dev);
136
137 scn = expo_lookup_scene_id(exp, scene_id);
138 scene_highlight_first(scn);
139
140 cedit_arange(exp, vid_priv, scene_id);
141
142 ret = expo_calc_dims(exp);
143 if (ret)
144 return log_msg_ret("dim", ret);
145
Simon Glass6a5af5f2023-08-14 16:40:27 -0600146 *vid_privp = vid_priv;
147 *scnp = scn;
148
149 return scene_id;
150}
151
Simon Glass14bd4132025-05-02 08:46:21 -0600152int cedit_do_action(struct expo *exp, struct scene *scn,
153 struct video_priv *vid_priv, struct expo_action *act)
154{
155 switch (act->type) {
156 case EXPOACT_NONE:
157 case EXPOACT_POINT_ITEM:
158 return -EAGAIN;
159 case EXPOACT_POINT_OBJ:
160 scene_set_highlight_id(scn, act->select.id);
161 cedit_arange(exp, vid_priv, scn->id);
162 break;
163 case EXPOACT_OPEN:
164 scene_set_open(scn, act->select.id, true);
165 cedit_arange(exp, vid_priv, scn->id);
166 switch (scn->highlight_id) {
167 case EXPOID_SAVE:
168 exp->done = true;
169 exp->save = true;
170 break;
171 case EXPOID_DISCARD:
172 exp->done = true;
173 break;
174 }
175 break;
176 case EXPOACT_CLOSE:
177 scene_set_open(scn, act->select.id, false);
178 cedit_arange(exp, vid_priv, scn->id);
179 break;
180 case EXPOACT_SELECT:
181 scene_set_open(scn, scn->highlight_id, false);
182 cedit_arange(exp, vid_priv, scn->id);
183 break;
184 case EXPOACT_QUIT:
185 log_debug("quitting\n");
186 exp->done = true;
187 break;
188 }
189
190 return 0;
191}
192
Simon Glass6a5af5f2023-08-14 16:40:27 -0600193int cedit_run(struct expo *exp)
194{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600195 struct video_priv *vid_priv;
196 uint scene_id;
197 struct scene *scn;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600198 int ret;
199
Simon Glass6a5af5f2023-08-14 16:40:27 -0600200 ret = cedit_prepare(exp, &vid_priv, &scn);
201 if (ret < 0)
202 return log_msg_ret("prep", ret);
203 scene_id = ret;
204
Simon Glass527d8642025-05-02 08:46:20 -0600205 exp->done = false;
206 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600207 do {
208 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600209
Simon Glass137b4422025-05-02 08:46:16 -0600210 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600211 if (!ret)
212 cedit_do_action(exp, scn, vid_priv, &act);
213 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600214 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600215 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600216
217 if (ret)
218 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600219 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600220 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600221
222 return 0;
223}
Simon Glass28bf4352023-08-14 16:40:33 -0600224
225static int check_space(int ret, struct abuf *buf)
226{
227 if (ret == -FDT_ERR_NOSPACE) {
228 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
229 return log_msg_ret("spc", -ENOMEM);
230 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
231 abuf_size(buf));
232 if (ret)
233 return log_msg_ret("res", -EFAULT);
234 }
235
236 return 0;
237}
238
Simon Glassdb6a0512023-10-01 19:13:23 -0600239/**
240 * get_cur_menuitem_text() - Get the text of the currently selected item
241 *
242 * Looks up the object for the current item, finds text object for it and looks
243 * up the string for that text
244 *
245 * @menu: Menu to look at
246 * @strp: Returns a pointer to the next
247 * Return: 0 if OK, -ENOENT if something was not found
248 */
Simon Glass237f3752023-08-14 16:40:35 -0600249static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
250 const char **strp)
251{
252 struct scene *scn = menu->obj.scene;
253 const struct scene_menitem *mi;
254 const struct scene_obj_txt *txt;
255 const char *str;
256
257 mi = scene_menuitem_find(menu, menu->cur_item_id);
258 if (!mi)
259 return log_msg_ret("mi", -ENOENT);
260
261 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
262 if (!txt)
263 return log_msg_ret("txt", -ENOENT);
264
265 str = expo_get_str(scn->expo, txt->str_id);
266 if (!str)
267 return log_msg_ret("str", -ENOENT);
268 *strp = str;
269
270 return 0;
271}
272
Simon Glass6f3e87a2024-10-14 16:32:00 -0600273/**
274 * get_cur_menuitem_val() - Get the value of a menu's current item
275 *
276 * Obtains the value of the current item in the menu. If no value, then
277 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
278 * the currently selected item. If the first item is selected, this returns 0;
279 * if the second, 1; etc.
280 *
281 * @menu: Menu to check
282 * @valp: Returns current-item value / sequence number
283 * Return: 0 on success, else -ve error value
284 */
285static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
286{
287 const struct scene_menitem *mi;
288 int seq;
289
290 seq = 0;
291 list_for_each_entry(mi, &menu->item_head, sibling) {
292 if (mi->id == menu->cur_item_id) {
293 *valp = mi->value == INT_MAX ? seq : mi->value;
294 return 0;
295 }
296 seq++;
297 }
298
299 return log_msg_ret("nf", -ENOENT);
300}
301
302/**
303 * write_dt_string() - Write a string to the devicetree, expanding if needed
304 *
305 * If this fails, it tries again after expanding the devicetree a little
306 *
307 * @buf: Buffer containing the devicetree
308 * @name: Property name to use
309 * @str: String value
310 * Return: 0 if OK, -EFAULT if something went horribly wrong
311 */
Simon Glassf78388b2023-10-01 19:13:28 -0600312static int write_dt_string(struct abuf *buf, const char *name, const char *str)
313{
314 int ret, i;
315
Simon Glassf78388b2023-10-01 19:13:28 -0600316 ret = -EAGAIN;
317 for (i = 0; ret && i < 2; i++) {
318 ret = fdt_property_string(abuf_data(buf), name, str);
319 if (!i) {
320 ret = check_space(ret, buf);
321 if (ret)
322 return log_msg_ret("rs2", -ENOMEM);
323 }
324 }
325
326 /* this should not happen */
327 if (ret)
328 return log_msg_ret("str", -EFAULT);
329
330 return 0;
331}
332
Simon Glass6f3e87a2024-10-14 16:32:00 -0600333/**
334 * write_dt_u32() - Write an int to the devicetree, expanding if needed
335 *
336 * If this fails, it tries again after expanding the devicetree a little
337 *
338 * @buf: Buffer containing the devicetree
339 * @name: Property name to use
340 * @lva: Integer value
341 * Return: 0 if OK, -EFAULT if something went horribly wrong
342 */
343static int write_dt_u32(struct abuf *buf, const char *name, uint val)
344{
345 int ret, i;
346
347 /* write the text of the current item */
348 ret = -EAGAIN;
349 for (i = 0; ret && i < 2; i++) {
350 ret = fdt_property_u32(abuf_data(buf), name, val);
351 if (!i) {
352 ret = check_space(ret, buf);
353 if (ret)
354 return log_msg_ret("rs2", -ENOMEM);
355 }
356 }
357
358 /* this should not happen */
359 if (ret)
360 return log_msg_ret("str", -EFAULT);
361
362 return 0;
363}
364
Simon Glass28bf4352023-08-14 16:40:33 -0600365static int h_write_settings(struct scene_obj *obj, void *vpriv)
366{
367 struct cedit_iter_priv *priv = vpriv;
368 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600369 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600370
371 switch (obj->type) {
372 case SCENEOBJT_NONE:
373 case SCENEOBJT_IMAGE:
374 case SCENEOBJT_TEXT:
375 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600376 case SCENEOBJT_TEXTLINE: {
377 const struct scene_obj_textline *tline;
378
379 tline = (struct scene_obj_textline *)obj;
380 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
381 if (ret)
382 return log_msg_ret("wr2", ret);
383 break;
384 }
Simon Glass28bf4352023-08-14 16:40:33 -0600385 case SCENEOBJT_MENU: {
386 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600387 const char *str;
388 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600389 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600390
Simon Glassf78388b2023-10-01 19:13:28 -0600391 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600392 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600393 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600394 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600395 return log_msg_ret("wrt", ret);
396
397 snprintf(name, sizeof(name), "%s-value", obj->name);
398 ret = get_cur_menuitem_val(menu, &val);
399 if (ret < 0)
400 return log_msg_ret("cur", ret);
401 ret = write_dt_u32(buf, name, val);
402 if (ret)
403 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600404
Simon Glass237f3752023-08-14 16:40:35 -0600405 ret = get_cur_menuitem_text(menu, &str);
406 if (ret)
407 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600408
Simon Glassf78388b2023-10-01 19:13:28 -0600409 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600410 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600411 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600412 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600413 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600414
415 break;
416 }
417 }
418
419 return 0;
420}
421
422int cedit_write_settings(struct expo *exp, struct abuf *buf)
423{
424 struct cedit_iter_priv priv;
425 void *fdt;
426 int ret;
427
Simon Glass6651e942025-05-01 07:37:01 -0600428 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600429 return log_msg_ret("buf", -ENOMEM);
430
431 fdt = abuf_data(buf);
432 ret = fdt_create(fdt, abuf_size(buf));
433 if (!ret)
434 ret = fdt_finish_reservemap(fdt);
435 if (!ret)
436 ret = fdt_begin_node(fdt, "");
437 if (!ret)
438 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
439 if (ret) {
440 log_debug("Failed to start FDT (err=%d)\n", ret);
441 return log_msg_ret("sta", -EINVAL);
442 }
443
444 /* write out the items */
445 priv.buf = buf;
446 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
447 if (ret) {
448 log_debug("Failed to write settings (err=%d)\n", ret);
449 return log_msg_ret("set", ret);
450 }
451
452 ret = fdt_end_node(fdt);
453 if (!ret)
454 ret = fdt_end_node(fdt);
455 if (!ret)
456 ret = fdt_finish(fdt);
457 if (ret) {
458 log_debug("Failed to finish FDT (err=%d)\n", ret);
459 return log_msg_ret("fin", -EINVAL);
460 }
461
462 return 0;
463}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600464
465static int h_read_settings(struct scene_obj *obj, void *vpriv)
466{
467 struct cedit_iter_priv *priv = vpriv;
468 ofnode node = priv->node;
469
470 switch (obj->type) {
471 case SCENEOBJT_NONE:
472 case SCENEOBJT_IMAGE:
473 case SCENEOBJT_TEXT:
474 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600475 case SCENEOBJT_TEXTLINE: {
476 const struct scene_obj_textline *tline;
477 const char *val;
478 int len;
479
480 tline = (struct scene_obj_textline *)obj;
481
482 val = ofnode_read_prop(node, obj->name, &len);
483 if (len >= tline->max_chars)
484 return log_msg_ret("str", -ENOSPC);
485 strcpy(abuf_data(&tline->buf), val);
486 break;
487 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600488 case SCENEOBJT_MENU: {
489 struct scene_obj_menu *menu;
490 uint val;
491
492 if (ofnode_read_u32(node, obj->name, &val))
493 return log_msg_ret("rd", -ENOENT);
494 menu = (struct scene_obj_menu *)obj;
495 menu->cur_item_id = val;
496
497 break;
498 }
499 }
500
501 return 0;
502}
503
504int cedit_read_settings(struct expo *exp, oftree tree)
505{
506 struct cedit_iter_priv priv;
507 ofnode root, node;
508 int ret;
509
510 root = oftree_root(tree);
511 if (!ofnode_valid(root))
512 return log_msg_ret("roo", -ENOENT);
513 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
514 if (!ofnode_valid(node))
515 return log_msg_ret("pat", -ENOENT);
516
517 /* read in the items */
518 priv.node = node;
519 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
520 if (ret) {
521 log_debug("Failed to read settings (err=%d)\n", ret);
522 return log_msg_ret("set", ret);
523 }
524
525 return 0;
526}
Simon Glass237f3752023-08-14 16:40:35 -0600527
528static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
529{
530 const struct scene_obj_menu *menu;
531 struct cedit_iter_priv *priv = vpriv;
532 char name[80], var[60];
533 const char *str;
534 int val, ret;
535
Simon Glass53a0a2f2024-10-14 16:31:57 -0600536 if (obj->id < EXPOID_BASE_ID)
537 return 0;
538
Simon Glass237f3752023-08-14 16:40:35 -0600539 snprintf(var, sizeof(var), "c.%s", obj->name);
540
Simon Glassb7a64532023-10-01 19:13:24 -0600541 switch (obj->type) {
542 case SCENEOBJT_NONE:
543 case SCENEOBJT_IMAGE:
544 case SCENEOBJT_TEXT:
545 break;
546 case SCENEOBJT_MENU:
547 menu = (struct scene_obj_menu *)obj;
548 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600549
Simon Glassb7a64532023-10-01 19:13:24 -0600550 if (priv->verbose)
551 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600552
Simon Glassb7a64532023-10-01 19:13:24 -0600553 ret = env_set_ulong(var, val);
554 if (ret)
555 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600556
Simon Glassb7a64532023-10-01 19:13:24 -0600557 ret = get_cur_menuitem_text(menu, &str);
558 if (ret)
559 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600560
Simon Glassb7a64532023-10-01 19:13:24 -0600561 snprintf(name, sizeof(name), "c.%s-str", obj->name);
562 if (priv->verbose)
563 printf("%s=%s\n", name, str);
564
565 ret = env_set(name, str);
566 if (ret)
567 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600568
569 ret = get_cur_menuitem_val(menu, &val);
570 if (ret < 0)
571 return log_msg_ret("cur", ret);
572 snprintf(name, sizeof(name), "c.%s-value", obj->name);
573 if (priv->verbose)
574 printf("%s=%d\n", name, val);
575
Simon Glassb7a64532023-10-01 19:13:24 -0600576 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600577 case SCENEOBJT_TEXTLINE: {
578 const struct scene_obj_textline *tline;
579
580 tline = (struct scene_obj_textline *)obj;
581 str = abuf_data(&tline->buf);
582 ret = env_set(var, str);
583 if (ret)
584 return log_msg_ret("set", ret);
585
586 if (priv->verbose)
587 printf("%s=%s\n", var, str);
588
589 break;
590 }
Simon Glassb7a64532023-10-01 19:13:24 -0600591 }
Simon Glass237f3752023-08-14 16:40:35 -0600592
593 return 0;
594}
595
596int cedit_write_settings_env(struct expo *exp, bool verbose)
597{
598 struct cedit_iter_priv priv;
599 int ret;
600
601 /* write out the items */
602 priv.verbose = verbose;
603 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
604 if (ret) {
605 log_debug("Failed to write settings to env (err=%d)\n", ret);
606 return log_msg_ret("set", ret);
607 }
608
609 return 0;
610}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600611
612static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
613{
614 struct cedit_iter_priv *priv = vpriv;
615 struct scene_obj_menu *menu;
616 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600617 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600618
Simon Glass53a0a2f2024-10-14 16:31:57 -0600619 if (obj->id < EXPOID_BASE_ID)
620 return 0;
621
Simon Glass0f2e5a62023-08-14 16:40:36 -0600622 snprintf(var, sizeof(var), "c.%s", obj->name);
623
Simon Glassb7a64532023-10-01 19:13:24 -0600624 switch (obj->type) {
625 case SCENEOBJT_NONE:
626 case SCENEOBJT_IMAGE:
627 case SCENEOBJT_TEXT:
628 break;
629 case SCENEOBJT_MENU:
630 menu = (struct scene_obj_menu *)obj;
631 val = env_get_ulong(var, 10, 0);
632 if (priv->verbose)
633 printf("%s=%d\n", var, val);
634 if (!val)
635 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600636
Simon Glassb7a64532023-10-01 19:13:24 -0600637 /*
638 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600639 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600640 */
641 menu->cur_item_id = val;
642 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600643 case SCENEOBJT_TEXTLINE: {
644 const struct scene_obj_textline *tline;
645 const char *value;
646
647 tline = (struct scene_obj_textline *)obj;
648 value = env_get(var);
649 if (value && strlen(value) >= tline->max_chars)
650 return log_msg_ret("str", -ENOSPC);
651 if (!value)
652 value = "";
653 if (priv->verbose)
654 printf("%s=%s\n", var, value);
655 strcpy(abuf_data(&tline->buf), value);
656 break;
657 }
Simon Glassb7a64532023-10-01 19:13:24 -0600658 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600659
660 return 0;
661}
662
663int cedit_read_settings_env(struct expo *exp, bool verbose)
664{
665 struct cedit_iter_priv priv;
666 int ret;
667
668 /* write out the items */
669 priv.verbose = verbose;
670 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
671 if (ret) {
672 log_debug("Failed to read settings from env (err=%d)\n", ret);
673 return log_msg_ret("set", ret);
674 }
675
676 return 0;
677}
Simon Glass2b91ca62023-08-14 16:40:37 -0600678
Simon Glass2b91ca62023-08-14 16:40:37 -0600679static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
680{
681 const struct scene_obj_menu *menu;
682 struct cedit_iter_priv *priv = vpriv;
683 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600684 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600685
Simon Glass53a0a2f2024-10-14 16:31:57 -0600686 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600687 return 0;
688
689 menu = (struct scene_obj_menu *)obj;
690 val = menu->cur_item_id;
691
Simon Glass6f3e87a2024-10-14 16:32:00 -0600692 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600693 if (ret < 0)
694 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600695 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600696
697 /* figure out where to place this item */
698 if (!obj->bit_length)
699 return log_msg_ret("len", -EINVAL);
700 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
701 return log_msg_ret("bit", -E2BIG);
702
Simon Glass6f3e87a2024-10-14 16:32:00 -0600703 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600704 uint bitnum = obj->start_bit + i;
705
706 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600707 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600708 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
709 log_debug("bit %x %x %x\n", bitnum,
710 priv->mask[CMOS_BYTE(bitnum)],
711 priv->value[CMOS_BYTE(bitnum)]);
712 }
713
714 return 0;
715}
716
717int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
718 bool verbose)
719{
720 struct cedit_iter_priv priv;
721 int ret, i, count, first, last;
722
723 /* write out the items */
724 priv.mask = calloc(1, CMOS_MAX_BYTES);
725 if (!priv.mask)
726 return log_msg_ret("mas", -ENOMEM);
727 priv.value = calloc(1, CMOS_MAX_BYTES);
728 if (!priv.value) {
729 free(priv.mask);
730 return log_msg_ret("val", -ENOMEM);
731 }
732
733 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
734 if (ret) {
735 log_debug("Failed to write CMOS (err=%d)\n", ret);
736 ret = log_msg_ret("set", ret);
737 goto done;
738 }
739
740 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600741 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600742 first = CMOS_MAX_BYTES;
743 last = -1;
744 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
745 if (priv.mask[i]) {
746 log_debug("Write byte %x: %x\n", i, priv.value[i]);
747 ret = rtc_write8(dev, i, priv.value[i]);
748 if (ret) {
749 ret = log_msg_ret("wri", ret);
750 goto done;
751 }
752 count++;
753 first = min(first, i);
754 last = max(last, i);
755 }
756 }
757 if (verbose) {
758 printf("Write %d bytes from offset %x to %x\n", count, first,
759 last);
760 }
761
762done:
763 free(priv.mask);
764 free(priv.value);
765 return ret;
766}
Simon Glass4462fa32023-08-14 16:40:38 -0600767
768static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
769{
770 struct cedit_iter_priv *priv = vpriv;
771 const struct scene_menitem *mi;
772 struct scene_obj_menu *menu;
773 int val, ret;
774 uint i;
775
Simon Glass53a0a2f2024-10-14 16:31:57 -0600776 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600777 return 0;
778
779 menu = (struct scene_obj_menu *)obj;
780
781 /* figure out where to place this item */
782 if (!obj->bit_length)
783 return log_msg_ret("len", -EINVAL);
784 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
785 return log_msg_ret("bit", -E2BIG);
786
787 val = 0;
788 for (i = 0; i < obj->bit_length; i++) {
789 uint bitnum = obj->start_bit + i;
790 uint offset = CMOS_BYTE(bitnum);
791
792 /* read the byte if not already read */
793 if (!priv->mask[offset]) {
794 ret = rtc_read8(priv->dev, offset);
795 if (ret < 0)
796 return log_msg_ret("rea", ret);
797 priv->value[offset] = ret;
798
799 /* mark it as read */
800 priv->mask[offset] = 0xff;
801 }
802
803 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
804 val |= BIT(i);
805 log_debug("bit %x %x\n", bitnum, val);
806 }
807
808 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600809 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600810 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600811 if (!mi)
812 return log_msg_ret("seq", -ENOENT);
813
814 menu->cur_item_id = mi->id;
815 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
816
817 return 0;
818}
819
820int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
821 bool verbose)
822{
823 struct cedit_iter_priv priv;
824 int ret, i, count, first, last;
825
826 /* read in the items */
827 priv.mask = calloc(1, CMOS_MAX_BYTES);
828 if (!priv.mask)
829 return log_msg_ret("mas", -ENOMEM);
830 priv.value = calloc(1, CMOS_MAX_BYTES);
831 if (!priv.value) {
832 free(priv.mask);
833 return log_msg_ret("val", -ENOMEM);
834 }
835 priv.dev = dev;
836
837 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
838 if (ret) {
839 log_debug("Failed to read CMOS (err=%d)\n", ret);
840 ret = log_msg_ret("set", ret);
841 goto done;
842 }
843
Simon Glass330aa1e2024-10-14 16:31:59 -0600844 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600845 first = CMOS_MAX_BYTES;
846 last = -1;
847 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
848 if (priv.mask[i]) {
849 log_debug("Read byte %x: %x\n", i, priv.value[i]);
850 count++;
851 first = min(first, i);
852 last = max(last, i);
853 }
854 }
855 if (verbose) {
856 printf("Read %d bytes from offset %x to %x\n", count, first,
857 last);
858 }
859
860done:
861 free(priv.mask);
862 free(priv.value);
863 return ret;
864}