blob: 54810257fb9a706f5ab509430853b766b81e7fa5 [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;
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 Glass6a5af5f2023-08-14 16:40:27 -0600145 *scnp = scn;
146
147 return scene_id;
148}
149
Simon Glass14bd4132025-05-02 08:46:21 -0600150int cedit_do_action(struct expo *exp, struct scene *scn,
151 struct video_priv *vid_priv, struct expo_action *act)
152{
Simon Glass1b3388c2025-05-02 08:46:25 -0600153 int ret;
154
Simon Glass14bd4132025-05-02 08:46:21 -0600155 switch (act->type) {
156 case EXPOACT_NONE:
Simon Glass14bd4132025-05-02 08:46:21 -0600157 return -EAGAIN;
Simon Glass1b3388c2025-05-02 08:46:25 -0600158 case EXPOACT_POINT_ITEM:
159 ret = scene_menu_select_item(scn, scn->highlight_id,
160 act->select.id);
161 if (ret)
162 return log_msg_ret("cdp", ret);
163 break;
Simon Glass14bd4132025-05-02 08:46:21 -0600164 case EXPOACT_POINT_OBJ:
165 scene_set_highlight_id(scn, act->select.id);
166 cedit_arange(exp, vid_priv, scn->id);
167 break;
168 case EXPOACT_OPEN:
169 scene_set_open(scn, act->select.id, true);
170 cedit_arange(exp, vid_priv, scn->id);
171 switch (scn->highlight_id) {
172 case EXPOID_SAVE:
173 exp->done = true;
174 exp->save = true;
175 break;
176 case EXPOID_DISCARD:
177 exp->done = true;
178 break;
179 }
180 break;
181 case EXPOACT_CLOSE:
182 scene_set_open(scn, act->select.id, false);
183 cedit_arange(exp, vid_priv, scn->id);
184 break;
185 case EXPOACT_SELECT:
186 scene_set_open(scn, scn->highlight_id, false);
187 cedit_arange(exp, vid_priv, scn->id);
188 break;
189 case EXPOACT_QUIT:
190 log_debug("quitting\n");
191 exp->done = true;
192 break;
193 }
194
195 return 0;
196}
197
Simon Glass6a5af5f2023-08-14 16:40:27 -0600198int cedit_run(struct expo *exp)
199{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600200 struct video_priv *vid_priv;
Simon Glass736bc0d2025-05-02 08:46:22 -0600201 struct udevice *dev;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600202 struct scene *scn;
Simon Glass736bc0d2025-05-02 08:46:22 -0600203 uint scene_id;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600204 int ret;
205
Simon Glass736bc0d2025-05-02 08:46:22 -0600206 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
207 if (ret)
208 return log_msg_ret("vid", ret);
209 vid_priv = dev_get_uclass_priv(dev);
210
211 ret = cedit_prepare(exp, dev, &scn);
Simon Glass6a5af5f2023-08-14 16:40:27 -0600212 if (ret < 0)
213 return log_msg_ret("prep", ret);
214 scene_id = ret;
215
Simon Glass527d8642025-05-02 08:46:20 -0600216 exp->done = false;
217 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600218 do {
219 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600220
Simon Glass137b4422025-05-02 08:46:16 -0600221 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600222 if (!ret)
223 cedit_do_action(exp, scn, vid_priv, &act);
224 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600225 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600226 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600227
228 if (ret)
229 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600230 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600231 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600232
233 return 0;
234}
Simon Glass28bf4352023-08-14 16:40:33 -0600235
236static int check_space(int ret, struct abuf *buf)
237{
238 if (ret == -FDT_ERR_NOSPACE) {
239 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
240 return log_msg_ret("spc", -ENOMEM);
241 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
242 abuf_size(buf));
243 if (ret)
244 return log_msg_ret("res", -EFAULT);
245 }
246
247 return 0;
248}
249
Simon Glassdb6a0512023-10-01 19:13:23 -0600250/**
251 * get_cur_menuitem_text() - Get the text of the currently selected item
252 *
253 * Looks up the object for the current item, finds text object for it and looks
254 * up the string for that text
255 *
256 * @menu: Menu to look at
257 * @strp: Returns a pointer to the next
258 * Return: 0 if OK, -ENOENT if something was not found
259 */
Simon Glass237f3752023-08-14 16:40:35 -0600260static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
261 const char **strp)
262{
263 struct scene *scn = menu->obj.scene;
264 const struct scene_menitem *mi;
265 const struct scene_obj_txt *txt;
266 const char *str;
267
268 mi = scene_menuitem_find(menu, menu->cur_item_id);
269 if (!mi)
270 return log_msg_ret("mi", -ENOENT);
271
272 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
273 if (!txt)
274 return log_msg_ret("txt", -ENOENT);
275
Simon Glass9ef02aa2025-05-02 08:46:37 -0600276 str = expo_get_str(scn->expo, txt->gen.str_id);
Simon Glass237f3752023-08-14 16:40:35 -0600277 if (!str)
278 return log_msg_ret("str", -ENOENT);
279 *strp = str;
280
281 return 0;
282}
283
Simon Glass6f3e87a2024-10-14 16:32:00 -0600284/**
285 * get_cur_menuitem_val() - Get the value of a menu's current item
286 *
287 * Obtains the value of the current item in the menu. If no value, then
288 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
289 * the currently selected item. If the first item is selected, this returns 0;
290 * if the second, 1; etc.
291 *
292 * @menu: Menu to check
293 * @valp: Returns current-item value / sequence number
294 * Return: 0 on success, else -ve error value
295 */
296static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
297{
298 const struct scene_menitem *mi;
299 int seq;
300
301 seq = 0;
302 list_for_each_entry(mi, &menu->item_head, sibling) {
303 if (mi->id == menu->cur_item_id) {
304 *valp = mi->value == INT_MAX ? seq : mi->value;
305 return 0;
306 }
307 seq++;
308 }
309
310 return log_msg_ret("nf", -ENOENT);
311}
312
313/**
314 * write_dt_string() - Write a string to the devicetree, expanding if needed
315 *
316 * If this fails, it tries again after expanding the devicetree a little
317 *
318 * @buf: Buffer containing the devicetree
319 * @name: Property name to use
320 * @str: String value
321 * Return: 0 if OK, -EFAULT if something went horribly wrong
322 */
Simon Glassf78388b2023-10-01 19:13:28 -0600323static int write_dt_string(struct abuf *buf, const char *name, const char *str)
324{
325 int ret, i;
326
Simon Glassf78388b2023-10-01 19:13:28 -0600327 ret = -EAGAIN;
328 for (i = 0; ret && i < 2; i++) {
329 ret = fdt_property_string(abuf_data(buf), name, str);
330 if (!i) {
331 ret = check_space(ret, buf);
332 if (ret)
333 return log_msg_ret("rs2", -ENOMEM);
334 }
335 }
336
337 /* this should not happen */
338 if (ret)
339 return log_msg_ret("str", -EFAULT);
340
341 return 0;
342}
343
Simon Glass6f3e87a2024-10-14 16:32:00 -0600344/**
345 * write_dt_u32() - Write an int to the devicetree, expanding if needed
346 *
347 * If this fails, it tries again after expanding the devicetree a little
348 *
349 * @buf: Buffer containing the devicetree
350 * @name: Property name to use
351 * @lva: Integer value
352 * Return: 0 if OK, -EFAULT if something went horribly wrong
353 */
354static int write_dt_u32(struct abuf *buf, const char *name, uint val)
355{
356 int ret, i;
357
358 /* write the text of the current item */
359 ret = -EAGAIN;
360 for (i = 0; ret && i < 2; i++) {
361 ret = fdt_property_u32(abuf_data(buf), name, val);
362 if (!i) {
363 ret = check_space(ret, buf);
364 if (ret)
365 return log_msg_ret("rs2", -ENOMEM);
366 }
367 }
368
369 /* this should not happen */
370 if (ret)
371 return log_msg_ret("str", -EFAULT);
372
373 return 0;
374}
375
Simon Glass28bf4352023-08-14 16:40:33 -0600376static int h_write_settings(struct scene_obj *obj, void *vpriv)
377{
378 struct cedit_iter_priv *priv = vpriv;
379 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600380 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600381
382 switch (obj->type) {
383 case SCENEOBJT_NONE:
384 case SCENEOBJT_IMAGE:
385 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600386 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600387 case SCENEOBJT_TEXTEDIT:
Simon Glass28bf4352023-08-14 16:40:33 -0600388 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600389 case SCENEOBJT_TEXTLINE: {
390 const struct scene_obj_textline *tline;
391
392 tline = (struct scene_obj_textline *)obj;
393 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
394 if (ret)
395 return log_msg_ret("wr2", ret);
396 break;
397 }
Simon Glass28bf4352023-08-14 16:40:33 -0600398 case SCENEOBJT_MENU: {
399 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600400 const char *str;
401 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600402 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600403
Simon Glassf78388b2023-10-01 19:13:28 -0600404 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600405 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600406 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600407 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600408 return log_msg_ret("wrt", ret);
409
410 snprintf(name, sizeof(name), "%s-value", obj->name);
411 ret = get_cur_menuitem_val(menu, &val);
412 if (ret < 0)
413 return log_msg_ret("cur", ret);
414 ret = write_dt_u32(buf, name, val);
415 if (ret)
416 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600417
Simon Glass237f3752023-08-14 16:40:35 -0600418 ret = get_cur_menuitem_text(menu, &str);
419 if (ret)
420 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600421
Simon Glassf78388b2023-10-01 19:13:28 -0600422 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600423 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600424 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600425 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600426 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600427
428 break;
429 }
430 }
431
432 return 0;
433}
434
435int cedit_write_settings(struct expo *exp, struct abuf *buf)
436{
437 struct cedit_iter_priv priv;
438 void *fdt;
439 int ret;
440
Simon Glass6651e942025-05-01 07:37:01 -0600441 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600442 return log_msg_ret("buf", -ENOMEM);
443
444 fdt = abuf_data(buf);
445 ret = fdt_create(fdt, abuf_size(buf));
446 if (!ret)
447 ret = fdt_finish_reservemap(fdt);
448 if (!ret)
449 ret = fdt_begin_node(fdt, "");
450 if (!ret)
451 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
452 if (ret) {
453 log_debug("Failed to start FDT (err=%d)\n", ret);
454 return log_msg_ret("sta", -EINVAL);
455 }
456
457 /* write out the items */
458 priv.buf = buf;
459 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
460 if (ret) {
461 log_debug("Failed to write settings (err=%d)\n", ret);
462 return log_msg_ret("set", ret);
463 }
464
465 ret = fdt_end_node(fdt);
466 if (!ret)
467 ret = fdt_end_node(fdt);
468 if (!ret)
469 ret = fdt_finish(fdt);
470 if (ret) {
471 log_debug("Failed to finish FDT (err=%d)\n", ret);
472 return log_msg_ret("fin", -EINVAL);
473 }
474
475 return 0;
476}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600477
478static int h_read_settings(struct scene_obj *obj, void *vpriv)
479{
480 struct cedit_iter_priv *priv = vpriv;
481 ofnode node = priv->node;
482
483 switch (obj->type) {
484 case SCENEOBJT_NONE:
485 case SCENEOBJT_IMAGE:
486 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600487 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600488 case SCENEOBJT_TEXTEDIT:
Simon Glassb1cd32b2023-08-14 16:40:34 -0600489 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600490 case SCENEOBJT_TEXTLINE: {
491 const struct scene_obj_textline *tline;
492 const char *val;
493 int len;
494
495 tline = (struct scene_obj_textline *)obj;
496
497 val = ofnode_read_prop(node, obj->name, &len);
498 if (len >= tline->max_chars)
499 return log_msg_ret("str", -ENOSPC);
500 strcpy(abuf_data(&tline->buf), val);
501 break;
502 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600503 case SCENEOBJT_MENU: {
504 struct scene_obj_menu *menu;
505 uint val;
506
507 if (ofnode_read_u32(node, obj->name, &val))
508 return log_msg_ret("rd", -ENOENT);
509 menu = (struct scene_obj_menu *)obj;
510 menu->cur_item_id = val;
511
512 break;
513 }
514 }
515
516 return 0;
517}
518
519int cedit_read_settings(struct expo *exp, oftree tree)
520{
521 struct cedit_iter_priv priv;
522 ofnode root, node;
523 int ret;
524
525 root = oftree_root(tree);
526 if (!ofnode_valid(root))
527 return log_msg_ret("roo", -ENOENT);
528 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
529 if (!ofnode_valid(node))
530 return log_msg_ret("pat", -ENOENT);
531
532 /* read in the items */
533 priv.node = node;
534 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
535 if (ret) {
536 log_debug("Failed to read settings (err=%d)\n", ret);
537 return log_msg_ret("set", ret);
538 }
539
540 return 0;
541}
Simon Glass237f3752023-08-14 16:40:35 -0600542
543static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
544{
545 const struct scene_obj_menu *menu;
546 struct cedit_iter_priv *priv = vpriv;
547 char name[80], var[60];
548 const char *str;
549 int val, ret;
550
Simon Glass53a0a2f2024-10-14 16:31:57 -0600551 if (obj->id < EXPOID_BASE_ID)
552 return 0;
553
Simon Glass237f3752023-08-14 16:40:35 -0600554 snprintf(var, sizeof(var), "c.%s", obj->name);
555
Simon Glassb7a64532023-10-01 19:13:24 -0600556 switch (obj->type) {
557 case SCENEOBJT_NONE:
558 case SCENEOBJT_IMAGE:
559 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600560 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600561 case SCENEOBJT_TEXTEDIT:
Simon Glassb7a64532023-10-01 19:13:24 -0600562 break;
563 case SCENEOBJT_MENU:
564 menu = (struct scene_obj_menu *)obj;
565 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600566
Simon Glassb7a64532023-10-01 19:13:24 -0600567 if (priv->verbose)
568 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600569
Simon Glassb7a64532023-10-01 19:13:24 -0600570 ret = env_set_ulong(var, val);
571 if (ret)
572 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600573
Simon Glassb7a64532023-10-01 19:13:24 -0600574 ret = get_cur_menuitem_text(menu, &str);
575 if (ret)
576 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600577
Simon Glassb7a64532023-10-01 19:13:24 -0600578 snprintf(name, sizeof(name), "c.%s-str", obj->name);
579 if (priv->verbose)
580 printf("%s=%s\n", name, str);
581
582 ret = env_set(name, str);
583 if (ret)
584 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600585
586 ret = get_cur_menuitem_val(menu, &val);
587 if (ret < 0)
588 return log_msg_ret("cur", ret);
589 snprintf(name, sizeof(name), "c.%s-value", obj->name);
590 if (priv->verbose)
591 printf("%s=%d\n", name, val);
592
Simon Glassb7a64532023-10-01 19:13:24 -0600593 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600594 case SCENEOBJT_TEXTLINE: {
595 const struct scene_obj_textline *tline;
596
597 tline = (struct scene_obj_textline *)obj;
598 str = abuf_data(&tline->buf);
599 ret = env_set(var, str);
600 if (ret)
601 return log_msg_ret("set", ret);
602
603 if (priv->verbose)
604 printf("%s=%s\n", var, str);
605
606 break;
607 }
Simon Glassb7a64532023-10-01 19:13:24 -0600608 }
Simon Glass237f3752023-08-14 16:40:35 -0600609
610 return 0;
611}
612
613int cedit_write_settings_env(struct expo *exp, bool verbose)
614{
615 struct cedit_iter_priv priv;
616 int ret;
617
618 /* write out the items */
619 priv.verbose = verbose;
620 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
621 if (ret) {
622 log_debug("Failed to write settings to env (err=%d)\n", ret);
623 return log_msg_ret("set", ret);
624 }
625
626 return 0;
627}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600628
629static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
630{
631 struct cedit_iter_priv *priv = vpriv;
632 struct scene_obj_menu *menu;
633 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600634 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600635
Simon Glass53a0a2f2024-10-14 16:31:57 -0600636 if (obj->id < EXPOID_BASE_ID)
637 return 0;
638
Simon Glass0f2e5a62023-08-14 16:40:36 -0600639 snprintf(var, sizeof(var), "c.%s", obj->name);
640
Simon Glassb7a64532023-10-01 19:13:24 -0600641 switch (obj->type) {
642 case SCENEOBJT_NONE:
643 case SCENEOBJT_IMAGE:
644 case SCENEOBJT_TEXT:
Simon Glass138a3972025-05-02 08:46:44 -0600645 case SCENEOBJT_BOX:
Simon Glass5dc887d2025-05-02 08:46:46 -0600646 case SCENEOBJT_TEXTEDIT:
Simon Glassb7a64532023-10-01 19:13:24 -0600647 break;
648 case SCENEOBJT_MENU:
649 menu = (struct scene_obj_menu *)obj;
650 val = env_get_ulong(var, 10, 0);
651 if (priv->verbose)
652 printf("%s=%d\n", var, val);
653 if (!val)
654 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600655
Simon Glassb7a64532023-10-01 19:13:24 -0600656 /*
657 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600658 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600659 */
660 menu->cur_item_id = val;
661 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600662 case SCENEOBJT_TEXTLINE: {
663 const struct scene_obj_textline *tline;
664 const char *value;
665
666 tline = (struct scene_obj_textline *)obj;
667 value = env_get(var);
668 if (value && strlen(value) >= tline->max_chars)
669 return log_msg_ret("str", -ENOSPC);
670 if (!value)
671 value = "";
672 if (priv->verbose)
673 printf("%s=%s\n", var, value);
674 strcpy(abuf_data(&tline->buf), value);
675 break;
676 }
Simon Glassb7a64532023-10-01 19:13:24 -0600677 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600678
679 return 0;
680}
681
682int cedit_read_settings_env(struct expo *exp, bool verbose)
683{
684 struct cedit_iter_priv priv;
685 int ret;
686
687 /* write out the items */
688 priv.verbose = verbose;
689 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
690 if (ret) {
691 log_debug("Failed to read settings from env (err=%d)\n", ret);
692 return log_msg_ret("set", ret);
693 }
694
695 return 0;
696}
Simon Glass2b91ca62023-08-14 16:40:37 -0600697
Simon Glass2b91ca62023-08-14 16:40:37 -0600698static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
699{
700 const struct scene_obj_menu *menu;
701 struct cedit_iter_priv *priv = vpriv;
702 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600703 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600704
Simon Glass53a0a2f2024-10-14 16:31:57 -0600705 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600706 return 0;
707
708 menu = (struct scene_obj_menu *)obj;
709 val = menu->cur_item_id;
710
Simon Glass6f3e87a2024-10-14 16:32:00 -0600711 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600712 if (ret < 0)
713 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600714 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600715
716 /* figure out where to place this item */
717 if (!obj->bit_length)
718 return log_msg_ret("len", -EINVAL);
719 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
720 return log_msg_ret("bit", -E2BIG);
721
Simon Glass6f3e87a2024-10-14 16:32:00 -0600722 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600723 uint bitnum = obj->start_bit + i;
724
725 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600726 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600727 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
728 log_debug("bit %x %x %x\n", bitnum,
729 priv->mask[CMOS_BYTE(bitnum)],
730 priv->value[CMOS_BYTE(bitnum)]);
731 }
732
733 return 0;
734}
735
736int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
737 bool verbose)
738{
739 struct cedit_iter_priv priv;
740 int ret, i, count, first, last;
741
742 /* write out the items */
743 priv.mask = calloc(1, CMOS_MAX_BYTES);
744 if (!priv.mask)
745 return log_msg_ret("mas", -ENOMEM);
746 priv.value = calloc(1, CMOS_MAX_BYTES);
747 if (!priv.value) {
748 free(priv.mask);
749 return log_msg_ret("val", -ENOMEM);
750 }
751
752 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
753 if (ret) {
754 log_debug("Failed to write CMOS (err=%d)\n", ret);
755 ret = log_msg_ret("set", ret);
756 goto done;
757 }
758
759 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600760 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600761 first = CMOS_MAX_BYTES;
762 last = -1;
763 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
764 if (priv.mask[i]) {
765 log_debug("Write byte %x: %x\n", i, priv.value[i]);
766 ret = rtc_write8(dev, i, priv.value[i]);
767 if (ret) {
768 ret = log_msg_ret("wri", ret);
769 goto done;
770 }
771 count++;
772 first = min(first, i);
773 last = max(last, i);
774 }
775 }
776 if (verbose) {
777 printf("Write %d bytes from offset %x to %x\n", count, first,
778 last);
779 }
780
781done:
782 free(priv.mask);
783 free(priv.value);
784 return ret;
785}
Simon Glass4462fa32023-08-14 16:40:38 -0600786
787static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
788{
789 struct cedit_iter_priv *priv = vpriv;
790 const struct scene_menitem *mi;
791 struct scene_obj_menu *menu;
792 int val, ret;
793 uint i;
794
Simon Glass53a0a2f2024-10-14 16:31:57 -0600795 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600796 return 0;
797
798 menu = (struct scene_obj_menu *)obj;
799
800 /* figure out where to place this item */
801 if (!obj->bit_length)
802 return log_msg_ret("len", -EINVAL);
803 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
804 return log_msg_ret("bit", -E2BIG);
805
806 val = 0;
807 for (i = 0; i < obj->bit_length; i++) {
808 uint bitnum = obj->start_bit + i;
809 uint offset = CMOS_BYTE(bitnum);
810
811 /* read the byte if not already read */
812 if (!priv->mask[offset]) {
813 ret = rtc_read8(priv->dev, offset);
814 if (ret < 0)
815 return log_msg_ret("rea", ret);
816 priv->value[offset] = ret;
817
818 /* mark it as read */
819 priv->mask[offset] = 0xff;
820 }
821
822 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
823 val |= BIT(i);
824 log_debug("bit %x %x\n", bitnum, val);
825 }
826
827 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600828 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600829 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600830 if (!mi)
831 return log_msg_ret("seq", -ENOENT);
832
833 menu->cur_item_id = mi->id;
834 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
835
836 return 0;
837}
838
839int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
840 bool verbose)
841{
842 struct cedit_iter_priv priv;
843 int ret, i, count, first, last;
844
845 /* read in the items */
846 priv.mask = calloc(1, CMOS_MAX_BYTES);
847 if (!priv.mask)
848 return log_msg_ret("mas", -ENOMEM);
849 priv.value = calloc(1, CMOS_MAX_BYTES);
850 if (!priv.value) {
851 free(priv.mask);
852 return log_msg_ret("val", -ENOMEM);
853 }
854 priv.dev = dev;
855
856 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
857 if (ret) {
858 log_debug("Failed to read CMOS (err=%d)\n", ret);
859 ret = log_msg_ret("set", ret);
860 goto done;
861 }
862
Simon Glass330aa1e2024-10-14 16:31:59 -0600863 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600864 first = CMOS_MAX_BYTES;
865 last = -1;
866 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
867 if (priv.mask[i]) {
868 log_debug("Read byte %x: %x\n", i, priv.value[i]);
869 count++;
870 first = min(first, i);
871 last = max(last, i);
872 }
873 }
874 if (verbose) {
875 printf("Read %d bytes from offset %x to %x\n", count, first,
876 last);
877 }
878
879done:
880 free(priv.mask);
881 free(priv.value);
882 return ret;
883}