blob: 9153fe769c6dfcbce733a3639feda565fa3d2a7a [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 Glassb7a64532023-10-01 19:13:24 -060085 break;
86 case SCENEOBJT_MENU:
Simon Glassc8925112023-06-01 10:23:02 -060087 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060088 scene_menu_arrange(scn, &arr,
89 (struct scene_obj_menu *)obj);
Simon Glassc8925112023-06-01 10:23:02 -060090 y += 50;
Simon Glassb7a64532023-10-01 19:13:24 -060091 break;
Simon Glass23c3eb42023-10-01 19:13:37 -060092 case SCENEOBJT_TEXTLINE:
93 scene_obj_set_pos(scn, obj->id, 50, y);
Simon Glass377f18e2024-10-14 16:31:55 -060094 scene_textline_arrange(scn, &arr,
Simon Glass23c3eb42023-10-01 19:13:37 -060095 (struct scene_obj_textline *)obj);
96 y += 50;
97 break;
Simon Glassc8925112023-06-01 10:23:02 -060098 }
99 }
100
101 return 0;
102}
103
Simon Glass736bc0d2025-05-02 08:46:22 -0600104int cedit_prepare(struct expo *exp, struct udevice *vid_dev,
Simon Glass6a5af5f2023-08-14 16:40:27 -0600105 struct scene **scnp)
Simon Glassc8925112023-06-01 10:23:02 -0600106{
Simon Glass736bc0d2025-05-02 08:46:22 -0600107 struct udevice *dev = vid_dev;
Simon Glassc8925112023-06-01 10:23:02 -0600108 struct video_priv *vid_priv;
Simon Glassc8925112023-06-01 10:23:02 -0600109 struct scene *scn;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600110 uint scene_id;
Simon Glassc8925112023-06-01 10:23:02 -0600111 int ret;
112
Simon Glassc8925112023-06-01 10:23:02 -0600113 /* For now we only support a video console */
Simon Glassc8925112023-06-01 10:23:02 -0600114 ret = expo_set_display(exp, dev);
115 if (ret)
116 return log_msg_ret("dis", ret);
117
118 ret = expo_first_scene_id(exp);
119 if (ret < 0)
120 return log_msg_ret("scn", ret);
121 scene_id = ret;
122
123 ret = expo_set_scene_id(exp, scene_id);
124 if (ret)
125 return log_msg_ret("sid", ret);
126
127 exp->popup = true;
128
129 /* This is not supported for now */
130 if (0)
131 expo_set_text_mode(exp, true);
132
133 vid_priv = dev_get_uclass_priv(dev);
134
135 scn = expo_lookup_scene_id(exp, scene_id);
136 scene_highlight_first(scn);
137
138 cedit_arange(exp, vid_priv, scene_id);
139
140 ret = expo_calc_dims(exp);
141 if (ret)
142 return log_msg_ret("dim", ret);
143
Simon Glass6a5af5f2023-08-14 16:40:27 -0600144 *scnp = scn;
145
146 return scene_id;
147}
148
Simon Glass14bd4132025-05-02 08:46:21 -0600149int cedit_do_action(struct expo *exp, struct scene *scn,
150 struct video_priv *vid_priv, struct expo_action *act)
151{
Simon Glass1b3388c2025-05-02 08:46:25 -0600152 int ret;
153
Simon Glass14bd4132025-05-02 08:46:21 -0600154 switch (act->type) {
155 case EXPOACT_NONE:
Simon Glass14bd4132025-05-02 08:46:21 -0600156 return -EAGAIN;
Simon Glass1b3388c2025-05-02 08:46:25 -0600157 case EXPOACT_POINT_ITEM:
158 ret = scene_menu_select_item(scn, scn->highlight_id,
159 act->select.id);
160 if (ret)
161 return log_msg_ret("cdp", ret);
162 break;
Simon Glass14bd4132025-05-02 08:46:21 -0600163 case EXPOACT_POINT_OBJ:
164 scene_set_highlight_id(scn, act->select.id);
165 cedit_arange(exp, vid_priv, scn->id);
166 break;
167 case EXPOACT_OPEN:
168 scene_set_open(scn, act->select.id, true);
169 cedit_arange(exp, vid_priv, scn->id);
170 switch (scn->highlight_id) {
171 case EXPOID_SAVE:
172 exp->done = true;
173 exp->save = true;
174 break;
175 case EXPOID_DISCARD:
176 exp->done = true;
177 break;
178 }
179 break;
180 case EXPOACT_CLOSE:
181 scene_set_open(scn, act->select.id, false);
182 cedit_arange(exp, vid_priv, scn->id);
183 break;
184 case EXPOACT_SELECT:
185 scene_set_open(scn, scn->highlight_id, false);
186 cedit_arange(exp, vid_priv, scn->id);
187 break;
188 case EXPOACT_QUIT:
189 log_debug("quitting\n");
190 exp->done = true;
191 break;
192 }
193
194 return 0;
195}
196
Simon Glass6a5af5f2023-08-14 16:40:27 -0600197int cedit_run(struct expo *exp)
198{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600199 struct video_priv *vid_priv;
Simon Glass736bc0d2025-05-02 08:46:22 -0600200 struct udevice *dev;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600201 struct scene *scn;
Simon Glass736bc0d2025-05-02 08:46:22 -0600202 uint scene_id;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600203 int ret;
204
Simon Glass736bc0d2025-05-02 08:46:22 -0600205 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
206 if (ret)
207 return log_msg_ret("vid", ret);
208 vid_priv = dev_get_uclass_priv(dev);
209
210 ret = cedit_prepare(exp, dev, &scn);
Simon Glass6a5af5f2023-08-14 16:40:27 -0600211 if (ret < 0)
212 return log_msg_ret("prep", ret);
213 scene_id = ret;
214
Simon Glass527d8642025-05-02 08:46:20 -0600215 exp->done = false;
216 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600217 do {
218 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600219
Simon Glass137b4422025-05-02 08:46:16 -0600220 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600221 if (!ret)
222 cedit_do_action(exp, scn, vid_priv, &act);
223 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600224 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600225 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600226
227 if (ret)
228 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600229 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600230 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600231
232 return 0;
233}
Simon Glass28bf4352023-08-14 16:40:33 -0600234
235static int check_space(int ret, struct abuf *buf)
236{
237 if (ret == -FDT_ERR_NOSPACE) {
238 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
239 return log_msg_ret("spc", -ENOMEM);
240 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
241 abuf_size(buf));
242 if (ret)
243 return log_msg_ret("res", -EFAULT);
244 }
245
246 return 0;
247}
248
Simon Glassdb6a0512023-10-01 19:13:23 -0600249/**
250 * get_cur_menuitem_text() - Get the text of the currently selected item
251 *
252 * Looks up the object for the current item, finds text object for it and looks
253 * up the string for that text
254 *
255 * @menu: Menu to look at
256 * @strp: Returns a pointer to the next
257 * Return: 0 if OK, -ENOENT if something was not found
258 */
Simon Glass237f3752023-08-14 16:40:35 -0600259static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
260 const char **strp)
261{
262 struct scene *scn = menu->obj.scene;
263 const struct scene_menitem *mi;
264 const struct scene_obj_txt *txt;
265 const char *str;
266
267 mi = scene_menuitem_find(menu, menu->cur_item_id);
268 if (!mi)
269 return log_msg_ret("mi", -ENOENT);
270
271 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
272 if (!txt)
273 return log_msg_ret("txt", -ENOENT);
274
Simon Glass9ef02aa2025-05-02 08:46:37 -0600275 str = expo_get_str(scn->expo, txt->gen.str_id);
Simon Glass237f3752023-08-14 16:40:35 -0600276 if (!str)
277 return log_msg_ret("str", -ENOENT);
278 *strp = str;
279
280 return 0;
281}
282
Simon Glass6f3e87a2024-10-14 16:32:00 -0600283/**
284 * get_cur_menuitem_val() - Get the value of a menu's current item
285 *
286 * Obtains the value of the current item in the menu. If no value, then
287 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
288 * the currently selected item. If the first item is selected, this returns 0;
289 * if the second, 1; etc.
290 *
291 * @menu: Menu to check
292 * @valp: Returns current-item value / sequence number
293 * Return: 0 on success, else -ve error value
294 */
295static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
296{
297 const struct scene_menitem *mi;
298 int seq;
299
300 seq = 0;
301 list_for_each_entry(mi, &menu->item_head, sibling) {
302 if (mi->id == menu->cur_item_id) {
303 *valp = mi->value == INT_MAX ? seq : mi->value;
304 return 0;
305 }
306 seq++;
307 }
308
309 return log_msg_ret("nf", -ENOENT);
310}
311
312/**
313 * write_dt_string() - Write a string to the devicetree, expanding if needed
314 *
315 * If this fails, it tries again after expanding the devicetree a little
316 *
317 * @buf: Buffer containing the devicetree
318 * @name: Property name to use
319 * @str: String value
320 * Return: 0 if OK, -EFAULT if something went horribly wrong
321 */
Simon Glassf78388b2023-10-01 19:13:28 -0600322static int write_dt_string(struct abuf *buf, const char *name, const char *str)
323{
324 int ret, i;
325
Simon Glassf78388b2023-10-01 19:13:28 -0600326 ret = -EAGAIN;
327 for (i = 0; ret && i < 2; i++) {
328 ret = fdt_property_string(abuf_data(buf), name, str);
329 if (!i) {
330 ret = check_space(ret, buf);
331 if (ret)
332 return log_msg_ret("rs2", -ENOMEM);
333 }
334 }
335
336 /* this should not happen */
337 if (ret)
338 return log_msg_ret("str", -EFAULT);
339
340 return 0;
341}
342
Simon Glass6f3e87a2024-10-14 16:32:00 -0600343/**
344 * write_dt_u32() - Write an int to the devicetree, expanding if needed
345 *
346 * If this fails, it tries again after expanding the devicetree a little
347 *
348 * @buf: Buffer containing the devicetree
349 * @name: Property name to use
350 * @lva: Integer value
351 * Return: 0 if OK, -EFAULT if something went horribly wrong
352 */
353static int write_dt_u32(struct abuf *buf, const char *name, uint val)
354{
355 int ret, i;
356
357 /* write the text of the current item */
358 ret = -EAGAIN;
359 for (i = 0; ret && i < 2; i++) {
360 ret = fdt_property_u32(abuf_data(buf), name, val);
361 if (!i) {
362 ret = check_space(ret, buf);
363 if (ret)
364 return log_msg_ret("rs2", -ENOMEM);
365 }
366 }
367
368 /* this should not happen */
369 if (ret)
370 return log_msg_ret("str", -EFAULT);
371
372 return 0;
373}
374
Simon Glass28bf4352023-08-14 16:40:33 -0600375static int h_write_settings(struct scene_obj *obj, void *vpriv)
376{
377 struct cedit_iter_priv *priv = vpriv;
378 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600379 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600380
381 switch (obj->type) {
382 case SCENEOBJT_NONE:
383 case SCENEOBJT_IMAGE:
384 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600385 case SCENEOBJT_BOX:
Simon Glass28bf4352023-08-14 16:40:33 -0600386 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600387 case SCENEOBJT_TEXTLINE: {
388 const struct scene_obj_textline *tline;
389
390 tline = (struct scene_obj_textline *)obj;
391 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
392 if (ret)
393 return log_msg_ret("wr2", ret);
394 break;
395 }
Simon Glass28bf4352023-08-14 16:40:33 -0600396 case SCENEOBJT_MENU: {
397 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600398 const char *str;
399 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600400 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600401
Simon Glassf78388b2023-10-01 19:13:28 -0600402 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600403 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600404 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600405 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600406 return log_msg_ret("wrt", ret);
407
408 snprintf(name, sizeof(name), "%s-value", obj->name);
409 ret = get_cur_menuitem_val(menu, &val);
410 if (ret < 0)
411 return log_msg_ret("cur", ret);
412 ret = write_dt_u32(buf, name, val);
413 if (ret)
414 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600415
Simon Glass237f3752023-08-14 16:40:35 -0600416 ret = get_cur_menuitem_text(menu, &str);
417 if (ret)
418 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600419
Simon Glassf78388b2023-10-01 19:13:28 -0600420 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600421 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600422 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600423 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600424 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600425
426 break;
427 }
428 }
429
430 return 0;
431}
432
433int cedit_write_settings(struct expo *exp, struct abuf *buf)
434{
435 struct cedit_iter_priv priv;
436 void *fdt;
437 int ret;
438
Simon Glass6651e942025-05-01 07:37:01 -0600439 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600440 return log_msg_ret("buf", -ENOMEM);
441
442 fdt = abuf_data(buf);
443 ret = fdt_create(fdt, abuf_size(buf));
444 if (!ret)
445 ret = fdt_finish_reservemap(fdt);
446 if (!ret)
447 ret = fdt_begin_node(fdt, "");
448 if (!ret)
449 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
450 if (ret) {
451 log_debug("Failed to start FDT (err=%d)\n", ret);
452 return log_msg_ret("sta", -EINVAL);
453 }
454
455 /* write out the items */
456 priv.buf = buf;
457 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
458 if (ret) {
459 log_debug("Failed to write settings (err=%d)\n", ret);
460 return log_msg_ret("set", ret);
461 }
462
463 ret = fdt_end_node(fdt);
464 if (!ret)
465 ret = fdt_end_node(fdt);
466 if (!ret)
467 ret = fdt_finish(fdt);
468 if (ret) {
469 log_debug("Failed to finish FDT (err=%d)\n", ret);
470 return log_msg_ret("fin", -EINVAL);
471 }
472
473 return 0;
474}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600475
476static int h_read_settings(struct scene_obj *obj, void *vpriv)
477{
478 struct cedit_iter_priv *priv = vpriv;
479 ofnode node = priv->node;
480
481 switch (obj->type) {
482 case SCENEOBJT_NONE:
483 case SCENEOBJT_IMAGE:
484 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600485 case SCENEOBJT_BOX:
Simon Glassb1cd32b2023-08-14 16:40:34 -0600486 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600487 case SCENEOBJT_TEXTLINE: {
488 const struct scene_obj_textline *tline;
489 const char *val;
490 int len;
491
492 tline = (struct scene_obj_textline *)obj;
493
494 val = ofnode_read_prop(node, obj->name, &len);
495 if (len >= tline->max_chars)
496 return log_msg_ret("str", -ENOSPC);
497 strcpy(abuf_data(&tline->buf), val);
498 break;
499 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600500 case SCENEOBJT_MENU: {
501 struct scene_obj_menu *menu;
502 uint val;
503
504 if (ofnode_read_u32(node, obj->name, &val))
505 return log_msg_ret("rd", -ENOENT);
506 menu = (struct scene_obj_menu *)obj;
507 menu->cur_item_id = val;
508
509 break;
510 }
511 }
512
513 return 0;
514}
515
516int cedit_read_settings(struct expo *exp, oftree tree)
517{
518 struct cedit_iter_priv priv;
519 ofnode root, node;
520 int ret;
521
522 root = oftree_root(tree);
523 if (!ofnode_valid(root))
524 return log_msg_ret("roo", -ENOENT);
525 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
526 if (!ofnode_valid(node))
527 return log_msg_ret("pat", -ENOENT);
528
529 /* read in the items */
530 priv.node = node;
531 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
532 if (ret) {
533 log_debug("Failed to read settings (err=%d)\n", ret);
534 return log_msg_ret("set", ret);
535 }
536
537 return 0;
538}
Simon Glass237f3752023-08-14 16:40:35 -0600539
540static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
541{
542 const struct scene_obj_menu *menu;
543 struct cedit_iter_priv *priv = vpriv;
544 char name[80], var[60];
545 const char *str;
546 int val, ret;
547
Simon Glass53a0a2f2024-10-14 16:31:57 -0600548 if (obj->id < EXPOID_BASE_ID)
549 return 0;
550
Simon Glass237f3752023-08-14 16:40:35 -0600551 snprintf(var, sizeof(var), "c.%s", obj->name);
552
Simon Glassb7a64532023-10-01 19:13:24 -0600553 switch (obj->type) {
554 case SCENEOBJT_NONE:
555 case SCENEOBJT_IMAGE:
556 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600557 case SCENEOBJT_BOX:
Simon Glassb7a64532023-10-01 19:13:24 -0600558 break;
559 case SCENEOBJT_MENU:
560 menu = (struct scene_obj_menu *)obj;
561 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600562
Simon Glassb7a64532023-10-01 19:13:24 -0600563 if (priv->verbose)
564 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600565
Simon Glassb7a64532023-10-01 19:13:24 -0600566 ret = env_set_ulong(var, val);
567 if (ret)
568 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600569
Simon Glassb7a64532023-10-01 19:13:24 -0600570 ret = get_cur_menuitem_text(menu, &str);
571 if (ret)
572 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600573
Simon Glassb7a64532023-10-01 19:13:24 -0600574 snprintf(name, sizeof(name), "c.%s-str", obj->name);
575 if (priv->verbose)
576 printf("%s=%s\n", name, str);
577
578 ret = env_set(name, str);
579 if (ret)
580 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600581
582 ret = get_cur_menuitem_val(menu, &val);
583 if (ret < 0)
584 return log_msg_ret("cur", ret);
585 snprintf(name, sizeof(name), "c.%s-value", obj->name);
586 if (priv->verbose)
587 printf("%s=%d\n", name, val);
588
Simon Glassb7a64532023-10-01 19:13:24 -0600589 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600590 case SCENEOBJT_TEXTLINE: {
591 const struct scene_obj_textline *tline;
592
593 tline = (struct scene_obj_textline *)obj;
594 str = abuf_data(&tline->buf);
595 ret = env_set(var, str);
596 if (ret)
597 return log_msg_ret("set", ret);
598
599 if (priv->verbose)
600 printf("%s=%s\n", var, str);
601
602 break;
603 }
Simon Glassb7a64532023-10-01 19:13:24 -0600604 }
Simon Glass237f3752023-08-14 16:40:35 -0600605
606 return 0;
607}
608
609int cedit_write_settings_env(struct expo *exp, bool verbose)
610{
611 struct cedit_iter_priv priv;
612 int ret;
613
614 /* write out the items */
615 priv.verbose = verbose;
616 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
617 if (ret) {
618 log_debug("Failed to write settings to env (err=%d)\n", ret);
619 return log_msg_ret("set", ret);
620 }
621
622 return 0;
623}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600624
625static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
626{
627 struct cedit_iter_priv *priv = vpriv;
628 struct scene_obj_menu *menu;
629 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600630 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600631
Simon Glass53a0a2f2024-10-14 16:31:57 -0600632 if (obj->id < EXPOID_BASE_ID)
633 return 0;
634
Simon Glass0f2e5a62023-08-14 16:40:36 -0600635 snprintf(var, sizeof(var), "c.%s", obj->name);
636
Simon Glassb7a64532023-10-01 19:13:24 -0600637 switch (obj->type) {
638 case SCENEOBJT_NONE:
639 case SCENEOBJT_IMAGE:
640 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600641 case SCENEOBJT_BOX:
Simon Glassb7a64532023-10-01 19:13:24 -0600642 break;
643 case SCENEOBJT_MENU:
644 menu = (struct scene_obj_menu *)obj;
645 val = env_get_ulong(var, 10, 0);
646 if (priv->verbose)
647 printf("%s=%d\n", var, val);
648 if (!val)
649 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600650
Simon Glassb7a64532023-10-01 19:13:24 -0600651 /*
652 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600653 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600654 */
655 menu->cur_item_id = val;
656 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600657 case SCENEOBJT_TEXTLINE: {
658 const struct scene_obj_textline *tline;
659 const char *value;
660
661 tline = (struct scene_obj_textline *)obj;
662 value = env_get(var);
663 if (value && strlen(value) >= tline->max_chars)
664 return log_msg_ret("str", -ENOSPC);
665 if (!value)
666 value = "";
667 if (priv->verbose)
668 printf("%s=%s\n", var, value);
669 strcpy(abuf_data(&tline->buf), value);
670 break;
671 }
Simon Glassb7a64532023-10-01 19:13:24 -0600672 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600673
674 return 0;
675}
676
677int cedit_read_settings_env(struct expo *exp, bool verbose)
678{
679 struct cedit_iter_priv priv;
680 int ret;
681
682 /* write out the items */
683 priv.verbose = verbose;
684 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
685 if (ret) {
686 log_debug("Failed to read settings from env (err=%d)\n", ret);
687 return log_msg_ret("set", ret);
688 }
689
690 return 0;
691}
Simon Glass2b91ca62023-08-14 16:40:37 -0600692
Simon Glass2b91ca62023-08-14 16:40:37 -0600693static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
694{
695 const struct scene_obj_menu *menu;
696 struct cedit_iter_priv *priv = vpriv;
697 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600698 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600699
Simon Glass53a0a2f2024-10-14 16:31:57 -0600700 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600701 return 0;
702
703 menu = (struct scene_obj_menu *)obj;
704 val = menu->cur_item_id;
705
Simon Glass6f3e87a2024-10-14 16:32:00 -0600706 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600707 if (ret < 0)
708 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600709 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600710
711 /* figure out where to place this item */
712 if (!obj->bit_length)
713 return log_msg_ret("len", -EINVAL);
714 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
715 return log_msg_ret("bit", -E2BIG);
716
Simon Glass6f3e87a2024-10-14 16:32:00 -0600717 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600718 uint bitnum = obj->start_bit + i;
719
720 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600721 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600722 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
723 log_debug("bit %x %x %x\n", bitnum,
724 priv->mask[CMOS_BYTE(bitnum)],
725 priv->value[CMOS_BYTE(bitnum)]);
726 }
727
728 return 0;
729}
730
731int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
732 bool verbose)
733{
734 struct cedit_iter_priv priv;
735 int ret, i, count, first, last;
736
737 /* write out the items */
738 priv.mask = calloc(1, CMOS_MAX_BYTES);
739 if (!priv.mask)
740 return log_msg_ret("mas", -ENOMEM);
741 priv.value = calloc(1, CMOS_MAX_BYTES);
742 if (!priv.value) {
743 free(priv.mask);
744 return log_msg_ret("val", -ENOMEM);
745 }
746
747 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
748 if (ret) {
749 log_debug("Failed to write CMOS (err=%d)\n", ret);
750 ret = log_msg_ret("set", ret);
751 goto done;
752 }
753
754 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600755 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600756 first = CMOS_MAX_BYTES;
757 last = -1;
758 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
759 if (priv.mask[i]) {
760 log_debug("Write byte %x: %x\n", i, priv.value[i]);
761 ret = rtc_write8(dev, i, priv.value[i]);
762 if (ret) {
763 ret = log_msg_ret("wri", ret);
764 goto done;
765 }
766 count++;
767 first = min(first, i);
768 last = max(last, i);
769 }
770 }
771 if (verbose) {
772 printf("Write %d bytes from offset %x to %x\n", count, first,
773 last);
774 }
775
776done:
777 free(priv.mask);
778 free(priv.value);
779 return ret;
780}
Simon Glass4462fa32023-08-14 16:40:38 -0600781
782static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
783{
784 struct cedit_iter_priv *priv = vpriv;
785 const struct scene_menitem *mi;
786 struct scene_obj_menu *menu;
787 int val, ret;
788 uint i;
789
Simon Glass53a0a2f2024-10-14 16:31:57 -0600790 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600791 return 0;
792
793 menu = (struct scene_obj_menu *)obj;
794
795 /* figure out where to place this item */
796 if (!obj->bit_length)
797 return log_msg_ret("len", -EINVAL);
798 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
799 return log_msg_ret("bit", -E2BIG);
800
801 val = 0;
802 for (i = 0; i < obj->bit_length; i++) {
803 uint bitnum = obj->start_bit + i;
804 uint offset = CMOS_BYTE(bitnum);
805
806 /* read the byte if not already read */
807 if (!priv->mask[offset]) {
808 ret = rtc_read8(priv->dev, offset);
809 if (ret < 0)
810 return log_msg_ret("rea", ret);
811 priv->value[offset] = ret;
812
813 /* mark it as read */
814 priv->mask[offset] = 0xff;
815 }
816
817 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
818 val |= BIT(i);
819 log_debug("bit %x %x\n", bitnum, val);
820 }
821
822 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600823 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600824 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600825 if (!mi)
826 return log_msg_ret("seq", -ENOENT);
827
828 menu->cur_item_id = mi->id;
829 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
830
831 return 0;
832}
833
834int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
835 bool verbose)
836{
837 struct cedit_iter_priv priv;
838 int ret, i, count, first, last;
839
840 /* read in the items */
841 priv.mask = calloc(1, CMOS_MAX_BYTES);
842 if (!priv.mask)
843 return log_msg_ret("mas", -ENOMEM);
844 priv.value = calloc(1, CMOS_MAX_BYTES);
845 if (!priv.value) {
846 free(priv.mask);
847 return log_msg_ret("val", -ENOMEM);
848 }
849 priv.dev = dev;
850
851 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
852 if (ret) {
853 log_debug("Failed to read CMOS (err=%d)\n", ret);
854 ret = log_msg_ret("set", ret);
855 goto done;
856 }
857
Simon Glass330aa1e2024-10-14 16:31:59 -0600858 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600859 first = CMOS_MAX_BYTES;
860 last = -1;
861 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
862 if (priv.mask[i]) {
863 log_debug("Read byte %x: %x\n", i, priv.value[i]);
864 count++;
865 first = min(first, i);
866 last = max(last, i);
867 }
868 }
869 if (verbose) {
870 printf("Read %d bytes from offset %x to %x\n", count, first,
871 last);
872 }
873
874done:
875 free(priv.mask);
876 free(priv.value);
877 return ret;
878}