blob: eac851b395a525e6db71a621178ff52da7d4f6d1 [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 Glass736bc0d2025-05-02 08:46:22 -0600103int cedit_prepare(struct expo *exp, struct udevice *vid_dev,
Simon Glass6a5af5f2023-08-14 16:40:27 -0600104 struct scene **scnp)
Simon Glassc8925112023-06-01 10:23:02 -0600105{
Simon Glass736bc0d2025-05-02 08:46:22 -0600106 struct udevice *dev = vid_dev;
Simon Glassc8925112023-06-01 10:23:02 -0600107 struct video_priv *vid_priv;
Simon Glassc8925112023-06-01 10:23:02 -0600108 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 */
Simon Glassc8925112023-06-01 10:23:02 -0600113 ret = expo_set_display(exp, dev);
114 if (ret)
115 return log_msg_ret("dis", ret);
116
117 ret = expo_first_scene_id(exp);
118 if (ret < 0)
119 return log_msg_ret("scn", ret);
120 scene_id = ret;
121
122 ret = expo_set_scene_id(exp, scene_id);
123 if (ret)
124 return log_msg_ret("sid", ret);
125
126 exp->popup = true;
127
128 /* This is not supported for now */
129 if (0)
130 expo_set_text_mode(exp, true);
131
132 vid_priv = dev_get_uclass_priv(dev);
133
134 scn = expo_lookup_scene_id(exp, scene_id);
135 scene_highlight_first(scn);
136
137 cedit_arange(exp, vid_priv, scene_id);
138
139 ret = expo_calc_dims(exp);
140 if (ret)
141 return log_msg_ret("dim", ret);
142
Simon Glass6a5af5f2023-08-14 16:40:27 -0600143 *scnp = scn;
144
145 return scene_id;
146}
147
Simon Glass14bd4132025-05-02 08:46:21 -0600148int cedit_do_action(struct expo *exp, struct scene *scn,
149 struct video_priv *vid_priv, struct expo_action *act)
150{
151 switch (act->type) {
152 case EXPOACT_NONE:
153 case EXPOACT_POINT_ITEM:
154 return -EAGAIN;
155 case EXPOACT_POINT_OBJ:
156 scene_set_highlight_id(scn, act->select.id);
157 cedit_arange(exp, vid_priv, scn->id);
158 break;
159 case EXPOACT_OPEN:
160 scene_set_open(scn, act->select.id, true);
161 cedit_arange(exp, vid_priv, scn->id);
162 switch (scn->highlight_id) {
163 case EXPOID_SAVE:
164 exp->done = true;
165 exp->save = true;
166 break;
167 case EXPOID_DISCARD:
168 exp->done = true;
169 break;
170 }
171 break;
172 case EXPOACT_CLOSE:
173 scene_set_open(scn, act->select.id, false);
174 cedit_arange(exp, vid_priv, scn->id);
175 break;
176 case EXPOACT_SELECT:
177 scene_set_open(scn, scn->highlight_id, false);
178 cedit_arange(exp, vid_priv, scn->id);
179 break;
180 case EXPOACT_QUIT:
181 log_debug("quitting\n");
182 exp->done = true;
183 break;
184 }
185
186 return 0;
187}
188
Simon Glass6a5af5f2023-08-14 16:40:27 -0600189int cedit_run(struct expo *exp)
190{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600191 struct video_priv *vid_priv;
Simon Glass736bc0d2025-05-02 08:46:22 -0600192 struct udevice *dev;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600193 struct scene *scn;
Simon Glass736bc0d2025-05-02 08:46:22 -0600194 uint scene_id;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600195 int ret;
196
Simon Glass736bc0d2025-05-02 08:46:22 -0600197 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
198 if (ret)
199 return log_msg_ret("vid", ret);
200 vid_priv = dev_get_uclass_priv(dev);
201
202 ret = cedit_prepare(exp, dev, &scn);
Simon Glass6a5af5f2023-08-14 16:40:27 -0600203 if (ret < 0)
204 return log_msg_ret("prep", ret);
205 scene_id = ret;
206
Simon Glass527d8642025-05-02 08:46:20 -0600207 exp->done = false;
208 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600209 do {
210 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600211
Simon Glass137b4422025-05-02 08:46:16 -0600212 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600213 if (!ret)
214 cedit_do_action(exp, scn, vid_priv, &act);
215 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600216 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600217 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600218
219 if (ret)
220 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600221 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600222 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600223
224 return 0;
225}
Simon Glass28bf4352023-08-14 16:40:33 -0600226
227static int check_space(int ret, struct abuf *buf)
228{
229 if (ret == -FDT_ERR_NOSPACE) {
230 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
231 return log_msg_ret("spc", -ENOMEM);
232 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
233 abuf_size(buf));
234 if (ret)
235 return log_msg_ret("res", -EFAULT);
236 }
237
238 return 0;
239}
240
Simon Glassdb6a0512023-10-01 19:13:23 -0600241/**
242 * get_cur_menuitem_text() - Get the text of the currently selected item
243 *
244 * Looks up the object for the current item, finds text object for it and looks
245 * up the string for that text
246 *
247 * @menu: Menu to look at
248 * @strp: Returns a pointer to the next
249 * Return: 0 if OK, -ENOENT if something was not found
250 */
Simon Glass237f3752023-08-14 16:40:35 -0600251static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
252 const char **strp)
253{
254 struct scene *scn = menu->obj.scene;
255 const struct scene_menitem *mi;
256 const struct scene_obj_txt *txt;
257 const char *str;
258
259 mi = scene_menuitem_find(menu, menu->cur_item_id);
260 if (!mi)
261 return log_msg_ret("mi", -ENOENT);
262
263 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
264 if (!txt)
265 return log_msg_ret("txt", -ENOENT);
266
267 str = expo_get_str(scn->expo, txt->str_id);
268 if (!str)
269 return log_msg_ret("str", -ENOENT);
270 *strp = str;
271
272 return 0;
273}
274
Simon Glass6f3e87a2024-10-14 16:32:00 -0600275/**
276 * get_cur_menuitem_val() - Get the value of a menu's current item
277 *
278 * Obtains the value of the current item in the menu. If no value, then
279 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
280 * the currently selected item. If the first item is selected, this returns 0;
281 * if the second, 1; etc.
282 *
283 * @menu: Menu to check
284 * @valp: Returns current-item value / sequence number
285 * Return: 0 on success, else -ve error value
286 */
287static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
288{
289 const struct scene_menitem *mi;
290 int seq;
291
292 seq = 0;
293 list_for_each_entry(mi, &menu->item_head, sibling) {
294 if (mi->id == menu->cur_item_id) {
295 *valp = mi->value == INT_MAX ? seq : mi->value;
296 return 0;
297 }
298 seq++;
299 }
300
301 return log_msg_ret("nf", -ENOENT);
302}
303
304/**
305 * write_dt_string() - Write a string to the devicetree, expanding if needed
306 *
307 * If this fails, it tries again after expanding the devicetree a little
308 *
309 * @buf: Buffer containing the devicetree
310 * @name: Property name to use
311 * @str: String value
312 * Return: 0 if OK, -EFAULT if something went horribly wrong
313 */
Simon Glassf78388b2023-10-01 19:13:28 -0600314static int write_dt_string(struct abuf *buf, const char *name, const char *str)
315{
316 int ret, i;
317
Simon Glassf78388b2023-10-01 19:13:28 -0600318 ret = -EAGAIN;
319 for (i = 0; ret && i < 2; i++) {
320 ret = fdt_property_string(abuf_data(buf), name, str);
321 if (!i) {
322 ret = check_space(ret, buf);
323 if (ret)
324 return log_msg_ret("rs2", -ENOMEM);
325 }
326 }
327
328 /* this should not happen */
329 if (ret)
330 return log_msg_ret("str", -EFAULT);
331
332 return 0;
333}
334
Simon Glass6f3e87a2024-10-14 16:32:00 -0600335/**
336 * write_dt_u32() - Write an int to the devicetree, expanding if needed
337 *
338 * If this fails, it tries again after expanding the devicetree a little
339 *
340 * @buf: Buffer containing the devicetree
341 * @name: Property name to use
342 * @lva: Integer value
343 * Return: 0 if OK, -EFAULT if something went horribly wrong
344 */
345static int write_dt_u32(struct abuf *buf, const char *name, uint val)
346{
347 int ret, i;
348
349 /* write the text of the current item */
350 ret = -EAGAIN;
351 for (i = 0; ret && i < 2; i++) {
352 ret = fdt_property_u32(abuf_data(buf), name, val);
353 if (!i) {
354 ret = check_space(ret, buf);
355 if (ret)
356 return log_msg_ret("rs2", -ENOMEM);
357 }
358 }
359
360 /* this should not happen */
361 if (ret)
362 return log_msg_ret("str", -EFAULT);
363
364 return 0;
365}
366
Simon Glass28bf4352023-08-14 16:40:33 -0600367static int h_write_settings(struct scene_obj *obj, void *vpriv)
368{
369 struct cedit_iter_priv *priv = vpriv;
370 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600371 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600372
373 switch (obj->type) {
374 case SCENEOBJT_NONE:
375 case SCENEOBJT_IMAGE:
376 case SCENEOBJT_TEXT:
377 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600378 case SCENEOBJT_TEXTLINE: {
379 const struct scene_obj_textline *tline;
380
381 tline = (struct scene_obj_textline *)obj;
382 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
383 if (ret)
384 return log_msg_ret("wr2", ret);
385 break;
386 }
Simon Glass28bf4352023-08-14 16:40:33 -0600387 case SCENEOBJT_MENU: {
388 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600389 const char *str;
390 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600391 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600392
Simon Glassf78388b2023-10-01 19:13:28 -0600393 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600394 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600395 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600396 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600397 return log_msg_ret("wrt", ret);
398
399 snprintf(name, sizeof(name), "%s-value", obj->name);
400 ret = get_cur_menuitem_val(menu, &val);
401 if (ret < 0)
402 return log_msg_ret("cur", ret);
403 ret = write_dt_u32(buf, name, val);
404 if (ret)
405 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600406
Simon Glass237f3752023-08-14 16:40:35 -0600407 ret = get_cur_menuitem_text(menu, &str);
408 if (ret)
409 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600410
Simon Glassf78388b2023-10-01 19:13:28 -0600411 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600412 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600413 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600414 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600415 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600416
417 break;
418 }
419 }
420
421 return 0;
422}
423
424int cedit_write_settings(struct expo *exp, struct abuf *buf)
425{
426 struct cedit_iter_priv priv;
427 void *fdt;
428 int ret;
429
Simon Glass6651e942025-05-01 07:37:01 -0600430 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600431 return log_msg_ret("buf", -ENOMEM);
432
433 fdt = abuf_data(buf);
434 ret = fdt_create(fdt, abuf_size(buf));
435 if (!ret)
436 ret = fdt_finish_reservemap(fdt);
437 if (!ret)
438 ret = fdt_begin_node(fdt, "");
439 if (!ret)
440 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
441 if (ret) {
442 log_debug("Failed to start FDT (err=%d)\n", ret);
443 return log_msg_ret("sta", -EINVAL);
444 }
445
446 /* write out the items */
447 priv.buf = buf;
448 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
449 if (ret) {
450 log_debug("Failed to write settings (err=%d)\n", ret);
451 return log_msg_ret("set", ret);
452 }
453
454 ret = fdt_end_node(fdt);
455 if (!ret)
456 ret = fdt_end_node(fdt);
457 if (!ret)
458 ret = fdt_finish(fdt);
459 if (ret) {
460 log_debug("Failed to finish FDT (err=%d)\n", ret);
461 return log_msg_ret("fin", -EINVAL);
462 }
463
464 return 0;
465}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600466
467static int h_read_settings(struct scene_obj *obj, void *vpriv)
468{
469 struct cedit_iter_priv *priv = vpriv;
470 ofnode node = priv->node;
471
472 switch (obj->type) {
473 case SCENEOBJT_NONE:
474 case SCENEOBJT_IMAGE:
475 case SCENEOBJT_TEXT:
476 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600477 case SCENEOBJT_TEXTLINE: {
478 const struct scene_obj_textline *tline;
479 const char *val;
480 int len;
481
482 tline = (struct scene_obj_textline *)obj;
483
484 val = ofnode_read_prop(node, obj->name, &len);
485 if (len >= tline->max_chars)
486 return log_msg_ret("str", -ENOSPC);
487 strcpy(abuf_data(&tline->buf), val);
488 break;
489 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600490 case SCENEOBJT_MENU: {
491 struct scene_obj_menu *menu;
492 uint val;
493
494 if (ofnode_read_u32(node, obj->name, &val))
495 return log_msg_ret("rd", -ENOENT);
496 menu = (struct scene_obj_menu *)obj;
497 menu->cur_item_id = val;
498
499 break;
500 }
501 }
502
503 return 0;
504}
505
506int cedit_read_settings(struct expo *exp, oftree tree)
507{
508 struct cedit_iter_priv priv;
509 ofnode root, node;
510 int ret;
511
512 root = oftree_root(tree);
513 if (!ofnode_valid(root))
514 return log_msg_ret("roo", -ENOENT);
515 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
516 if (!ofnode_valid(node))
517 return log_msg_ret("pat", -ENOENT);
518
519 /* read in the items */
520 priv.node = node;
521 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
522 if (ret) {
523 log_debug("Failed to read settings (err=%d)\n", ret);
524 return log_msg_ret("set", ret);
525 }
526
527 return 0;
528}
Simon Glass237f3752023-08-14 16:40:35 -0600529
530static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
531{
532 const struct scene_obj_menu *menu;
533 struct cedit_iter_priv *priv = vpriv;
534 char name[80], var[60];
535 const char *str;
536 int val, ret;
537
Simon Glass53a0a2f2024-10-14 16:31:57 -0600538 if (obj->id < EXPOID_BASE_ID)
539 return 0;
540
Simon Glass237f3752023-08-14 16:40:35 -0600541 snprintf(var, sizeof(var), "c.%s", obj->name);
542
Simon Glassb7a64532023-10-01 19:13:24 -0600543 switch (obj->type) {
544 case SCENEOBJT_NONE:
545 case SCENEOBJT_IMAGE:
546 case SCENEOBJT_TEXT:
547 break;
548 case SCENEOBJT_MENU:
549 menu = (struct scene_obj_menu *)obj;
550 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600551
Simon Glassb7a64532023-10-01 19:13:24 -0600552 if (priv->verbose)
553 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600554
Simon Glassb7a64532023-10-01 19:13:24 -0600555 ret = env_set_ulong(var, val);
556 if (ret)
557 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600558
Simon Glassb7a64532023-10-01 19:13:24 -0600559 ret = get_cur_menuitem_text(menu, &str);
560 if (ret)
561 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600562
Simon Glassb7a64532023-10-01 19:13:24 -0600563 snprintf(name, sizeof(name), "c.%s-str", obj->name);
564 if (priv->verbose)
565 printf("%s=%s\n", name, str);
566
567 ret = env_set(name, str);
568 if (ret)
569 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600570
571 ret = get_cur_menuitem_val(menu, &val);
572 if (ret < 0)
573 return log_msg_ret("cur", ret);
574 snprintf(name, sizeof(name), "c.%s-value", obj->name);
575 if (priv->verbose)
576 printf("%s=%d\n", name, val);
577
Simon Glassb7a64532023-10-01 19:13:24 -0600578 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600579 case SCENEOBJT_TEXTLINE: {
580 const struct scene_obj_textline *tline;
581
582 tline = (struct scene_obj_textline *)obj;
583 str = abuf_data(&tline->buf);
584 ret = env_set(var, str);
585 if (ret)
586 return log_msg_ret("set", ret);
587
588 if (priv->verbose)
589 printf("%s=%s\n", var, str);
590
591 break;
592 }
Simon Glassb7a64532023-10-01 19:13:24 -0600593 }
Simon Glass237f3752023-08-14 16:40:35 -0600594
595 return 0;
596}
597
598int cedit_write_settings_env(struct expo *exp, bool verbose)
599{
600 struct cedit_iter_priv priv;
601 int ret;
602
603 /* write out the items */
604 priv.verbose = verbose;
605 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
606 if (ret) {
607 log_debug("Failed to write settings to env (err=%d)\n", ret);
608 return log_msg_ret("set", ret);
609 }
610
611 return 0;
612}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600613
614static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
615{
616 struct cedit_iter_priv *priv = vpriv;
617 struct scene_obj_menu *menu;
618 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600619 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600620
Simon Glass53a0a2f2024-10-14 16:31:57 -0600621 if (obj->id < EXPOID_BASE_ID)
622 return 0;
623
Simon Glass0f2e5a62023-08-14 16:40:36 -0600624 snprintf(var, sizeof(var), "c.%s", obj->name);
625
Simon Glassb7a64532023-10-01 19:13:24 -0600626 switch (obj->type) {
627 case SCENEOBJT_NONE:
628 case SCENEOBJT_IMAGE:
629 case SCENEOBJT_TEXT:
630 break;
631 case SCENEOBJT_MENU:
632 menu = (struct scene_obj_menu *)obj;
633 val = env_get_ulong(var, 10, 0);
634 if (priv->verbose)
635 printf("%s=%d\n", var, val);
636 if (!val)
637 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600638
Simon Glassb7a64532023-10-01 19:13:24 -0600639 /*
640 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600641 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600642 */
643 menu->cur_item_id = val;
644 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600645 case SCENEOBJT_TEXTLINE: {
646 const struct scene_obj_textline *tline;
647 const char *value;
648
649 tline = (struct scene_obj_textline *)obj;
650 value = env_get(var);
651 if (value && strlen(value) >= tline->max_chars)
652 return log_msg_ret("str", -ENOSPC);
653 if (!value)
654 value = "";
655 if (priv->verbose)
656 printf("%s=%s\n", var, value);
657 strcpy(abuf_data(&tline->buf), value);
658 break;
659 }
Simon Glassb7a64532023-10-01 19:13:24 -0600660 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600661
662 return 0;
663}
664
665int cedit_read_settings_env(struct expo *exp, bool verbose)
666{
667 struct cedit_iter_priv priv;
668 int ret;
669
670 /* write out the items */
671 priv.verbose = verbose;
672 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
673 if (ret) {
674 log_debug("Failed to read settings from env (err=%d)\n", ret);
675 return log_msg_ret("set", ret);
676 }
677
678 return 0;
679}
Simon Glass2b91ca62023-08-14 16:40:37 -0600680
Simon Glass2b91ca62023-08-14 16:40:37 -0600681static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
682{
683 const struct scene_obj_menu *menu;
684 struct cedit_iter_priv *priv = vpriv;
685 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600686 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600687
Simon Glass53a0a2f2024-10-14 16:31:57 -0600688 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600689 return 0;
690
691 menu = (struct scene_obj_menu *)obj;
692 val = menu->cur_item_id;
693
Simon Glass6f3e87a2024-10-14 16:32:00 -0600694 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600695 if (ret < 0)
696 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600697 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600698
699 /* figure out where to place this item */
700 if (!obj->bit_length)
701 return log_msg_ret("len", -EINVAL);
702 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
703 return log_msg_ret("bit", -E2BIG);
704
Simon Glass6f3e87a2024-10-14 16:32:00 -0600705 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600706 uint bitnum = obj->start_bit + i;
707
708 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600709 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600710 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
711 log_debug("bit %x %x %x\n", bitnum,
712 priv->mask[CMOS_BYTE(bitnum)],
713 priv->value[CMOS_BYTE(bitnum)]);
714 }
715
716 return 0;
717}
718
719int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
720 bool verbose)
721{
722 struct cedit_iter_priv priv;
723 int ret, i, count, first, last;
724
725 /* write out the items */
726 priv.mask = calloc(1, CMOS_MAX_BYTES);
727 if (!priv.mask)
728 return log_msg_ret("mas", -ENOMEM);
729 priv.value = calloc(1, CMOS_MAX_BYTES);
730 if (!priv.value) {
731 free(priv.mask);
732 return log_msg_ret("val", -ENOMEM);
733 }
734
735 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
736 if (ret) {
737 log_debug("Failed to write CMOS (err=%d)\n", ret);
738 ret = log_msg_ret("set", ret);
739 goto done;
740 }
741
742 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600743 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600744 first = CMOS_MAX_BYTES;
745 last = -1;
746 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
747 if (priv.mask[i]) {
748 log_debug("Write byte %x: %x\n", i, priv.value[i]);
749 ret = rtc_write8(dev, i, priv.value[i]);
750 if (ret) {
751 ret = log_msg_ret("wri", ret);
752 goto done;
753 }
754 count++;
755 first = min(first, i);
756 last = max(last, i);
757 }
758 }
759 if (verbose) {
760 printf("Write %d bytes from offset %x to %x\n", count, first,
761 last);
762 }
763
764done:
765 free(priv.mask);
766 free(priv.value);
767 return ret;
768}
Simon Glass4462fa32023-08-14 16:40:38 -0600769
770static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
771{
772 struct cedit_iter_priv *priv = vpriv;
773 const struct scene_menitem *mi;
774 struct scene_obj_menu *menu;
775 int val, ret;
776 uint i;
777
Simon Glass53a0a2f2024-10-14 16:31:57 -0600778 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600779 return 0;
780
781 menu = (struct scene_obj_menu *)obj;
782
783 /* figure out where to place this item */
784 if (!obj->bit_length)
785 return log_msg_ret("len", -EINVAL);
786 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
787 return log_msg_ret("bit", -E2BIG);
788
789 val = 0;
790 for (i = 0; i < obj->bit_length; i++) {
791 uint bitnum = obj->start_bit + i;
792 uint offset = CMOS_BYTE(bitnum);
793
794 /* read the byte if not already read */
795 if (!priv->mask[offset]) {
796 ret = rtc_read8(priv->dev, offset);
797 if (ret < 0)
798 return log_msg_ret("rea", ret);
799 priv->value[offset] = ret;
800
801 /* mark it as read */
802 priv->mask[offset] = 0xff;
803 }
804
805 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
806 val |= BIT(i);
807 log_debug("bit %x %x\n", bitnum, val);
808 }
809
810 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600811 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600812 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600813 if (!mi)
814 return log_msg_ret("seq", -ENOENT);
815
816 menu->cur_item_id = mi->id;
817 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
818
819 return 0;
820}
821
822int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
823 bool verbose)
824{
825 struct cedit_iter_priv priv;
826 int ret, i, count, first, last;
827
828 /* read in the items */
829 priv.mask = calloc(1, CMOS_MAX_BYTES);
830 if (!priv.mask)
831 return log_msg_ret("mas", -ENOMEM);
832 priv.value = calloc(1, CMOS_MAX_BYTES);
833 if (!priv.value) {
834 free(priv.mask);
835 return log_msg_ret("val", -ENOMEM);
836 }
837 priv.dev = dev;
838
839 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
840 if (ret) {
841 log_debug("Failed to read CMOS (err=%d)\n", ret);
842 ret = log_msg_ret("set", ret);
843 goto done;
844 }
845
Simon Glass330aa1e2024-10-14 16:31:59 -0600846 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600847 first = CMOS_MAX_BYTES;
848 last = -1;
849 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
850 if (priv.mask[i]) {
851 log_debug("Read byte %x: %x\n", i, priv.value[i]);
852 count++;
853 first = min(first, i);
854 last = max(last, i);
855 }
856 }
857 if (verbose) {
858 printf("Read %d bytes from offset %x to %x\n", count, first,
859 last);
860 }
861
862done:
863 free(priv.mask);
864 free(priv.value);
865 return ret;
866}