blob: 8c6948d1d4610272a15856a2d9d39d208ee619e9 [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
152int cedit_run(struct expo *exp)
153{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600154 struct video_priv *vid_priv;
155 uint scene_id;
156 struct scene *scn;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600157 int ret;
158
Simon Glass6a5af5f2023-08-14 16:40:27 -0600159 ret = cedit_prepare(exp, &vid_priv, &scn);
160 if (ret < 0)
161 return log_msg_ret("prep", ret);
162 scene_id = ret;
163
Simon Glass527d8642025-05-02 08:46:20 -0600164 exp->done = false;
165 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600166 do {
167 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600168
Simon Glass137b4422025-05-02 08:46:16 -0600169 ret = expo_poll(exp, &act);
Simon Glassc8925112023-06-01 10:23:02 -0600170 if (!ret) {
171 switch (act.type) {
172 case EXPOACT_POINT_OBJ:
173 scene_set_highlight_id(scn, act.select.id);
174 cedit_arange(exp, vid_priv, scene_id);
175 break;
176 case EXPOACT_OPEN:
177 scene_set_open(scn, act.select.id, true);
178 cedit_arange(exp, vid_priv, scene_id);
Simon Glass53a0a2f2024-10-14 16:31:57 -0600179 switch (scn->highlight_id) {
180 case EXPOID_SAVE:
Simon Glass527d8642025-05-02 08:46:20 -0600181 exp->done = true;
182 exp->save = true;
Simon Glass53a0a2f2024-10-14 16:31:57 -0600183 break;
184 case EXPOID_DISCARD:
Simon Glass527d8642025-05-02 08:46:20 -0600185 exp->done = true;
Simon Glass53a0a2f2024-10-14 16:31:57 -0600186 break;
187 }
Simon Glassc8925112023-06-01 10:23:02 -0600188 break;
189 case EXPOACT_CLOSE:
190 scene_set_open(scn, act.select.id, false);
191 cedit_arange(exp, vid_priv, scene_id);
192 break;
193 case EXPOACT_SELECT:
194 scene_set_open(scn, scn->highlight_id, false);
195 cedit_arange(exp, vid_priv, scene_id);
196 break;
197 case EXPOACT_QUIT:
198 log_debug("quitting\n");
Simon Glass527d8642025-05-02 08:46:20 -0600199 exp->done = true;
Simon Glassc8925112023-06-01 10:23:02 -0600200 break;
201 default:
202 break;
203 }
Simon Glass137b4422025-05-02 08:46:16 -0600204 } else if (ret != -EAGAIN) {
205 return log_msg_ret("cep", ret);
Simon Glassc8925112023-06-01 10:23:02 -0600206 }
Simon Glass527d8642025-05-02 08:46:20 -0600207 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600208
209 if (ret)
210 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600211 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600212 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600213
214 return 0;
215}
Simon Glass28bf4352023-08-14 16:40:33 -0600216
217static int check_space(int ret, struct abuf *buf)
218{
219 if (ret == -FDT_ERR_NOSPACE) {
220 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
221 return log_msg_ret("spc", -ENOMEM);
222 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
223 abuf_size(buf));
224 if (ret)
225 return log_msg_ret("res", -EFAULT);
226 }
227
228 return 0;
229}
230
Simon Glassdb6a0512023-10-01 19:13:23 -0600231/**
232 * get_cur_menuitem_text() - Get the text of the currently selected item
233 *
234 * Looks up the object for the current item, finds text object for it and looks
235 * up the string for that text
236 *
237 * @menu: Menu to look at
238 * @strp: Returns a pointer to the next
239 * Return: 0 if OK, -ENOENT if something was not found
240 */
Simon Glass237f3752023-08-14 16:40:35 -0600241static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
242 const char **strp)
243{
244 struct scene *scn = menu->obj.scene;
245 const struct scene_menitem *mi;
246 const struct scene_obj_txt *txt;
247 const char *str;
248
249 mi = scene_menuitem_find(menu, menu->cur_item_id);
250 if (!mi)
251 return log_msg_ret("mi", -ENOENT);
252
253 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
254 if (!txt)
255 return log_msg_ret("txt", -ENOENT);
256
257 str = expo_get_str(scn->expo, txt->str_id);
258 if (!str)
259 return log_msg_ret("str", -ENOENT);
260 *strp = str;
261
262 return 0;
263}
264
Simon Glass6f3e87a2024-10-14 16:32:00 -0600265/**
266 * get_cur_menuitem_val() - Get the value of a menu's current item
267 *
268 * Obtains the value of the current item in the menu. If no value, then
269 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
270 * the currently selected item. If the first item is selected, this returns 0;
271 * if the second, 1; etc.
272 *
273 * @menu: Menu to check
274 * @valp: Returns current-item value / sequence number
275 * Return: 0 on success, else -ve error value
276 */
277static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
278{
279 const struct scene_menitem *mi;
280 int seq;
281
282 seq = 0;
283 list_for_each_entry(mi, &menu->item_head, sibling) {
284 if (mi->id == menu->cur_item_id) {
285 *valp = mi->value == INT_MAX ? seq : mi->value;
286 return 0;
287 }
288 seq++;
289 }
290
291 return log_msg_ret("nf", -ENOENT);
292}
293
294/**
295 * write_dt_string() - Write a string to the devicetree, expanding if needed
296 *
297 * If this fails, it tries again after expanding the devicetree a little
298 *
299 * @buf: Buffer containing the devicetree
300 * @name: Property name to use
301 * @str: String value
302 * Return: 0 if OK, -EFAULT if something went horribly wrong
303 */
Simon Glassf78388b2023-10-01 19:13:28 -0600304static int write_dt_string(struct abuf *buf, const char *name, const char *str)
305{
306 int ret, i;
307
Simon Glassf78388b2023-10-01 19:13:28 -0600308 ret = -EAGAIN;
309 for (i = 0; ret && i < 2; i++) {
310 ret = fdt_property_string(abuf_data(buf), name, str);
311 if (!i) {
312 ret = check_space(ret, buf);
313 if (ret)
314 return log_msg_ret("rs2", -ENOMEM);
315 }
316 }
317
318 /* this should not happen */
319 if (ret)
320 return log_msg_ret("str", -EFAULT);
321
322 return 0;
323}
324
Simon Glass6f3e87a2024-10-14 16:32:00 -0600325/**
326 * write_dt_u32() - Write an int to the devicetree, expanding if needed
327 *
328 * If this fails, it tries again after expanding the devicetree a little
329 *
330 * @buf: Buffer containing the devicetree
331 * @name: Property name to use
332 * @lva: Integer value
333 * Return: 0 if OK, -EFAULT if something went horribly wrong
334 */
335static int write_dt_u32(struct abuf *buf, const char *name, uint val)
336{
337 int ret, i;
338
339 /* write the text of the current item */
340 ret = -EAGAIN;
341 for (i = 0; ret && i < 2; i++) {
342 ret = fdt_property_u32(abuf_data(buf), name, val);
343 if (!i) {
344 ret = check_space(ret, buf);
345 if (ret)
346 return log_msg_ret("rs2", -ENOMEM);
347 }
348 }
349
350 /* this should not happen */
351 if (ret)
352 return log_msg_ret("str", -EFAULT);
353
354 return 0;
355}
356
Simon Glass28bf4352023-08-14 16:40:33 -0600357static int h_write_settings(struct scene_obj *obj, void *vpriv)
358{
359 struct cedit_iter_priv *priv = vpriv;
360 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600361 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600362
363 switch (obj->type) {
364 case SCENEOBJT_NONE:
365 case SCENEOBJT_IMAGE:
366 case SCENEOBJT_TEXT:
367 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600368 case SCENEOBJT_TEXTLINE: {
369 const struct scene_obj_textline *tline;
370
371 tline = (struct scene_obj_textline *)obj;
372 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
373 if (ret)
374 return log_msg_ret("wr2", ret);
375 break;
376 }
Simon Glass28bf4352023-08-14 16:40:33 -0600377 case SCENEOBJT_MENU: {
378 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600379 const char *str;
380 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600381 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600382
Simon Glassf78388b2023-10-01 19:13:28 -0600383 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600384 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600385 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600386 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600387 return log_msg_ret("wrt", ret);
388
389 snprintf(name, sizeof(name), "%s-value", obj->name);
390 ret = get_cur_menuitem_val(menu, &val);
391 if (ret < 0)
392 return log_msg_ret("cur", ret);
393 ret = write_dt_u32(buf, name, val);
394 if (ret)
395 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600396
Simon Glass237f3752023-08-14 16:40:35 -0600397 ret = get_cur_menuitem_text(menu, &str);
398 if (ret)
399 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600400
Simon Glassf78388b2023-10-01 19:13:28 -0600401 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600402 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600403 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600404 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600405 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600406
407 break;
408 }
409 }
410
411 return 0;
412}
413
414int cedit_write_settings(struct expo *exp, struct abuf *buf)
415{
416 struct cedit_iter_priv priv;
417 void *fdt;
418 int ret;
419
Simon Glass6651e942025-05-01 07:37:01 -0600420 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600421 return log_msg_ret("buf", -ENOMEM);
422
423 fdt = abuf_data(buf);
424 ret = fdt_create(fdt, abuf_size(buf));
425 if (!ret)
426 ret = fdt_finish_reservemap(fdt);
427 if (!ret)
428 ret = fdt_begin_node(fdt, "");
429 if (!ret)
430 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
431 if (ret) {
432 log_debug("Failed to start FDT (err=%d)\n", ret);
433 return log_msg_ret("sta", -EINVAL);
434 }
435
436 /* write out the items */
437 priv.buf = buf;
438 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
439 if (ret) {
440 log_debug("Failed to write settings (err=%d)\n", ret);
441 return log_msg_ret("set", ret);
442 }
443
444 ret = fdt_end_node(fdt);
445 if (!ret)
446 ret = fdt_end_node(fdt);
447 if (!ret)
448 ret = fdt_finish(fdt);
449 if (ret) {
450 log_debug("Failed to finish FDT (err=%d)\n", ret);
451 return log_msg_ret("fin", -EINVAL);
452 }
453
454 return 0;
455}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600456
457static int h_read_settings(struct scene_obj *obj, void *vpriv)
458{
459 struct cedit_iter_priv *priv = vpriv;
460 ofnode node = priv->node;
461
462 switch (obj->type) {
463 case SCENEOBJT_NONE:
464 case SCENEOBJT_IMAGE:
465 case SCENEOBJT_TEXT:
466 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600467 case SCENEOBJT_TEXTLINE: {
468 const struct scene_obj_textline *tline;
469 const char *val;
470 int len;
471
472 tline = (struct scene_obj_textline *)obj;
473
474 val = ofnode_read_prop(node, obj->name, &len);
475 if (len >= tline->max_chars)
476 return log_msg_ret("str", -ENOSPC);
477 strcpy(abuf_data(&tline->buf), val);
478 break;
479 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600480 case SCENEOBJT_MENU: {
481 struct scene_obj_menu *menu;
482 uint val;
483
484 if (ofnode_read_u32(node, obj->name, &val))
485 return log_msg_ret("rd", -ENOENT);
486 menu = (struct scene_obj_menu *)obj;
487 menu->cur_item_id = val;
488
489 break;
490 }
491 }
492
493 return 0;
494}
495
496int cedit_read_settings(struct expo *exp, oftree tree)
497{
498 struct cedit_iter_priv priv;
499 ofnode root, node;
500 int ret;
501
502 root = oftree_root(tree);
503 if (!ofnode_valid(root))
504 return log_msg_ret("roo", -ENOENT);
505 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
506 if (!ofnode_valid(node))
507 return log_msg_ret("pat", -ENOENT);
508
509 /* read in the items */
510 priv.node = node;
511 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
512 if (ret) {
513 log_debug("Failed to read settings (err=%d)\n", ret);
514 return log_msg_ret("set", ret);
515 }
516
517 return 0;
518}
Simon Glass237f3752023-08-14 16:40:35 -0600519
520static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
521{
522 const struct scene_obj_menu *menu;
523 struct cedit_iter_priv *priv = vpriv;
524 char name[80], var[60];
525 const char *str;
526 int val, ret;
527
Simon Glass53a0a2f2024-10-14 16:31:57 -0600528 if (obj->id < EXPOID_BASE_ID)
529 return 0;
530
Simon Glass237f3752023-08-14 16:40:35 -0600531 snprintf(var, sizeof(var), "c.%s", obj->name);
532
Simon Glassb7a64532023-10-01 19:13:24 -0600533 switch (obj->type) {
534 case SCENEOBJT_NONE:
535 case SCENEOBJT_IMAGE:
536 case SCENEOBJT_TEXT:
537 break;
538 case SCENEOBJT_MENU:
539 menu = (struct scene_obj_menu *)obj;
540 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600541
Simon Glassb7a64532023-10-01 19:13:24 -0600542 if (priv->verbose)
543 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600544
Simon Glassb7a64532023-10-01 19:13:24 -0600545 ret = env_set_ulong(var, val);
546 if (ret)
547 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600548
Simon Glassb7a64532023-10-01 19:13:24 -0600549 ret = get_cur_menuitem_text(menu, &str);
550 if (ret)
551 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600552
Simon Glassb7a64532023-10-01 19:13:24 -0600553 snprintf(name, sizeof(name), "c.%s-str", obj->name);
554 if (priv->verbose)
555 printf("%s=%s\n", name, str);
556
557 ret = env_set(name, str);
558 if (ret)
559 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600560
561 ret = get_cur_menuitem_val(menu, &val);
562 if (ret < 0)
563 return log_msg_ret("cur", ret);
564 snprintf(name, sizeof(name), "c.%s-value", obj->name);
565 if (priv->verbose)
566 printf("%s=%d\n", name, val);
567
Simon Glassb7a64532023-10-01 19:13:24 -0600568 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600569 case SCENEOBJT_TEXTLINE: {
570 const struct scene_obj_textline *tline;
571
572 tline = (struct scene_obj_textline *)obj;
573 str = abuf_data(&tline->buf);
574 ret = env_set(var, str);
575 if (ret)
576 return log_msg_ret("set", ret);
577
578 if (priv->verbose)
579 printf("%s=%s\n", var, str);
580
581 break;
582 }
Simon Glassb7a64532023-10-01 19:13:24 -0600583 }
Simon Glass237f3752023-08-14 16:40:35 -0600584
585 return 0;
586}
587
588int cedit_write_settings_env(struct expo *exp, bool verbose)
589{
590 struct cedit_iter_priv priv;
591 int ret;
592
593 /* write out the items */
594 priv.verbose = verbose;
595 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
596 if (ret) {
597 log_debug("Failed to write settings to env (err=%d)\n", ret);
598 return log_msg_ret("set", ret);
599 }
600
601 return 0;
602}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600603
604static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
605{
606 struct cedit_iter_priv *priv = vpriv;
607 struct scene_obj_menu *menu;
608 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600609 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600610
Simon Glass53a0a2f2024-10-14 16:31:57 -0600611 if (obj->id < EXPOID_BASE_ID)
612 return 0;
613
Simon Glass0f2e5a62023-08-14 16:40:36 -0600614 snprintf(var, sizeof(var), "c.%s", obj->name);
615
Simon Glassb7a64532023-10-01 19:13:24 -0600616 switch (obj->type) {
617 case SCENEOBJT_NONE:
618 case SCENEOBJT_IMAGE:
619 case SCENEOBJT_TEXT:
620 break;
621 case SCENEOBJT_MENU:
622 menu = (struct scene_obj_menu *)obj;
623 val = env_get_ulong(var, 10, 0);
624 if (priv->verbose)
625 printf("%s=%d\n", var, val);
626 if (!val)
627 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600628
Simon Glassb7a64532023-10-01 19:13:24 -0600629 /*
630 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600631 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600632 */
633 menu->cur_item_id = val;
634 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600635 case SCENEOBJT_TEXTLINE: {
636 const struct scene_obj_textline *tline;
637 const char *value;
638
639 tline = (struct scene_obj_textline *)obj;
640 value = env_get(var);
641 if (value && strlen(value) >= tline->max_chars)
642 return log_msg_ret("str", -ENOSPC);
643 if (!value)
644 value = "";
645 if (priv->verbose)
646 printf("%s=%s\n", var, value);
647 strcpy(abuf_data(&tline->buf), value);
648 break;
649 }
Simon Glassb7a64532023-10-01 19:13:24 -0600650 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600651
652 return 0;
653}
654
655int cedit_read_settings_env(struct expo *exp, bool verbose)
656{
657 struct cedit_iter_priv priv;
658 int ret;
659
660 /* write out the items */
661 priv.verbose = verbose;
662 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
663 if (ret) {
664 log_debug("Failed to read settings from env (err=%d)\n", ret);
665 return log_msg_ret("set", ret);
666 }
667
668 return 0;
669}
Simon Glass2b91ca62023-08-14 16:40:37 -0600670
Simon Glass2b91ca62023-08-14 16:40:37 -0600671static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
672{
673 const struct scene_obj_menu *menu;
674 struct cedit_iter_priv *priv = vpriv;
675 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600676 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600677
Simon Glass53a0a2f2024-10-14 16:31:57 -0600678 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600679 return 0;
680
681 menu = (struct scene_obj_menu *)obj;
682 val = menu->cur_item_id;
683
Simon Glass6f3e87a2024-10-14 16:32:00 -0600684 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600685 if (ret < 0)
686 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600687 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600688
689 /* figure out where to place this item */
690 if (!obj->bit_length)
691 return log_msg_ret("len", -EINVAL);
692 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
693 return log_msg_ret("bit", -E2BIG);
694
Simon Glass6f3e87a2024-10-14 16:32:00 -0600695 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600696 uint bitnum = obj->start_bit + i;
697
698 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600699 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600700 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
701 log_debug("bit %x %x %x\n", bitnum,
702 priv->mask[CMOS_BYTE(bitnum)],
703 priv->value[CMOS_BYTE(bitnum)]);
704 }
705
706 return 0;
707}
708
709int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
710 bool verbose)
711{
712 struct cedit_iter_priv priv;
713 int ret, i, count, first, last;
714
715 /* write out the items */
716 priv.mask = calloc(1, CMOS_MAX_BYTES);
717 if (!priv.mask)
718 return log_msg_ret("mas", -ENOMEM);
719 priv.value = calloc(1, CMOS_MAX_BYTES);
720 if (!priv.value) {
721 free(priv.mask);
722 return log_msg_ret("val", -ENOMEM);
723 }
724
725 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
726 if (ret) {
727 log_debug("Failed to write CMOS (err=%d)\n", ret);
728 ret = log_msg_ret("set", ret);
729 goto done;
730 }
731
732 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600733 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600734 first = CMOS_MAX_BYTES;
735 last = -1;
736 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
737 if (priv.mask[i]) {
738 log_debug("Write byte %x: %x\n", i, priv.value[i]);
739 ret = rtc_write8(dev, i, priv.value[i]);
740 if (ret) {
741 ret = log_msg_ret("wri", ret);
742 goto done;
743 }
744 count++;
745 first = min(first, i);
746 last = max(last, i);
747 }
748 }
749 if (verbose) {
750 printf("Write %d bytes from offset %x to %x\n", count, first,
751 last);
752 }
753
754done:
755 free(priv.mask);
756 free(priv.value);
757 return ret;
758}
Simon Glass4462fa32023-08-14 16:40:38 -0600759
760static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
761{
762 struct cedit_iter_priv *priv = vpriv;
763 const struct scene_menitem *mi;
764 struct scene_obj_menu *menu;
765 int val, ret;
766 uint i;
767
Simon Glass53a0a2f2024-10-14 16:31:57 -0600768 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600769 return 0;
770
771 menu = (struct scene_obj_menu *)obj;
772
773 /* figure out where to place this item */
774 if (!obj->bit_length)
775 return log_msg_ret("len", -EINVAL);
776 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
777 return log_msg_ret("bit", -E2BIG);
778
779 val = 0;
780 for (i = 0; i < obj->bit_length; i++) {
781 uint bitnum = obj->start_bit + i;
782 uint offset = CMOS_BYTE(bitnum);
783
784 /* read the byte if not already read */
785 if (!priv->mask[offset]) {
786 ret = rtc_read8(priv->dev, offset);
787 if (ret < 0)
788 return log_msg_ret("rea", ret);
789 priv->value[offset] = ret;
790
791 /* mark it as read */
792 priv->mask[offset] = 0xff;
793 }
794
795 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
796 val |= BIT(i);
797 log_debug("bit %x %x\n", bitnum, val);
798 }
799
800 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600801 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600802 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600803 if (!mi)
804 return log_msg_ret("seq", -ENOENT);
805
806 menu->cur_item_id = mi->id;
807 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
808
809 return 0;
810}
811
812int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
813 bool verbose)
814{
815 struct cedit_iter_priv priv;
816 int ret, i, count, first, last;
817
818 /* read in the items */
819 priv.mask = calloc(1, CMOS_MAX_BYTES);
820 if (!priv.mask)
821 return log_msg_ret("mas", -ENOMEM);
822 priv.value = calloc(1, CMOS_MAX_BYTES);
823 if (!priv.value) {
824 free(priv.mask);
825 return log_msg_ret("val", -ENOMEM);
826 }
827 priv.dev = dev;
828
829 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
830 if (ret) {
831 log_debug("Failed to read CMOS (err=%d)\n", ret);
832 ret = log_msg_ret("set", ret);
833 goto done;
834 }
835
Simon Glass330aa1e2024-10-14 16:31:59 -0600836 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600837 first = CMOS_MAX_BYTES;
838 last = -1;
839 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
840 if (priv.mask[i]) {
841 log_debug("Read byte %x: %x\n", i, priv.value[i]);
842 count++;
843 first = min(first, i);
844 last = max(last, i);
845 }
846 }
847 if (verbose) {
848 printf("Read %d bytes from offset %x to %x\n", count, first,
849 last);
850 }
851
852done:
853 free(priv.mask);
854 free(priv.value);
855 return ret;
856}