blob: d12892fbc4a1f04330c5bd5c04b96be821775057 [file] [log] [blame]
Simon Glassa0874dc2023-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 Glass8d0f8902023-08-14 16:40:27 -06009#define LOG_CATEGORY LOGC_EXPO
10
Simon Glass2dee81f2023-08-14 16:40:33 -060011#include <abuf.h>
Simon Glass040b0462023-08-14 16:40:25 -060012#include <cedit.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060013#include <cli.h>
14#include <dm.h>
Simon Glassfc9c0e02023-08-14 16:40:35 -060015#include <env.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060016#include <expo.h>
Simon Glasseb6c71b2023-08-14 16:40:37 -060017#include <malloc.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060018#include <menu.h>
Simon Glasseb6c71b2023-08-14 16:40:37 -060019#include <rtc.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060020#include <video.h>
21#include <linux/delay.h>
22#include "scene_internal.h"
23
Simon Glasseb6c71b2023-08-14 16:40:37 -060024enum {
25 CMOS_MAX_BITS = 2048,
26 CMOS_MAX_BYTES = CMOS_MAX_BITS / 8,
27};
28
29#define CMOS_BYTE(bit) ((bit) / 8)
30#define CMOS_BIT(bit) ((bit) % 8)
31
Simon Glass2dee81f2023-08-14 16:40:33 -060032/**
33 * struct cedit_iter_priv - private data for cedit operations
34 *
35 * @buf: Buffer to use when writing settings to the devicetree
Simon Glass472317c2023-08-14 16:40:34 -060036 * @node: Node to read from when reading settings from devicetree
Simon Glassfc9c0e02023-08-14 16:40:35 -060037 * @verbose: true to show writing to environment variables
Simon Glasseb6c71b2023-08-14 16:40:37 -060038 * @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it
39 * will be written
40 * @value: Value bits for CMOS RAM. This is the actual value written
Simon Glasscfc402d2023-08-14 16:40:38 -060041 * @dev: RTC device to write to
Simon Glass2dee81f2023-08-14 16:40:33 -060042 */
43struct cedit_iter_priv {
44 struct abuf *buf;
Simon Glass472317c2023-08-14 16:40:34 -060045 ofnode node;
Simon Glassfc9c0e02023-08-14 16:40:35 -060046 bool verbose;
Simon Glasseb6c71b2023-08-14 16:40:37 -060047 u8 *mask;
48 u8 *value;
Simon Glasscfc402d2023-08-14 16:40:38 -060049 struct udevice *dev;
Simon Glass2dee81f2023-08-14 16:40:33 -060050};
51
Simon Glassa0874dc2023-06-01 10:23:02 -060052int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
53{
Simon Glass54eca1d2024-10-14 16:31:55 -060054 struct expo_arrange_info arr;
Simon Glassa0874dc2023-06-01 10:23:02 -060055 struct scene_obj_txt *txt;
56 struct scene_obj *obj;
57 struct scene *scn;
Simon Glass54eca1d2024-10-14 16:31:55 -060058 int y, ret;
Simon Glassa0874dc2023-06-01 10:23:02 -060059
60 scn = expo_lookup_scene_id(exp, scene_id);
61 if (!scn)
62 return log_msg_ret("scn", -ENOENT);
63
64 txt = scene_obj_find_by_name(scn, "prompt");
65 if (txt)
66 scene_obj_set_pos(scn, txt->obj.id, 0, vpriv->ysize - 50);
67
68 txt = scene_obj_find_by_name(scn, "title");
69 if (txt)
70 scene_obj_set_pos(scn, txt->obj.id, 200, 10);
71
Simon Glass54eca1d2024-10-14 16:31:55 -060072 memset(&arr, '\0', sizeof(arr));
73 ret = scene_calc_arrange(scn, &arr);
74 if (ret < 0)
75 return log_msg_ret("arr", ret);
76
Simon Glassa0874dc2023-06-01 10:23:02 -060077 y = 100;
78 list_for_each_entry(obj, &scn->obj_head, sibling) {
Simon Glassfd6073a2023-10-01 19:13:24 -060079 switch (obj->type) {
80 case SCENEOBJT_NONE:
81 case SCENEOBJT_IMAGE:
82 case SCENEOBJT_TEXT:
83 break;
84 case SCENEOBJT_MENU:
Simon Glassa0874dc2023-06-01 10:23:02 -060085 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass54eca1d2024-10-14 16:31:55 -060086 scene_menu_arrange(scn, &arr,
87 (struct scene_obj_menu *)obj);
Simon Glassa0874dc2023-06-01 10:23:02 -060088 y += 50;
Simon Glassfd6073a2023-10-01 19:13:24 -060089 break;
Simon Glassfe553662023-10-01 19:13:37 -060090 case SCENEOBJT_TEXTLINE:
91 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass54eca1d2024-10-14 16:31:55 -060092 scene_textline_arrange(scn, &arr,
Simon Glassfe553662023-10-01 19:13:37 -060093 (struct scene_obj_textline *)obj);
94 y += 50;
95 break;
Simon Glassa0874dc2023-06-01 10:23:02 -060096 }
97 }
98
99 return 0;
100}
101
Simon Glass8d0f8902023-08-14 16:40:27 -0600102int cedit_prepare(struct expo *exp, struct video_priv **vid_privp,
103 struct scene **scnp)
Simon Glassa0874dc2023-06-01 10:23:02 -0600104{
Simon Glassa0874dc2023-06-01 10:23:02 -0600105 struct video_priv *vid_priv;
Simon Glassa0874dc2023-06-01 10:23:02 -0600106 struct udevice *dev;
107 struct scene *scn;
Simon Glass8d0f8902023-08-14 16:40:27 -0600108 uint scene_id;
Simon Glassa0874dc2023-06-01 10:23:02 -0600109 int ret;
110
Simon Glassa0874dc2023-06-01 10:23:02 -0600111 /* For now we only support a video console */
112 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
113 if (ret)
114 return log_msg_ret("vid", ret);
115 ret = expo_set_display(exp, dev);
116 if (ret)
117 return log_msg_ret("dis", ret);
118
119 ret = expo_first_scene_id(exp);
120 if (ret < 0)
121 return log_msg_ret("scn", ret);
122 scene_id = ret;
123
124 ret = expo_set_scene_id(exp, scene_id);
125 if (ret)
126 return log_msg_ret("sid", ret);
127
128 exp->popup = true;
129
130 /* This is not supported for now */
131 if (0)
132 expo_set_text_mode(exp, true);
133
134 vid_priv = dev_get_uclass_priv(dev);
135
136 scn = expo_lookup_scene_id(exp, scene_id);
137 scene_highlight_first(scn);
138
139 cedit_arange(exp, vid_priv, scene_id);
140
141 ret = expo_calc_dims(exp);
142 if (ret)
143 return log_msg_ret("dim", ret);
144
Simon Glass8d0f8902023-08-14 16:40:27 -0600145 *vid_privp = vid_priv;
146 *scnp = scn;
147
148 return scene_id;
149}
150
151int cedit_run(struct expo *exp)
152{
153 struct cli_ch_state s_cch, *cch = &s_cch;
154 struct video_priv *vid_priv;
155 uint scene_id;
156 struct scene *scn;
Simon Glassd8ff97c2024-10-14 16:31:57 -0600157 bool done, save;
Simon Glass8d0f8902023-08-14 16:40:27 -0600158 int ret;
159
160 cli_ch_init(cch);
161 ret = cedit_prepare(exp, &vid_priv, &scn);
162 if (ret < 0)
163 return log_msg_ret("prep", ret);
164 scene_id = ret;
165
Simon Glassa0874dc2023-06-01 10:23:02 -0600166 done = false;
Simon Glassd8ff97c2024-10-14 16:31:57 -0600167 save = false;
Simon Glassa0874dc2023-06-01 10:23:02 -0600168 do {
169 struct expo_action act;
170 int ichar, key;
171
172 ret = expo_render(exp);
173 if (ret)
174 break;
175
176 ichar = cli_ch_process(cch, 0);
177 if (!ichar) {
178 while (!ichar && !tstc()) {
179 schedule();
180 mdelay(2);
181 ichar = cli_ch_process(cch, -ETIMEDOUT);
182 }
183 if (!ichar) {
184 ichar = getchar();
185 ichar = cli_ch_process(cch, ichar);
186 }
187 }
188
189 key = 0;
190 if (ichar) {
191 key = bootmenu_conv_key(ichar);
Simon Glass8579cb02023-10-01 19:13:36 -0600192 if (key == BKEY_NONE || key >= BKEY_FIRST_EXTRA)
Simon Glassa0874dc2023-06-01 10:23:02 -0600193 key = ichar;
194 }
195 if (!key)
196 continue;
197
198 ret = expo_send_key(exp, key);
199 if (ret)
200 break;
201
202 ret = expo_action_get(exp, &act);
203 if (!ret) {
204 switch (act.type) {
205 case EXPOACT_POINT_OBJ:
206 scene_set_highlight_id(scn, act.select.id);
207 cedit_arange(exp, vid_priv, scene_id);
208 break;
209 case EXPOACT_OPEN:
210 scene_set_open(scn, act.select.id, true);
211 cedit_arange(exp, vid_priv, scene_id);
Simon Glassd8ff97c2024-10-14 16:31:57 -0600212 switch (scn->highlight_id) {
213 case EXPOID_SAVE:
214 done = true;
215 save = true;
216 break;
217 case EXPOID_DISCARD:
218 done = true;
219 break;
220 }
Simon Glassa0874dc2023-06-01 10:23:02 -0600221 break;
222 case EXPOACT_CLOSE:
223 scene_set_open(scn, act.select.id, false);
224 cedit_arange(exp, vid_priv, scene_id);
225 break;
226 case EXPOACT_SELECT:
227 scene_set_open(scn, scn->highlight_id, false);
228 cedit_arange(exp, vid_priv, scene_id);
229 break;
230 case EXPOACT_QUIT:
231 log_debug("quitting\n");
232 done = true;
233 break;
234 default:
235 break;
236 }
237 }
238 } while (!done);
239
240 if (ret)
241 return log_msg_ret("end", ret);
Simon Glassd8ff97c2024-10-14 16:31:57 -0600242 if (!save)
243 return -EACCES;
Simon Glassa0874dc2023-06-01 10:23:02 -0600244
245 return 0;
246}
Simon Glass2dee81f2023-08-14 16:40:33 -0600247
248static int check_space(int ret, struct abuf *buf)
249{
250 if (ret == -FDT_ERR_NOSPACE) {
251 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
252 return log_msg_ret("spc", -ENOMEM);
253 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
254 abuf_size(buf));
255 if (ret)
256 return log_msg_ret("res", -EFAULT);
257 }
258
259 return 0;
260}
261
Simon Glass909c4862023-10-01 19:13:23 -0600262/**
263 * get_cur_menuitem_text() - Get the text of the currently selected item
264 *
265 * Looks up the object for the current item, finds text object for it and looks
266 * up the string for that text
267 *
268 * @menu: Menu to look at
269 * @strp: Returns a pointer to the next
270 * Return: 0 if OK, -ENOENT if something was not found
271 */
Simon Glassfc9c0e02023-08-14 16:40:35 -0600272static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
273 const char **strp)
274{
275 struct scene *scn = menu->obj.scene;
276 const struct scene_menitem *mi;
277 const struct scene_obj_txt *txt;
278 const char *str;
279
280 mi = scene_menuitem_find(menu, menu->cur_item_id);
281 if (!mi)
282 return log_msg_ret("mi", -ENOENT);
283
284 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
285 if (!txt)
286 return log_msg_ret("txt", -ENOENT);
287
288 str = expo_get_str(scn->expo, txt->str_id);
289 if (!str)
290 return log_msg_ret("str", -ENOENT);
291 *strp = str;
292
293 return 0;
294}
295
Simon Glass55a9de52024-10-14 16:32:00 -0600296/**
297 * get_cur_menuitem_val() - Get the value of a menu's current item
298 *
299 * Obtains the value of the current item in the menu. If no value, then
300 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
301 * the currently selected item. If the first item is selected, this returns 0;
302 * if the second, 1; etc.
303 *
304 * @menu: Menu to check
305 * @valp: Returns current-item value / sequence number
306 * Return: 0 on success, else -ve error value
307 */
308static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
309{
310 const struct scene_menitem *mi;
311 int seq;
312
313 seq = 0;
314 list_for_each_entry(mi, &menu->item_head, sibling) {
315 if (mi->id == menu->cur_item_id) {
316 *valp = mi->value == INT_MAX ? seq : mi->value;
317 return 0;
318 }
319 seq++;
320 }
321
322 return log_msg_ret("nf", -ENOENT);
323}
324
325/**
326 * write_dt_string() - Write a string 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 * @str: String value
333 * Return: 0 if OK, -EFAULT if something went horribly wrong
334 */
Simon Glass117617c2023-10-01 19:13:28 -0600335static int write_dt_string(struct abuf *buf, const char *name, const char *str)
336{
337 int ret, i;
338
Simon Glass55a9de52024-10-14 16:32:00 -0600339 ret = -EAGAIN;
340 for (i = 0; ret && i < 2; i++) {
341 ret = fdt_property_string(abuf_data(buf), name, str);
342 if (!i) {
343 ret = check_space(ret, buf);
344 if (ret)
345 return log_msg_ret("rs2", -ENOMEM);
346 }
347 }
348
349 /* this should not happen */
350 if (ret)
351 return log_msg_ret("str", -EFAULT);
352
353 return 0;
354}
355
356/**
357 * write_dt_u32() - Write an int to the devicetree, expanding if needed
358 *
359 * If this fails, it tries again after expanding the devicetree a little
360 *
361 * @buf: Buffer containing the devicetree
362 * @name: Property name to use
363 * @lva: Integer value
364 * Return: 0 if OK, -EFAULT if something went horribly wrong
365 */
366static int write_dt_u32(struct abuf *buf, const char *name, uint val)
367{
368 int ret, i;
369
Simon Glass117617c2023-10-01 19:13:28 -0600370 /* write the text of the current item */
371 ret = -EAGAIN;
372 for (i = 0; ret && i < 2; i++) {
Simon Glass55a9de52024-10-14 16:32:00 -0600373 ret = fdt_property_u32(abuf_data(buf), name, val);
Simon Glass117617c2023-10-01 19:13:28 -0600374 if (!i) {
375 ret = check_space(ret, buf);
376 if (ret)
377 return log_msg_ret("rs2", -ENOMEM);
378 }
379 }
380
381 /* this should not happen */
382 if (ret)
383 return log_msg_ret("str", -EFAULT);
384
385 return 0;
386}
387
Simon Glass2dee81f2023-08-14 16:40:33 -0600388static int h_write_settings(struct scene_obj *obj, void *vpriv)
389{
390 struct cedit_iter_priv *priv = vpriv;
391 struct abuf *buf = priv->buf;
Simon Glassfe553662023-10-01 19:13:37 -0600392 int ret;
Simon Glass2dee81f2023-08-14 16:40:33 -0600393
394 switch (obj->type) {
395 case SCENEOBJT_NONE:
396 case SCENEOBJT_IMAGE:
397 case SCENEOBJT_TEXT:
398 break;
Simon Glassfe553662023-10-01 19:13:37 -0600399 case SCENEOBJT_TEXTLINE: {
400 const struct scene_obj_textline *tline;
401
402 tline = (struct scene_obj_textline *)obj;
403 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
404 if (ret)
405 return log_msg_ret("wr2", ret);
406 break;
407 }
Simon Glass2dee81f2023-08-14 16:40:33 -0600408 case SCENEOBJT_MENU: {
409 const struct scene_obj_menu *menu;
Simon Glass2dee81f2023-08-14 16:40:33 -0600410 const char *str;
411 char name[80];
Simon Glass55a9de52024-10-14 16:32:00 -0600412 int val;
Simon Glass2dee81f2023-08-14 16:40:33 -0600413
Simon Glass117617c2023-10-01 19:13:28 -0600414 /* write the ID of the current item */
Simon Glass2dee81f2023-08-14 16:40:33 -0600415 menu = (struct scene_obj_menu *)obj;
Simon Glass55a9de52024-10-14 16:32:00 -0600416 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass2dee81f2023-08-14 16:40:33 -0600417 if (ret)
Simon Glass55a9de52024-10-14 16:32:00 -0600418 return log_msg_ret("wrt", ret);
419
420 snprintf(name, sizeof(name), "%s-value", obj->name);
421 ret = get_cur_menuitem_val(menu, &val);
422 if (ret < 0)
423 return log_msg_ret("cur", ret);
424 ret = write_dt_u32(buf, name, val);
425 if (ret)
426 return log_msg_ret("wr2", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600427
Simon Glassfc9c0e02023-08-14 16:40:35 -0600428 ret = get_cur_menuitem_text(menu, &str);
429 if (ret)
430 return log_msg_ret("mis", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600431
Simon Glass117617c2023-10-01 19:13:28 -0600432 /* write the text of the current item */
Simon Glass2dee81f2023-08-14 16:40:33 -0600433 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glass117617c2023-10-01 19:13:28 -0600434 ret = write_dt_string(buf, name, str);
Simon Glass2dee81f2023-08-14 16:40:33 -0600435 if (ret)
Simon Glass117617c2023-10-01 19:13:28 -0600436 return log_msg_ret("wr2", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600437
438 break;
439 }
440 }
441
442 return 0;
443}
444
445int cedit_write_settings(struct expo *exp, struct abuf *buf)
446{
447 struct cedit_iter_priv priv;
448 void *fdt;
449 int ret;
450
451 abuf_init(buf);
452 if (!abuf_realloc(buf, CEDIT_SIZE_INC))
453 return log_msg_ret("buf", -ENOMEM);
454
455 fdt = abuf_data(buf);
456 ret = fdt_create(fdt, abuf_size(buf));
457 if (!ret)
458 ret = fdt_finish_reservemap(fdt);
459 if (!ret)
460 ret = fdt_begin_node(fdt, "");
461 if (!ret)
462 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
463 if (ret) {
464 log_debug("Failed to start FDT (err=%d)\n", ret);
465 return log_msg_ret("sta", -EINVAL);
466 }
467
468 /* write out the items */
469 priv.buf = buf;
470 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
471 if (ret) {
472 log_debug("Failed to write settings (err=%d)\n", ret);
473 return log_msg_ret("set", ret);
474 }
475
476 ret = fdt_end_node(fdt);
477 if (!ret)
478 ret = fdt_end_node(fdt);
479 if (!ret)
480 ret = fdt_finish(fdt);
481 if (ret) {
482 log_debug("Failed to finish FDT (err=%d)\n", ret);
483 return log_msg_ret("fin", -EINVAL);
484 }
485
486 return 0;
487}
Simon Glass472317c2023-08-14 16:40:34 -0600488
489static int h_read_settings(struct scene_obj *obj, void *vpriv)
490{
491 struct cedit_iter_priv *priv = vpriv;
492 ofnode node = priv->node;
493
494 switch (obj->type) {
495 case SCENEOBJT_NONE:
496 case SCENEOBJT_IMAGE:
497 case SCENEOBJT_TEXT:
498 break;
Simon Glassfe553662023-10-01 19:13:37 -0600499 case SCENEOBJT_TEXTLINE: {
500 const struct scene_obj_textline *tline;
501 const char *val;
502 int len;
503
504 tline = (struct scene_obj_textline *)obj;
505
506 val = ofnode_read_prop(node, obj->name, &len);
507 if (len >= tline->max_chars)
508 return log_msg_ret("str", -ENOSPC);
509 strcpy(abuf_data(&tline->buf), val);
510 break;
511 }
Simon Glass472317c2023-08-14 16:40:34 -0600512 case SCENEOBJT_MENU: {
513 struct scene_obj_menu *menu;
514 uint val;
515
516 if (ofnode_read_u32(node, obj->name, &val))
517 return log_msg_ret("rd", -ENOENT);
518 menu = (struct scene_obj_menu *)obj;
519 menu->cur_item_id = val;
520
521 break;
522 }
523 }
524
525 return 0;
526}
527
528int cedit_read_settings(struct expo *exp, oftree tree)
529{
530 struct cedit_iter_priv priv;
531 ofnode root, node;
532 int ret;
533
534 root = oftree_root(tree);
535 if (!ofnode_valid(root))
536 return log_msg_ret("roo", -ENOENT);
537 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
538 if (!ofnode_valid(node))
539 return log_msg_ret("pat", -ENOENT);
540
541 /* read in the items */
542 priv.node = node;
543 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
544 if (ret) {
545 log_debug("Failed to read settings (err=%d)\n", ret);
546 return log_msg_ret("set", ret);
547 }
548
549 return 0;
550}
Simon Glassfc9c0e02023-08-14 16:40:35 -0600551
552static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
553{
554 const struct scene_obj_menu *menu;
555 struct cedit_iter_priv *priv = vpriv;
556 char name[80], var[60];
557 const char *str;
558 int val, ret;
559
Simon Glassd8ff97c2024-10-14 16:31:57 -0600560 if (obj->id < EXPOID_BASE_ID)
561 return 0;
562
Simon Glassfc9c0e02023-08-14 16:40:35 -0600563 snprintf(var, sizeof(var), "c.%s", obj->name);
564
Simon Glassfd6073a2023-10-01 19:13:24 -0600565 switch (obj->type) {
566 case SCENEOBJT_NONE:
567 case SCENEOBJT_IMAGE:
568 case SCENEOBJT_TEXT:
569 break;
570 case SCENEOBJT_MENU:
571 menu = (struct scene_obj_menu *)obj;
572 val = menu->cur_item_id;
Simon Glassfc9c0e02023-08-14 16:40:35 -0600573
Simon Glassfd6073a2023-10-01 19:13:24 -0600574 if (priv->verbose)
575 printf("%s=%d\n", var, val);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600576
Simon Glassfd6073a2023-10-01 19:13:24 -0600577 ret = env_set_ulong(var, val);
578 if (ret)
579 return log_msg_ret("set", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600580
Simon Glassfd6073a2023-10-01 19:13:24 -0600581 ret = get_cur_menuitem_text(menu, &str);
582 if (ret)
583 return log_msg_ret("mis", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600584
Simon Glassfd6073a2023-10-01 19:13:24 -0600585 snprintf(name, sizeof(name), "c.%s-str", obj->name);
586 if (priv->verbose)
587 printf("%s=%s\n", name, str);
588
589 ret = env_set(name, str);
590 if (ret)
591 return log_msg_ret("st2", ret);
Simon Glass55a9de52024-10-14 16:32:00 -0600592
593 ret = get_cur_menuitem_val(menu, &val);
594 if (ret < 0)
595 return log_msg_ret("cur", ret);
596 snprintf(name, sizeof(name), "c.%s-value", obj->name);
597 if (priv->verbose)
598 printf("%s=%d\n", name, val);
599
Simon Glassfd6073a2023-10-01 19:13:24 -0600600 break;
Simon Glassfe553662023-10-01 19:13:37 -0600601 case SCENEOBJT_TEXTLINE: {
602 const struct scene_obj_textline *tline;
603
604 tline = (struct scene_obj_textline *)obj;
605 str = abuf_data(&tline->buf);
606 ret = env_set(var, str);
607 if (ret)
608 return log_msg_ret("set", ret);
609
610 if (priv->verbose)
611 printf("%s=%s\n", var, str);
612
613 break;
614 }
Simon Glassfd6073a2023-10-01 19:13:24 -0600615 }
Simon Glassfc9c0e02023-08-14 16:40:35 -0600616
617 return 0;
618}
619
620int cedit_write_settings_env(struct expo *exp, bool verbose)
621{
622 struct cedit_iter_priv priv;
623 int ret;
624
625 /* write out the items */
626 priv.verbose = verbose;
627 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
628 if (ret) {
629 log_debug("Failed to write settings to env (err=%d)\n", ret);
630 return log_msg_ret("set", ret);
631 }
632
633 return 0;
634}
Simon Glassbcf2b722023-08-14 16:40:36 -0600635
636static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
637{
638 struct cedit_iter_priv *priv = vpriv;
639 struct scene_obj_menu *menu;
640 char var[60];
Simon Glasseb6c71b2023-08-14 16:40:37 -0600641 int val;
Simon Glassbcf2b722023-08-14 16:40:36 -0600642
Simon Glassd8ff97c2024-10-14 16:31:57 -0600643 if (obj->id < EXPOID_BASE_ID)
644 return 0;
645
Simon Glassbcf2b722023-08-14 16:40:36 -0600646 snprintf(var, sizeof(var), "c.%s", obj->name);
647
Simon Glassfd6073a2023-10-01 19:13:24 -0600648 switch (obj->type) {
649 case SCENEOBJT_NONE:
650 case SCENEOBJT_IMAGE:
651 case SCENEOBJT_TEXT:
652 break;
653 case SCENEOBJT_MENU:
654 menu = (struct scene_obj_menu *)obj;
655 val = env_get_ulong(var, 10, 0);
656 if (priv->verbose)
657 printf("%s=%d\n", var, val);
658 if (!val)
659 return log_msg_ret("get", -ENOENT);
Simon Glassbcf2b722023-08-14 16:40:36 -0600660
Simon Glassfd6073a2023-10-01 19:13:24 -0600661 /*
662 * note that no validation is done here, to make sure the ID is
Simon Glassf6987862024-10-14 16:31:59 -0600663 * valid and actually points to a menu item
Simon Glassfd6073a2023-10-01 19:13:24 -0600664 */
665 menu->cur_item_id = val;
666 break;
Simon Glassfe553662023-10-01 19:13:37 -0600667 case SCENEOBJT_TEXTLINE: {
668 const struct scene_obj_textline *tline;
669 const char *value;
670
671 tline = (struct scene_obj_textline *)obj;
672 value = env_get(var);
673 if (value && strlen(value) >= tline->max_chars)
674 return log_msg_ret("str", -ENOSPC);
675 if (!value)
676 value = "";
677 if (priv->verbose)
678 printf("%s=%s\n", var, value);
679 strcpy(abuf_data(&tline->buf), value);
680 break;
681 }
Simon Glassfd6073a2023-10-01 19:13:24 -0600682 }
Simon Glassbcf2b722023-08-14 16:40:36 -0600683
684 return 0;
685}
686
687int cedit_read_settings_env(struct expo *exp, bool verbose)
688{
689 struct cedit_iter_priv priv;
690 int ret;
691
692 /* write out the items */
693 priv.verbose = verbose;
694 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
695 if (ret) {
696 log_debug("Failed to read settings from env (err=%d)\n", ret);
697 return log_msg_ret("set", ret);
698 }
699
700 return 0;
701}
Simon Glasseb6c71b2023-08-14 16:40:37 -0600702
Simon Glasseb6c71b2023-08-14 16:40:37 -0600703static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
704{
705 const struct scene_obj_menu *menu;
706 struct cedit_iter_priv *priv = vpriv;
707 int val, ret;
Simon Glass55a9de52024-10-14 16:32:00 -0600708 uint i;
Simon Glasseb6c71b2023-08-14 16:40:37 -0600709
Simon Glassd8ff97c2024-10-14 16:31:57 -0600710 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glasseb6c71b2023-08-14 16:40:37 -0600711 return 0;
712
713 menu = (struct scene_obj_menu *)obj;
714 val = menu->cur_item_id;
715
Simon Glass55a9de52024-10-14 16:32:00 -0600716 ret = get_cur_menuitem_val(menu, &val);
Simon Glasseb6c71b2023-08-14 16:40:37 -0600717 if (ret < 0)
718 return log_msg_ret("cur", ret);
Simon Glass55a9de52024-10-14 16:32:00 -0600719 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glasseb6c71b2023-08-14 16:40:37 -0600720
721 /* figure out where to place this item */
722 if (!obj->bit_length)
723 return log_msg_ret("len", -EINVAL);
724 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
725 return log_msg_ret("bit", -E2BIG);
726
Simon Glass55a9de52024-10-14 16:32:00 -0600727 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glasseb6c71b2023-08-14 16:40:37 -0600728 uint bitnum = obj->start_bit + i;
729
730 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass55a9de52024-10-14 16:32:00 -0600731 if (val & 1)
Simon Glasseb6c71b2023-08-14 16:40:37 -0600732 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
733 log_debug("bit %x %x %x\n", bitnum,
734 priv->mask[CMOS_BYTE(bitnum)],
735 priv->value[CMOS_BYTE(bitnum)]);
736 }
737
738 return 0;
739}
740
741int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
742 bool verbose)
743{
744 struct cedit_iter_priv priv;
745 int ret, i, count, first, last;
746
747 /* write out the items */
748 priv.mask = calloc(1, CMOS_MAX_BYTES);
749 if (!priv.mask)
750 return log_msg_ret("mas", -ENOMEM);
751 priv.value = calloc(1, CMOS_MAX_BYTES);
752 if (!priv.value) {
753 free(priv.mask);
754 return log_msg_ret("val", -ENOMEM);
755 }
756
757 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
758 if (ret) {
759 log_debug("Failed to write CMOS (err=%d)\n", ret);
760 ret = log_msg_ret("set", ret);
761 goto done;
762 }
763
764 /* write the data to the RTC */
Simon Glassf6987862024-10-14 16:31:59 -0600765 log_debug("Writing CMOS\n");
Simon Glasseb6c71b2023-08-14 16:40:37 -0600766 first = CMOS_MAX_BYTES;
767 last = -1;
768 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
769 if (priv.mask[i]) {
770 log_debug("Write byte %x: %x\n", i, priv.value[i]);
771 ret = rtc_write8(dev, i, priv.value[i]);
772 if (ret) {
773 ret = log_msg_ret("wri", ret);
774 goto done;
775 }
776 count++;
777 first = min(first, i);
778 last = max(last, i);
779 }
780 }
781 if (verbose) {
782 printf("Write %d bytes from offset %x to %x\n", count, first,
783 last);
784 }
785
786done:
787 free(priv.mask);
788 free(priv.value);
789 return ret;
790}
Simon Glasscfc402d2023-08-14 16:40:38 -0600791
792static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
793{
794 struct cedit_iter_priv *priv = vpriv;
795 const struct scene_menitem *mi;
796 struct scene_obj_menu *menu;
797 int val, ret;
798 uint i;
799
Simon Glassd8ff97c2024-10-14 16:31:57 -0600800 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glasscfc402d2023-08-14 16:40:38 -0600801 return 0;
802
803 menu = (struct scene_obj_menu *)obj;
804
805 /* figure out where to place this item */
806 if (!obj->bit_length)
807 return log_msg_ret("len", -EINVAL);
808 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
809 return log_msg_ret("bit", -E2BIG);
810
811 val = 0;
812 for (i = 0; i < obj->bit_length; i++) {
813 uint bitnum = obj->start_bit + i;
814 uint offset = CMOS_BYTE(bitnum);
815
816 /* read the byte if not already read */
817 if (!priv->mask[offset]) {
818 ret = rtc_read8(priv->dev, offset);
819 if (ret < 0)
820 return log_msg_ret("rea", ret);
821 priv->value[offset] = ret;
822
823 /* mark it as read */
824 priv->mask[offset] = 0xff;
825 }
826
827 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
828 val |= BIT(i);
829 log_debug("bit %x %x\n", bitnum, val);
830 }
831
832 /* update the current item */
Simon Glassf6987862024-10-14 16:31:59 -0600833 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass55a9de52024-10-14 16:32:00 -0600834 mi = scene_menuitem_find_val(menu, val);
Simon Glasscfc402d2023-08-14 16:40:38 -0600835 if (!mi)
836 return log_msg_ret("seq", -ENOENT);
837
838 menu->cur_item_id = mi->id;
839 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
840
841 return 0;
842}
843
844int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
845 bool verbose)
846{
847 struct cedit_iter_priv priv;
848 int ret, i, count, first, last;
849
850 /* read in the items */
851 priv.mask = calloc(1, CMOS_MAX_BYTES);
852 if (!priv.mask)
853 return log_msg_ret("mas", -ENOMEM);
854 priv.value = calloc(1, CMOS_MAX_BYTES);
855 if (!priv.value) {
856 free(priv.mask);
857 return log_msg_ret("val", -ENOMEM);
858 }
859 priv.dev = dev;
860
861 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
862 if (ret) {
863 log_debug("Failed to read CMOS (err=%d)\n", ret);
864 ret = log_msg_ret("set", ret);
865 goto done;
866 }
867
Simon Glassf6987862024-10-14 16:31:59 -0600868 /* indicate what bytes were read from the RTC */
Simon Glasscfc402d2023-08-14 16:40:38 -0600869 first = CMOS_MAX_BYTES;
870 last = -1;
871 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
872 if (priv.mask[i]) {
873 log_debug("Read byte %x: %x\n", i, priv.value[i]);
874 count++;
875 first = min(first, i);
876 last = max(last, i);
877 }
878 }
879 if (verbose) {
880 printf("Read %d bytes from offset %x to %x\n", count, first,
881 last);
882 }
883
884done:
885 free(priv.mask);
886 free(priv.value);
887 return ret;
888}