blob: 56dc7c6af15b066e2c958eb9e718ee2dacc62ef8 [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:
Simon Glass138a3972025-05-02 08:46:44 -060084 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -060085 case SCENEOBJT_TEXTEDIT:
Simon Glassb7a64532023-10-01 19:13:24 -060086 break;
87 case SCENEOBJT_MENU:
Simon Glassc8925112023-06-01 10:23:02 -060088 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060089 scene_menu_arrange(scn, &arr,
90 (struct scene_obj_menu *)obj);
Simon Glassc8925112023-06-01 10:23:02 -060091 y += 50;
Simon Glassb7a64532023-10-01 19:13:24 -060092 break;
Simon Glass23c3eb42023-10-01 19:13:37 -060093 case SCENEOBJT_TEXTLINE:
94 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060095 scene_textline_arrange(scn, &arr,
Simon Glass23c3eb42023-10-01 19:13:37 -060096 (struct scene_obj_textline *)obj);
97 y += 50;
98 break;
Simon Glassc8925112023-06-01 10:23:02 -060099 }
100 }
101
102 return 0;
103}
104
Simon Glass736bc0d2025-05-02 08:46:22 -0600105int cedit_prepare(struct expo *exp, struct udevice *vid_dev,
Simon Glass6a5af5f2023-08-14 16:40:27 -0600106 struct scene **scnp)
Simon Glassc8925112023-06-01 10:23:02 -0600107{
Simon Glass736bc0d2025-05-02 08:46:22 -0600108 struct udevice *dev = vid_dev;
Simon Glassc8925112023-06-01 10:23:02 -0600109 struct video_priv *vid_priv;
Simon Glassc8925112023-06-01 10:23:02 -0600110 struct scene *scn;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600111 uint scene_id;
Simon Glassc8925112023-06-01 10:23:02 -0600112 int ret;
113
Simon Glassc8925112023-06-01 10:23:02 -0600114 /* For now we only support a video console */
Simon Glassc8925112023-06-01 10:23:02 -0600115 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;
Simon Glass2d857262025-05-02 08:46:50 -0600129 exp->show_highlight = true;
Simon Glassc8925112023-06-01 10:23:02 -0600130
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 *scnp = scn;
147
148 return scene_id;
149}
150
Simon Glass14bd4132025-05-02 08:46:21 -0600151int cedit_do_action(struct expo *exp, struct scene *scn,
152 struct video_priv *vid_priv, struct expo_action *act)
153{
Simon Glass1b3388c2025-05-02 08:46:25 -0600154 int ret;
155
Simon Glass14bd4132025-05-02 08:46:21 -0600156 switch (act->type) {
157 case EXPOACT_NONE:
Simon Glass14bd4132025-05-02 08:46:21 -0600158 return -EAGAIN;
Simon Glass1b3388c2025-05-02 08:46:25 -0600159 case EXPOACT_POINT_ITEM:
160 ret = scene_menu_select_item(scn, scn->highlight_id,
161 act->select.id);
162 if (ret)
163 return log_msg_ret("cdp", ret);
164 break;
Simon Glass14bd4132025-05-02 08:46:21 -0600165 case EXPOACT_POINT_OBJ:
166 scene_set_highlight_id(scn, act->select.id);
167 cedit_arange(exp, vid_priv, scn->id);
168 break;
169 case EXPOACT_OPEN:
170 scene_set_open(scn, act->select.id, true);
171 cedit_arange(exp, vid_priv, scn->id);
172 switch (scn->highlight_id) {
173 case EXPOID_SAVE:
174 exp->done = true;
175 exp->save = true;
176 break;
177 case EXPOID_DISCARD:
178 exp->done = true;
179 break;
180 }
181 break;
182 case EXPOACT_CLOSE:
183 scene_set_open(scn, act->select.id, false);
184 cedit_arange(exp, vid_priv, scn->id);
185 break;
186 case EXPOACT_SELECT:
187 scene_set_open(scn, scn->highlight_id, false);
188 cedit_arange(exp, vid_priv, scn->id);
189 break;
190 case EXPOACT_QUIT:
191 log_debug("quitting\n");
192 exp->done = true;
193 break;
194 }
195
196 return 0;
197}
198
Simon Glass6a5af5f2023-08-14 16:40:27 -0600199int cedit_run(struct expo *exp)
200{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600201 struct video_priv *vid_priv;
Simon Glass736bc0d2025-05-02 08:46:22 -0600202 struct udevice *dev;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600203 struct scene *scn;
Simon Glass736bc0d2025-05-02 08:46:22 -0600204 uint scene_id;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600205 int ret;
206
Simon Glass736bc0d2025-05-02 08:46:22 -0600207 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
208 if (ret)
209 return log_msg_ret("vid", ret);
210 vid_priv = dev_get_uclass_priv(dev);
211
212 ret = cedit_prepare(exp, dev, &scn);
Simon Glass6a5af5f2023-08-14 16:40:27 -0600213 if (ret < 0)
214 return log_msg_ret("prep", ret);
215 scene_id = ret;
216
Simon Glass527d8642025-05-02 08:46:20 -0600217 exp->done = false;
218 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600219 do {
220 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600221
Simon Glass02708f52025-05-02 08:46:52 -0600222 ret = expo_render(exp);
223 if (ret)
224 return log_msg_ret("cer", ret);
225
Simon Glass137b4422025-05-02 08:46:16 -0600226 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600227 if (!ret)
228 cedit_do_action(exp, scn, vid_priv, &act);
229 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600230 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600231 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600232
233 if (ret)
234 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600235 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600236 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600237
238 return 0;
239}
Simon Glass28bf4352023-08-14 16:40:33 -0600240
241static int check_space(int ret, struct abuf *buf)
242{
243 if (ret == -FDT_ERR_NOSPACE) {
244 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
245 return log_msg_ret("spc", -ENOMEM);
246 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
247 abuf_size(buf));
248 if (ret)
249 return log_msg_ret("res", -EFAULT);
250 }
251
252 return 0;
253}
254
Simon Glassdb6a0512023-10-01 19:13:23 -0600255/**
256 * get_cur_menuitem_text() - Get the text of the currently selected item
257 *
258 * Looks up the object for the current item, finds text object for it and looks
259 * up the string for that text
260 *
261 * @menu: Menu to look at
262 * @strp: Returns a pointer to the next
263 * Return: 0 if OK, -ENOENT if something was not found
264 */
Simon Glass237f3752023-08-14 16:40:35 -0600265static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
266 const char **strp)
267{
268 struct scene *scn = menu->obj.scene;
269 const struct scene_menitem *mi;
270 const struct scene_obj_txt *txt;
271 const char *str;
272
273 mi = scene_menuitem_find(menu, menu->cur_item_id);
274 if (!mi)
275 return log_msg_ret("mi", -ENOENT);
276
277 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
278 if (!txt)
279 return log_msg_ret("txt", -ENOENT);
280
Simon Glass9ef02aa2025-05-02 08:46:37 -0600281 str = expo_get_str(scn->expo, txt->gen.str_id);
Simon Glass237f3752023-08-14 16:40:35 -0600282 if (!str)
283 return log_msg_ret("str", -ENOENT);
284 *strp = str;
285
286 return 0;
287}
288
Simon Glass6f3e87a2024-10-14 16:32:00 -0600289/**
290 * get_cur_menuitem_val() - Get the value of a menu's current item
291 *
292 * Obtains the value of the current item in the menu. If no value, then
293 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
294 * the currently selected item. If the first item is selected, this returns 0;
295 * if the second, 1; etc.
296 *
297 * @menu: Menu to check
298 * @valp: Returns current-item value / sequence number
299 * Return: 0 on success, else -ve error value
300 */
301static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
302{
303 const struct scene_menitem *mi;
304 int seq;
305
306 seq = 0;
307 list_for_each_entry(mi, &menu->item_head, sibling) {
308 if (mi->id == menu->cur_item_id) {
309 *valp = mi->value == INT_MAX ? seq : mi->value;
310 return 0;
311 }
312 seq++;
313 }
314
315 return log_msg_ret("nf", -ENOENT);
316}
317
318/**
319 * write_dt_string() - Write a string to the devicetree, expanding if needed
320 *
321 * If this fails, it tries again after expanding the devicetree a little
322 *
323 * @buf: Buffer containing the devicetree
324 * @name: Property name to use
325 * @str: String value
326 * Return: 0 if OK, -EFAULT if something went horribly wrong
327 */
Simon Glassf78388b2023-10-01 19:13:28 -0600328static int write_dt_string(struct abuf *buf, const char *name, const char *str)
329{
330 int ret, i;
331
Simon Glassf78388b2023-10-01 19:13:28 -0600332 ret = -EAGAIN;
333 for (i = 0; ret && i < 2; i++) {
334 ret = fdt_property_string(abuf_data(buf), name, str);
335 if (!i) {
336 ret = check_space(ret, buf);
337 if (ret)
338 return log_msg_ret("rs2", -ENOMEM);
339 }
340 }
341
342 /* this should not happen */
343 if (ret)
344 return log_msg_ret("str", -EFAULT);
345
346 return 0;
347}
348
Simon Glass6f3e87a2024-10-14 16:32:00 -0600349/**
350 * write_dt_u32() - Write an int to the devicetree, expanding if needed
351 *
352 * If this fails, it tries again after expanding the devicetree a little
353 *
354 * @buf: Buffer containing the devicetree
355 * @name: Property name to use
356 * @lva: Integer value
357 * Return: 0 if OK, -EFAULT if something went horribly wrong
358 */
359static int write_dt_u32(struct abuf *buf, const char *name, uint val)
360{
361 int ret, i;
362
363 /* write the text of the current item */
364 ret = -EAGAIN;
365 for (i = 0; ret && i < 2; i++) {
366 ret = fdt_property_u32(abuf_data(buf), name, val);
367 if (!i) {
368 ret = check_space(ret, buf);
369 if (ret)
370 return log_msg_ret("rs2", -ENOMEM);
371 }
372 }
373
374 /* this should not happen */
375 if (ret)
376 return log_msg_ret("str", -EFAULT);
377
378 return 0;
379}
380
Simon Glass28bf4352023-08-14 16:40:33 -0600381static int h_write_settings(struct scene_obj *obj, void *vpriv)
382{
383 struct cedit_iter_priv *priv = vpriv;
384 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600385 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600386
387 switch (obj->type) {
388 case SCENEOBJT_NONE:
389 case SCENEOBJT_IMAGE:
390 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600391 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600392 case SCENEOBJT_TEXTEDIT:
Simon Glass28bf4352023-08-14 16:40:33 -0600393 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600394 case SCENEOBJT_TEXTLINE: {
395 const struct scene_obj_textline *tline;
396
397 tline = (struct scene_obj_textline *)obj;
398 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
399 if (ret)
400 return log_msg_ret("wr2", ret);
401 break;
402 }
Simon Glass28bf4352023-08-14 16:40:33 -0600403 case SCENEOBJT_MENU: {
404 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600405 const char *str;
406 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600407 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600408
Simon Glassf78388b2023-10-01 19:13:28 -0600409 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600410 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600411 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600412 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600413 return log_msg_ret("wrt", ret);
414
415 snprintf(name, sizeof(name), "%s-value", obj->name);
416 ret = get_cur_menuitem_val(menu, &val);
417 if (ret < 0)
418 return log_msg_ret("cur", ret);
419 ret = write_dt_u32(buf, name, val);
420 if (ret)
421 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600422
Simon Glass237f3752023-08-14 16:40:35 -0600423 ret = get_cur_menuitem_text(menu, &str);
424 if (ret)
425 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600426
Simon Glassf78388b2023-10-01 19:13:28 -0600427 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600428 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600429 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600430 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600431 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600432
433 break;
434 }
435 }
436
437 return 0;
438}
439
440int cedit_write_settings(struct expo *exp, struct abuf *buf)
441{
442 struct cedit_iter_priv priv;
443 void *fdt;
444 int ret;
445
Simon Glass6651e942025-05-01 07:37:01 -0600446 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600447 return log_msg_ret("buf", -ENOMEM);
448
449 fdt = abuf_data(buf);
450 ret = fdt_create(fdt, abuf_size(buf));
451 if (!ret)
452 ret = fdt_finish_reservemap(fdt);
453 if (!ret)
454 ret = fdt_begin_node(fdt, "");
455 if (!ret)
456 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
457 if (ret) {
458 log_debug("Failed to start FDT (err=%d)\n", ret);
459 return log_msg_ret("sta", -EINVAL);
460 }
461
462 /* write out the items */
463 priv.buf = buf;
464 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
465 if (ret) {
466 log_debug("Failed to write settings (err=%d)\n", ret);
467 return log_msg_ret("set", ret);
468 }
469
470 ret = fdt_end_node(fdt);
471 if (!ret)
472 ret = fdt_end_node(fdt);
473 if (!ret)
474 ret = fdt_finish(fdt);
475 if (ret) {
476 log_debug("Failed to finish FDT (err=%d)\n", ret);
477 return log_msg_ret("fin", -EINVAL);
478 }
479
480 return 0;
481}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600482
483static int h_read_settings(struct scene_obj *obj, void *vpriv)
484{
485 struct cedit_iter_priv *priv = vpriv;
486 ofnode node = priv->node;
487
488 switch (obj->type) {
489 case SCENEOBJT_NONE:
490 case SCENEOBJT_IMAGE:
491 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600492 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600493 case SCENEOBJT_TEXTEDIT:
Simon Glassb1cd32b2023-08-14 16:40:34 -0600494 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600495 case SCENEOBJT_TEXTLINE: {
496 const struct scene_obj_textline *tline;
497 const char *val;
498 int len;
499
500 tline = (struct scene_obj_textline *)obj;
501
502 val = ofnode_read_prop(node, obj->name, &len);
503 if (len >= tline->max_chars)
504 return log_msg_ret("str", -ENOSPC);
505 strcpy(abuf_data(&tline->buf), val);
506 break;
507 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600508 case SCENEOBJT_MENU: {
509 struct scene_obj_menu *menu;
510 uint val;
511
512 if (ofnode_read_u32(node, obj->name, &val))
513 return log_msg_ret("rd", -ENOENT);
514 menu = (struct scene_obj_menu *)obj;
515 menu->cur_item_id = val;
516
517 break;
518 }
519 }
520
521 return 0;
522}
523
524int cedit_read_settings(struct expo *exp, oftree tree)
525{
526 struct cedit_iter_priv priv;
527 ofnode root, node;
528 int ret;
529
530 root = oftree_root(tree);
531 if (!ofnode_valid(root))
532 return log_msg_ret("roo", -ENOENT);
533 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
534 if (!ofnode_valid(node))
535 return log_msg_ret("pat", -ENOENT);
536
537 /* read in the items */
538 priv.node = node;
539 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
540 if (ret) {
541 log_debug("Failed to read settings (err=%d)\n", ret);
542 return log_msg_ret("set", ret);
543 }
544
545 return 0;
546}
Simon Glass237f3752023-08-14 16:40:35 -0600547
548static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
549{
550 const struct scene_obj_menu *menu;
551 struct cedit_iter_priv *priv = vpriv;
552 char name[80], var[60];
553 const char *str;
554 int val, ret;
555
Simon Glass53a0a2f2024-10-14 16:31:57 -0600556 if (obj->id < EXPOID_BASE_ID)
557 return 0;
558
Simon Glass237f3752023-08-14 16:40:35 -0600559 snprintf(var, sizeof(var), "c.%s", obj->name);
560
Simon Glassb7a64532023-10-01 19:13:24 -0600561 switch (obj->type) {
562 case SCENEOBJT_NONE:
563 case SCENEOBJT_IMAGE:
564 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600565 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600566 case SCENEOBJT_TEXTEDIT:
Simon Glassb7a64532023-10-01 19:13:24 -0600567 break;
568 case SCENEOBJT_MENU:
569 menu = (struct scene_obj_menu *)obj;
570 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600571
Simon Glassb7a64532023-10-01 19:13:24 -0600572 if (priv->verbose)
573 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600574
Simon Glassb7a64532023-10-01 19:13:24 -0600575 ret = env_set_ulong(var, val);
576 if (ret)
577 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600578
Simon Glassb7a64532023-10-01 19:13:24 -0600579 ret = get_cur_menuitem_text(menu, &str);
580 if (ret)
581 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600582
Simon Glassb7a64532023-10-01 19:13:24 -0600583 snprintf(name, sizeof(name), "c.%s-str", obj->name);
584 if (priv->verbose)
585 printf("%s=%s\n", name, str);
586
587 ret = env_set(name, str);
588 if (ret)
589 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600590
591 ret = get_cur_menuitem_val(menu, &val);
592 if (ret < 0)
593 return log_msg_ret("cur", ret);
594 snprintf(name, sizeof(name), "c.%s-value", obj->name);
595 if (priv->verbose)
596 printf("%s=%d\n", name, val);
597
Simon Glassb7a64532023-10-01 19:13:24 -0600598 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600599 case SCENEOBJT_TEXTLINE: {
600 const struct scene_obj_textline *tline;
601
602 tline = (struct scene_obj_textline *)obj;
603 str = abuf_data(&tline->buf);
604 ret = env_set(var, str);
605 if (ret)
606 return log_msg_ret("set", ret);
607
608 if (priv->verbose)
609 printf("%s=%s\n", var, str);
610
611 break;
612 }
Simon Glassb7a64532023-10-01 19:13:24 -0600613 }
Simon Glass237f3752023-08-14 16:40:35 -0600614
615 return 0;
616}
617
618int cedit_write_settings_env(struct expo *exp, bool verbose)
619{
620 struct cedit_iter_priv priv;
621 int ret;
622
623 /* write out the items */
624 priv.verbose = verbose;
625 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
626 if (ret) {
627 log_debug("Failed to write settings to env (err=%d)\n", ret);
628 return log_msg_ret("set", ret);
629 }
630
631 return 0;
632}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600633
634static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
635{
636 struct cedit_iter_priv *priv = vpriv;
637 struct scene_obj_menu *menu;
638 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600639 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600640
Simon Glass53a0a2f2024-10-14 16:31:57 -0600641 if (obj->id < EXPOID_BASE_ID)
642 return 0;
643
Simon Glass0f2e5a62023-08-14 16:40:36 -0600644 snprintf(var, sizeof(var), "c.%s", obj->name);
645
Simon Glassb7a64532023-10-01 19:13:24 -0600646 switch (obj->type) {
647 case SCENEOBJT_NONE:
648 case SCENEOBJT_IMAGE:
649 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600650 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600651 case SCENEOBJT_TEXTEDIT:
Simon Glassb7a64532023-10-01 19:13:24 -0600652 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 Glass0f2e5a62023-08-14 16:40:36 -0600660
Simon Glassb7a64532023-10-01 19:13:24 -0600661 /*
662 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600663 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600664 */
665 menu->cur_item_id = val;
666 break;
Simon Glass23c3eb42023-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 Glassb7a64532023-10-01 19:13:24 -0600682 }
Simon Glass0f2e5a62023-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 Glass2b91ca62023-08-14 16:40:37 -0600702
Simon Glass2b91ca62023-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 Glass6f3e87a2024-10-14 16:32:00 -0600708 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600709
Simon Glass53a0a2f2024-10-14 16:31:57 -0600710 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600711 return 0;
712
713 menu = (struct scene_obj_menu *)obj;
714 val = menu->cur_item_id;
715
Simon Glass6f3e87a2024-10-14 16:32:00 -0600716 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600717 if (ret < 0)
718 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600719 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-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 Glass6f3e87a2024-10-14 16:32:00 -0600727 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600728 uint bitnum = obj->start_bit + i;
729
730 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600731 if (val & 1)
Simon Glass2b91ca62023-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 Glass330aa1e2024-10-14 16:31:59 -0600765 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-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 Glass4462fa32023-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 Glass53a0a2f2024-10-14 16:31:57 -0600800 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-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 Glass330aa1e2024-10-14 16:31:59 -0600833 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600834 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-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 Glass330aa1e2024-10-14 16:31:59 -0600868 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-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}