blob: 792ab6d65bd02ae421f63e0904c5d6e2aebe76eb [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{
Simon Glass1b3388c2025-05-02 08:46:25 -0600151 int ret;
152
Simon Glass14bd4132025-05-02 08:46:21 -0600153 switch (act->type) {
154 case EXPOACT_NONE:
Simon Glass14bd4132025-05-02 08:46:21 -0600155 return -EAGAIN;
Simon Glass1b3388c2025-05-02 08:46:25 -0600156 case EXPOACT_POINT_ITEM:
157 ret = scene_menu_select_item(scn, scn->highlight_id,
158 act->select.id);
159 if (ret)
160 return log_msg_ret("cdp", ret);
161 break;
Simon Glass14bd4132025-05-02 08:46:21 -0600162 case EXPOACT_POINT_OBJ:
163 scene_set_highlight_id(scn, act->select.id);
164 cedit_arange(exp, vid_priv, scn->id);
165 break;
166 case EXPOACT_OPEN:
167 scene_set_open(scn, act->select.id, true);
168 cedit_arange(exp, vid_priv, scn->id);
169 switch (scn->highlight_id) {
170 case EXPOID_SAVE:
171 exp->done = true;
172 exp->save = true;
173 break;
174 case EXPOID_DISCARD:
175 exp->done = true;
176 break;
177 }
178 break;
179 case EXPOACT_CLOSE:
180 scene_set_open(scn, act->select.id, false);
181 cedit_arange(exp, vid_priv, scn->id);
182 break;
183 case EXPOACT_SELECT:
184 scene_set_open(scn, scn->highlight_id, false);
185 cedit_arange(exp, vid_priv, scn->id);
186 break;
187 case EXPOACT_QUIT:
188 log_debug("quitting\n");
189 exp->done = true;
190 break;
191 }
192
193 return 0;
194}
195
Simon Glass6a5af5f2023-08-14 16:40:27 -0600196int cedit_run(struct expo *exp)
197{
Simon Glass6a5af5f2023-08-14 16:40:27 -0600198 struct video_priv *vid_priv;
Simon Glass736bc0d2025-05-02 08:46:22 -0600199 struct udevice *dev;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600200 struct scene *scn;
Simon Glass736bc0d2025-05-02 08:46:22 -0600201 uint scene_id;
Simon Glass6a5af5f2023-08-14 16:40:27 -0600202 int ret;
203
Simon Glass736bc0d2025-05-02 08:46:22 -0600204 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
205 if (ret)
206 return log_msg_ret("vid", ret);
207 vid_priv = dev_get_uclass_priv(dev);
208
209 ret = cedit_prepare(exp, dev, &scn);
Simon Glass6a5af5f2023-08-14 16:40:27 -0600210 if (ret < 0)
211 return log_msg_ret("prep", ret);
212 scene_id = ret;
213
Simon Glass527d8642025-05-02 08:46:20 -0600214 exp->done = false;
215 exp->save = false;
Simon Glassc8925112023-06-01 10:23:02 -0600216 do {
217 struct expo_action act;
Simon Glassc8925112023-06-01 10:23:02 -0600218
Simon Glass137b4422025-05-02 08:46:16 -0600219 ret = expo_poll(exp, &act);
Simon Glass14bd4132025-05-02 08:46:21 -0600220 if (!ret)
221 cedit_do_action(exp, scn, vid_priv, &act);
222 else if (ret != -EAGAIN)
Simon Glass137b4422025-05-02 08:46:16 -0600223 return log_msg_ret("cep", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600224 } while (!exp->done);
Simon Glassc8925112023-06-01 10:23:02 -0600225
226 if (ret)
227 return log_msg_ret("end", ret);
Simon Glass527d8642025-05-02 08:46:20 -0600228 if (!exp->save)
Simon Glass53a0a2f2024-10-14 16:31:57 -0600229 return -EACCES;
Simon Glassc8925112023-06-01 10:23:02 -0600230
231 return 0;
232}
Simon Glass28bf4352023-08-14 16:40:33 -0600233
234static int check_space(int ret, struct abuf *buf)
235{
236 if (ret == -FDT_ERR_NOSPACE) {
237 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
238 return log_msg_ret("spc", -ENOMEM);
239 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
240 abuf_size(buf));
241 if (ret)
242 return log_msg_ret("res", -EFAULT);
243 }
244
245 return 0;
246}
247
Simon Glassdb6a0512023-10-01 19:13:23 -0600248/**
249 * get_cur_menuitem_text() - Get the text of the currently selected item
250 *
251 * Looks up the object for the current item, finds text object for it and looks
252 * up the string for that text
253 *
254 * @menu: Menu to look at
255 * @strp: Returns a pointer to the next
256 * Return: 0 if OK, -ENOENT if something was not found
257 */
Simon Glass237f3752023-08-14 16:40:35 -0600258static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
259 const char **strp)
260{
261 struct scene *scn = menu->obj.scene;
262 const struct scene_menitem *mi;
263 const struct scene_obj_txt *txt;
264 const char *str;
265
266 mi = scene_menuitem_find(menu, menu->cur_item_id);
267 if (!mi)
268 return log_msg_ret("mi", -ENOENT);
269
270 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
271 if (!txt)
272 return log_msg_ret("txt", -ENOENT);
273
274 str = expo_get_str(scn->expo, txt->str_id);
275 if (!str)
276 return log_msg_ret("str", -ENOENT);
277 *strp = str;
278
279 return 0;
280}
281
Simon Glass6f3e87a2024-10-14 16:32:00 -0600282/**
283 * get_cur_menuitem_val() - Get the value of a menu's current item
284 *
285 * Obtains the value of the current item in the menu. If no value, then
286 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
287 * the currently selected item. If the first item is selected, this returns 0;
288 * if the second, 1; etc.
289 *
290 * @menu: Menu to check
291 * @valp: Returns current-item value / sequence number
292 * Return: 0 on success, else -ve error value
293 */
294static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
295{
296 const struct scene_menitem *mi;
297 int seq;
298
299 seq = 0;
300 list_for_each_entry(mi, &menu->item_head, sibling) {
301 if (mi->id == menu->cur_item_id) {
302 *valp = mi->value == INT_MAX ? seq : mi->value;
303 return 0;
304 }
305 seq++;
306 }
307
308 return log_msg_ret("nf", -ENOENT);
309}
310
311/**
312 * write_dt_string() - Write a string to the devicetree, expanding if needed
313 *
314 * If this fails, it tries again after expanding the devicetree a little
315 *
316 * @buf: Buffer containing the devicetree
317 * @name: Property name to use
318 * @str: String value
319 * Return: 0 if OK, -EFAULT if something went horribly wrong
320 */
Simon Glassf78388b2023-10-01 19:13:28 -0600321static int write_dt_string(struct abuf *buf, const char *name, const char *str)
322{
323 int ret, i;
324
Simon Glassf78388b2023-10-01 19:13:28 -0600325 ret = -EAGAIN;
326 for (i = 0; ret && i < 2; i++) {
327 ret = fdt_property_string(abuf_data(buf), name, str);
328 if (!i) {
329 ret = check_space(ret, buf);
330 if (ret)
331 return log_msg_ret("rs2", -ENOMEM);
332 }
333 }
334
335 /* this should not happen */
336 if (ret)
337 return log_msg_ret("str", -EFAULT);
338
339 return 0;
340}
341
Simon Glass6f3e87a2024-10-14 16:32:00 -0600342/**
343 * write_dt_u32() - Write an int to the devicetree, expanding if needed
344 *
345 * If this fails, it tries again after expanding the devicetree a little
346 *
347 * @buf: Buffer containing the devicetree
348 * @name: Property name to use
349 * @lva: Integer value
350 * Return: 0 if OK, -EFAULT if something went horribly wrong
351 */
352static int write_dt_u32(struct abuf *buf, const char *name, uint val)
353{
354 int ret, i;
355
356 /* write the text of the current item */
357 ret = -EAGAIN;
358 for (i = 0; ret && i < 2; i++) {
359 ret = fdt_property_u32(abuf_data(buf), name, val);
360 if (!i) {
361 ret = check_space(ret, buf);
362 if (ret)
363 return log_msg_ret("rs2", -ENOMEM);
364 }
365 }
366
367 /* this should not happen */
368 if (ret)
369 return log_msg_ret("str", -EFAULT);
370
371 return 0;
372}
373
Simon Glass28bf4352023-08-14 16:40:33 -0600374static int h_write_settings(struct scene_obj *obj, void *vpriv)
375{
376 struct cedit_iter_priv *priv = vpriv;
377 struct abuf *buf = priv->buf;
Simon Glass23c3eb42023-10-01 19:13:37 -0600378 int ret;
Simon Glass28bf4352023-08-14 16:40:33 -0600379
380 switch (obj->type) {
381 case SCENEOBJT_NONE:
382 case SCENEOBJT_IMAGE:
383 case SCENEOBJT_TEXT:
384 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600385 case SCENEOBJT_TEXTLINE: {
386 const struct scene_obj_textline *tline;
387
388 tline = (struct scene_obj_textline *)obj;
389 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
390 if (ret)
391 return log_msg_ret("wr2", ret);
392 break;
393 }
Simon Glass28bf4352023-08-14 16:40:33 -0600394 case SCENEOBJT_MENU: {
395 const struct scene_obj_menu *menu;
Simon Glass28bf4352023-08-14 16:40:33 -0600396 const char *str;
397 char name[80];
Simon Glass6f3e87a2024-10-14 16:32:00 -0600398 int val;
Simon Glass28bf4352023-08-14 16:40:33 -0600399
Simon Glassf78388b2023-10-01 19:13:28 -0600400 /* write the ID of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600401 menu = (struct scene_obj_menu *)obj;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600402 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
Simon Glass28bf4352023-08-14 16:40:33 -0600403 if (ret)
Simon Glass6f3e87a2024-10-14 16:32:00 -0600404 return log_msg_ret("wrt", ret);
405
406 snprintf(name, sizeof(name), "%s-value", obj->name);
407 ret = get_cur_menuitem_val(menu, &val);
408 if (ret < 0)
409 return log_msg_ret("cur", ret);
410 ret = write_dt_u32(buf, name, val);
411 if (ret)
412 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600413
Simon Glass237f3752023-08-14 16:40:35 -0600414 ret = get_cur_menuitem_text(menu, &str);
415 if (ret)
416 return log_msg_ret("mis", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600417
Simon Glassf78388b2023-10-01 19:13:28 -0600418 /* write the text of the current item */
Simon Glass28bf4352023-08-14 16:40:33 -0600419 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glassf78388b2023-10-01 19:13:28 -0600420 ret = write_dt_string(buf, name, str);
Simon Glass28bf4352023-08-14 16:40:33 -0600421 if (ret)
Simon Glassf78388b2023-10-01 19:13:28 -0600422 return log_msg_ret("wr2", ret);
Simon Glass28bf4352023-08-14 16:40:33 -0600423
424 break;
425 }
426 }
427
428 return 0;
429}
430
431int cedit_write_settings(struct expo *exp, struct abuf *buf)
432{
433 struct cedit_iter_priv priv;
434 void *fdt;
435 int ret;
436
Simon Glass6651e942025-05-01 07:37:01 -0600437 if (!abuf_init_size(buf, CEDIT_SIZE_INC))
Simon Glass28bf4352023-08-14 16:40:33 -0600438 return log_msg_ret("buf", -ENOMEM);
439
440 fdt = abuf_data(buf);
441 ret = fdt_create(fdt, abuf_size(buf));
442 if (!ret)
443 ret = fdt_finish_reservemap(fdt);
444 if (!ret)
445 ret = fdt_begin_node(fdt, "");
446 if (!ret)
447 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
448 if (ret) {
449 log_debug("Failed to start FDT (err=%d)\n", ret);
450 return log_msg_ret("sta", -EINVAL);
451 }
452
453 /* write out the items */
454 priv.buf = buf;
455 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
456 if (ret) {
457 log_debug("Failed to write settings (err=%d)\n", ret);
458 return log_msg_ret("set", ret);
459 }
460
461 ret = fdt_end_node(fdt);
462 if (!ret)
463 ret = fdt_end_node(fdt);
464 if (!ret)
465 ret = fdt_finish(fdt);
466 if (ret) {
467 log_debug("Failed to finish FDT (err=%d)\n", ret);
468 return log_msg_ret("fin", -EINVAL);
469 }
470
471 return 0;
472}
Simon Glassb1cd32b2023-08-14 16:40:34 -0600473
474static int h_read_settings(struct scene_obj *obj, void *vpriv)
475{
476 struct cedit_iter_priv *priv = vpriv;
477 ofnode node = priv->node;
478
479 switch (obj->type) {
480 case SCENEOBJT_NONE:
481 case SCENEOBJT_IMAGE:
482 case SCENEOBJT_TEXT:
483 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600484 case SCENEOBJT_TEXTLINE: {
485 const struct scene_obj_textline *tline;
486 const char *val;
487 int len;
488
489 tline = (struct scene_obj_textline *)obj;
490
491 val = ofnode_read_prop(node, obj->name, &len);
492 if (len >= tline->max_chars)
493 return log_msg_ret("str", -ENOSPC);
494 strcpy(abuf_data(&tline->buf), val);
495 break;
496 }
Simon Glassb1cd32b2023-08-14 16:40:34 -0600497 case SCENEOBJT_MENU: {
498 struct scene_obj_menu *menu;
499 uint val;
500
501 if (ofnode_read_u32(node, obj->name, &val))
502 return log_msg_ret("rd", -ENOENT);
503 menu = (struct scene_obj_menu *)obj;
504 menu->cur_item_id = val;
505
506 break;
507 }
508 }
509
510 return 0;
511}
512
513int cedit_read_settings(struct expo *exp, oftree tree)
514{
515 struct cedit_iter_priv priv;
516 ofnode root, node;
517 int ret;
518
519 root = oftree_root(tree);
520 if (!ofnode_valid(root))
521 return log_msg_ret("roo", -ENOENT);
522 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
523 if (!ofnode_valid(node))
524 return log_msg_ret("pat", -ENOENT);
525
526 /* read in the items */
527 priv.node = node;
528 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
529 if (ret) {
530 log_debug("Failed to read settings (err=%d)\n", ret);
531 return log_msg_ret("set", ret);
532 }
533
534 return 0;
535}
Simon Glass237f3752023-08-14 16:40:35 -0600536
537static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
538{
539 const struct scene_obj_menu *menu;
540 struct cedit_iter_priv *priv = vpriv;
541 char name[80], var[60];
542 const char *str;
543 int val, ret;
544
Simon Glass53a0a2f2024-10-14 16:31:57 -0600545 if (obj->id < EXPOID_BASE_ID)
546 return 0;
547
Simon Glass237f3752023-08-14 16:40:35 -0600548 snprintf(var, sizeof(var), "c.%s", obj->name);
549
Simon Glassb7a64532023-10-01 19:13:24 -0600550 switch (obj->type) {
551 case SCENEOBJT_NONE:
552 case SCENEOBJT_IMAGE:
553 case SCENEOBJT_TEXT:
554 break;
555 case SCENEOBJT_MENU:
556 menu = (struct scene_obj_menu *)obj;
557 val = menu->cur_item_id;
Simon Glass237f3752023-08-14 16:40:35 -0600558
Simon Glassb7a64532023-10-01 19:13:24 -0600559 if (priv->verbose)
560 printf("%s=%d\n", var, val);
Simon Glass237f3752023-08-14 16:40:35 -0600561
Simon Glassb7a64532023-10-01 19:13:24 -0600562 ret = env_set_ulong(var, val);
563 if (ret)
564 return log_msg_ret("set", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600565
Simon Glassb7a64532023-10-01 19:13:24 -0600566 ret = get_cur_menuitem_text(menu, &str);
567 if (ret)
568 return log_msg_ret("mis", ret);
Simon Glass237f3752023-08-14 16:40:35 -0600569
Simon Glassb7a64532023-10-01 19:13:24 -0600570 snprintf(name, sizeof(name), "c.%s-str", obj->name);
571 if (priv->verbose)
572 printf("%s=%s\n", name, str);
573
574 ret = env_set(name, str);
575 if (ret)
576 return log_msg_ret("st2", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600577
578 ret = get_cur_menuitem_val(menu, &val);
579 if (ret < 0)
580 return log_msg_ret("cur", ret);
581 snprintf(name, sizeof(name), "c.%s-value", obj->name);
582 if (priv->verbose)
583 printf("%s=%d\n", name, val);
584
Simon Glassb7a64532023-10-01 19:13:24 -0600585 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600586 case SCENEOBJT_TEXTLINE: {
587 const struct scene_obj_textline *tline;
588
589 tline = (struct scene_obj_textline *)obj;
590 str = abuf_data(&tline->buf);
591 ret = env_set(var, str);
592 if (ret)
593 return log_msg_ret("set", ret);
594
595 if (priv->verbose)
596 printf("%s=%s\n", var, str);
597
598 break;
599 }
Simon Glassb7a64532023-10-01 19:13:24 -0600600 }
Simon Glass237f3752023-08-14 16:40:35 -0600601
602 return 0;
603}
604
605int cedit_write_settings_env(struct expo *exp, bool verbose)
606{
607 struct cedit_iter_priv priv;
608 int ret;
609
610 /* write out the items */
611 priv.verbose = verbose;
612 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
613 if (ret) {
614 log_debug("Failed to write settings to env (err=%d)\n", ret);
615 return log_msg_ret("set", ret);
616 }
617
618 return 0;
619}
Simon Glass0f2e5a62023-08-14 16:40:36 -0600620
621static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
622{
623 struct cedit_iter_priv *priv = vpriv;
624 struct scene_obj_menu *menu;
625 char var[60];
Simon Glass2b91ca62023-08-14 16:40:37 -0600626 int val;
Simon Glass0f2e5a62023-08-14 16:40:36 -0600627
Simon Glass53a0a2f2024-10-14 16:31:57 -0600628 if (obj->id < EXPOID_BASE_ID)
629 return 0;
630
Simon Glass0f2e5a62023-08-14 16:40:36 -0600631 snprintf(var, sizeof(var), "c.%s", obj->name);
632
Simon Glassb7a64532023-10-01 19:13:24 -0600633 switch (obj->type) {
634 case SCENEOBJT_NONE:
635 case SCENEOBJT_IMAGE:
636 case SCENEOBJT_TEXT:
637 break;
638 case SCENEOBJT_MENU:
639 menu = (struct scene_obj_menu *)obj;
640 val = env_get_ulong(var, 10, 0);
641 if (priv->verbose)
642 printf("%s=%d\n", var, val);
643 if (!val)
644 return log_msg_ret("get", -ENOENT);
Simon Glass0f2e5a62023-08-14 16:40:36 -0600645
Simon Glassb7a64532023-10-01 19:13:24 -0600646 /*
647 * note that no validation is done here, to make sure the ID is
Simon Glass330aa1e2024-10-14 16:31:59 -0600648 * valid and actually points to a menu item
Simon Glassb7a64532023-10-01 19:13:24 -0600649 */
650 menu->cur_item_id = val;
651 break;
Simon Glass23c3eb42023-10-01 19:13:37 -0600652 case SCENEOBJT_TEXTLINE: {
653 const struct scene_obj_textline *tline;
654 const char *value;
655
656 tline = (struct scene_obj_textline *)obj;
657 value = env_get(var);
658 if (value && strlen(value) >= tline->max_chars)
659 return log_msg_ret("str", -ENOSPC);
660 if (!value)
661 value = "";
662 if (priv->verbose)
663 printf("%s=%s\n", var, value);
664 strcpy(abuf_data(&tline->buf), value);
665 break;
666 }
Simon Glassb7a64532023-10-01 19:13:24 -0600667 }
Simon Glass0f2e5a62023-08-14 16:40:36 -0600668
669 return 0;
670}
671
672int cedit_read_settings_env(struct expo *exp, bool verbose)
673{
674 struct cedit_iter_priv priv;
675 int ret;
676
677 /* write out the items */
678 priv.verbose = verbose;
679 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
680 if (ret) {
681 log_debug("Failed to read settings from env (err=%d)\n", ret);
682 return log_msg_ret("set", ret);
683 }
684
685 return 0;
686}
Simon Glass2b91ca62023-08-14 16:40:37 -0600687
Simon Glass2b91ca62023-08-14 16:40:37 -0600688static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
689{
690 const struct scene_obj_menu *menu;
691 struct cedit_iter_priv *priv = vpriv;
692 int val, ret;
Simon Glass6f3e87a2024-10-14 16:32:00 -0600693 uint i;
Simon Glass2b91ca62023-08-14 16:40:37 -0600694
Simon Glass53a0a2f2024-10-14 16:31:57 -0600695 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass2b91ca62023-08-14 16:40:37 -0600696 return 0;
697
698 menu = (struct scene_obj_menu *)obj;
699 val = menu->cur_item_id;
700
Simon Glass6f3e87a2024-10-14 16:32:00 -0600701 ret = get_cur_menuitem_val(menu, &val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600702 if (ret < 0)
703 return log_msg_ret("cur", ret);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600704 log_debug("%s: val=%d\n", menu->obj.name, val);
Simon Glass2b91ca62023-08-14 16:40:37 -0600705
706 /* figure out where to place this item */
707 if (!obj->bit_length)
708 return log_msg_ret("len", -EINVAL);
709 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
710 return log_msg_ret("bit", -E2BIG);
711
Simon Glass6f3e87a2024-10-14 16:32:00 -0600712 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
Simon Glass2b91ca62023-08-14 16:40:37 -0600713 uint bitnum = obj->start_bit + i;
714
715 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600716 if (val & 1)
Simon Glass2b91ca62023-08-14 16:40:37 -0600717 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
718 log_debug("bit %x %x %x\n", bitnum,
719 priv->mask[CMOS_BYTE(bitnum)],
720 priv->value[CMOS_BYTE(bitnum)]);
721 }
722
723 return 0;
724}
725
726int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
727 bool verbose)
728{
729 struct cedit_iter_priv priv;
730 int ret, i, count, first, last;
731
732 /* write out the items */
733 priv.mask = calloc(1, CMOS_MAX_BYTES);
734 if (!priv.mask)
735 return log_msg_ret("mas", -ENOMEM);
736 priv.value = calloc(1, CMOS_MAX_BYTES);
737 if (!priv.value) {
738 free(priv.mask);
739 return log_msg_ret("val", -ENOMEM);
740 }
741
742 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
743 if (ret) {
744 log_debug("Failed to write CMOS (err=%d)\n", ret);
745 ret = log_msg_ret("set", ret);
746 goto done;
747 }
748
749 /* write the data to the RTC */
Simon Glass330aa1e2024-10-14 16:31:59 -0600750 log_debug("Writing CMOS\n");
Simon Glass2b91ca62023-08-14 16:40:37 -0600751 first = CMOS_MAX_BYTES;
752 last = -1;
753 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
754 if (priv.mask[i]) {
755 log_debug("Write byte %x: %x\n", i, priv.value[i]);
756 ret = rtc_write8(dev, i, priv.value[i]);
757 if (ret) {
758 ret = log_msg_ret("wri", ret);
759 goto done;
760 }
761 count++;
762 first = min(first, i);
763 last = max(last, i);
764 }
765 }
766 if (verbose) {
767 printf("Write %d bytes from offset %x to %x\n", count, first,
768 last);
769 }
770
771done:
772 free(priv.mask);
773 free(priv.value);
774 return ret;
775}
Simon Glass4462fa32023-08-14 16:40:38 -0600776
777static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
778{
779 struct cedit_iter_priv *priv = vpriv;
780 const struct scene_menitem *mi;
781 struct scene_obj_menu *menu;
782 int val, ret;
783 uint i;
784
Simon Glass53a0a2f2024-10-14 16:31:57 -0600785 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
Simon Glass4462fa32023-08-14 16:40:38 -0600786 return 0;
787
788 menu = (struct scene_obj_menu *)obj;
789
790 /* figure out where to place this item */
791 if (!obj->bit_length)
792 return log_msg_ret("len", -EINVAL);
793 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
794 return log_msg_ret("bit", -E2BIG);
795
796 val = 0;
797 for (i = 0; i < obj->bit_length; i++) {
798 uint bitnum = obj->start_bit + i;
799 uint offset = CMOS_BYTE(bitnum);
800
801 /* read the byte if not already read */
802 if (!priv->mask[offset]) {
803 ret = rtc_read8(priv->dev, offset);
804 if (ret < 0)
805 return log_msg_ret("rea", ret);
806 priv->value[offset] = ret;
807
808 /* mark it as read */
809 priv->mask[offset] = 0xff;
810 }
811
812 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
813 val |= BIT(i);
814 log_debug("bit %x %x\n", bitnum, val);
815 }
816
817 /* update the current item */
Simon Glass330aa1e2024-10-14 16:31:59 -0600818 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
Simon Glass6f3e87a2024-10-14 16:32:00 -0600819 mi = scene_menuitem_find_val(menu, val);
Simon Glass4462fa32023-08-14 16:40:38 -0600820 if (!mi)
821 return log_msg_ret("seq", -ENOENT);
822
823 menu->cur_item_id = mi->id;
824 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
825
826 return 0;
827}
828
829int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
830 bool verbose)
831{
832 struct cedit_iter_priv priv;
833 int ret, i, count, first, last;
834
835 /* read in the items */
836 priv.mask = calloc(1, CMOS_MAX_BYTES);
837 if (!priv.mask)
838 return log_msg_ret("mas", -ENOMEM);
839 priv.value = calloc(1, CMOS_MAX_BYTES);
840 if (!priv.value) {
841 free(priv.mask);
842 return log_msg_ret("val", -ENOMEM);
843 }
844 priv.dev = dev;
845
846 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
847 if (ret) {
848 log_debug("Failed to read CMOS (err=%d)\n", ret);
849 ret = log_msg_ret("set", ret);
850 goto done;
851 }
852
Simon Glass330aa1e2024-10-14 16:31:59 -0600853 /* indicate what bytes were read from the RTC */
Simon Glass4462fa32023-08-14 16:40:38 -0600854 first = CMOS_MAX_BYTES;
855 last = -1;
856 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
857 if (priv.mask[i]) {
858 log_debug("Read byte %x: %x\n", i, priv.value[i]);
859 count++;
860 first = min(first, i);
861 last = max(last, i);
862 }
863 }
864 if (verbose) {
865 printf("Read %d bytes from offset %x to %x\n", count, first,
866 last);
867 }
868
869done:
870 free(priv.mask);
871 free(priv.value);
872 return ret;
873}