blob: 407793aaddd412e7c5ca9dadb6034e22db43daa1 [file] [log] [blame]
Simon Glassa0874dc2023-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 Glass8d0f8902023-08-14 16:40:27 -06009#define LOG_CATEGORY LOGC_EXPO
10
Simon Glassa0874dc2023-06-01 10:23:02 -060011#include <common.h>
Simon Glass2dee81f2023-08-14 16:40:33 -060012#include <abuf.h>
Simon Glass040b0462023-08-14 16:40:25 -060013#include <cedit.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060014#include <cli.h>
15#include <dm.h>
Simon Glassfc9c0e02023-08-14 16:40:35 -060016#include <env.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060017#include <expo.h>
Simon Glasseb6c71b2023-08-14 16:40:37 -060018#include <malloc.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060019#include <menu.h>
Simon Glasseb6c71b2023-08-14 16:40:37 -060020#include <rtc.h>
Simon Glassa0874dc2023-06-01 10:23:02 -060021#include <video.h>
22#include <linux/delay.h>
23#include "scene_internal.h"
24
Simon Glasseb6c71b2023-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 Glass2dee81f2023-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 Glass472317c2023-08-14 16:40:34 -060037 * @node: Node to read from when reading settings from devicetree
Simon Glassfc9c0e02023-08-14 16:40:35 -060038 * @verbose: true to show writing to environment variables
Simon Glasseb6c71b2023-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 Glasscfc402d2023-08-14 16:40:38 -060042 * @dev: RTC device to write to
Simon Glass2dee81f2023-08-14 16:40:33 -060043 */
44struct cedit_iter_priv {
45 struct abuf *buf;
Simon Glass472317c2023-08-14 16:40:34 -060046 ofnode node;
Simon Glassfc9c0e02023-08-14 16:40:35 -060047 bool verbose;
Simon Glasseb6c71b2023-08-14 16:40:37 -060048 u8 *mask;
49 u8 *value;
Simon Glasscfc402d2023-08-14 16:40:38 -060050 struct udevice *dev;
Simon Glass2dee81f2023-08-14 16:40:33 -060051};
52
Simon Glassa0874dc2023-06-01 10:23:02 -060053int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
54{
55 struct scene_obj_txt *txt;
56 struct scene_obj *obj;
57 struct scene *scn;
58 int y;
59
60 scn = expo_lookup_scene_id(exp, scene_id);
61 if (!scn)
62 return log_msg_ret("scn", -ENOENT);
63
64 txt = scene_obj_find_by_name(scn, "prompt");
65 if (txt)
66 scene_obj_set_pos(scn, txt->obj.id, 0, vpriv->ysize - 50);
67
68 txt = scene_obj_find_by_name(scn, "title");
69 if (txt)
70 scene_obj_set_pos(scn, txt->obj.id, 200, 10);
71
72 y = 100;
73 list_for_each_entry(obj, &scn->obj_head, sibling) {
Simon Glassfd6073a2023-10-01 19:13:24 -060074 switch (obj->type) {
75 case SCENEOBJT_NONE:
76 case SCENEOBJT_IMAGE:
77 case SCENEOBJT_TEXT:
78 break;
79 case SCENEOBJT_MENU:
Simon Glassa0874dc2023-06-01 10:23:02 -060080 scene_obj_set_pos(scn, obj->id, 50, y);
81 scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
82 y += 50;
Simon Glassfd6073a2023-10-01 19:13:24 -060083 break;
Simon Glassa0874dc2023-06-01 10:23:02 -060084 }
85 }
86
87 return 0;
88}
89
Simon Glass8d0f8902023-08-14 16:40:27 -060090int cedit_prepare(struct expo *exp, struct video_priv **vid_privp,
91 struct scene **scnp)
Simon Glassa0874dc2023-06-01 10:23:02 -060092{
Simon Glassa0874dc2023-06-01 10:23:02 -060093 struct video_priv *vid_priv;
Simon Glassa0874dc2023-06-01 10:23:02 -060094 struct udevice *dev;
95 struct scene *scn;
Simon Glass8d0f8902023-08-14 16:40:27 -060096 uint scene_id;
Simon Glassa0874dc2023-06-01 10:23:02 -060097 int ret;
98
Simon Glassa0874dc2023-06-01 10:23:02 -060099 /* For now we only support a video console */
100 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
101 if (ret)
102 return log_msg_ret("vid", ret);
103 ret = expo_set_display(exp, dev);
104 if (ret)
105 return log_msg_ret("dis", ret);
106
107 ret = expo_first_scene_id(exp);
108 if (ret < 0)
109 return log_msg_ret("scn", ret);
110 scene_id = ret;
111
112 ret = expo_set_scene_id(exp, scene_id);
113 if (ret)
114 return log_msg_ret("sid", ret);
115
116 exp->popup = true;
117
118 /* This is not supported for now */
119 if (0)
120 expo_set_text_mode(exp, true);
121
122 vid_priv = dev_get_uclass_priv(dev);
123
124 scn = expo_lookup_scene_id(exp, scene_id);
125 scene_highlight_first(scn);
126
127 cedit_arange(exp, vid_priv, scene_id);
128
129 ret = expo_calc_dims(exp);
130 if (ret)
131 return log_msg_ret("dim", ret);
132
Simon Glass8d0f8902023-08-14 16:40:27 -0600133 *vid_privp = vid_priv;
134 *scnp = scn;
135
136 return scene_id;
137}
138
139int cedit_run(struct expo *exp)
140{
141 struct cli_ch_state s_cch, *cch = &s_cch;
142 struct video_priv *vid_priv;
143 uint scene_id;
144 struct scene *scn;
145 bool done;
146 int ret;
147
148 cli_ch_init(cch);
149 ret = cedit_prepare(exp, &vid_priv, &scn);
150 if (ret < 0)
151 return log_msg_ret("prep", ret);
152 scene_id = ret;
153
Simon Glassa0874dc2023-06-01 10:23:02 -0600154 done = false;
155 do {
156 struct expo_action act;
157 int ichar, key;
158
159 ret = expo_render(exp);
160 if (ret)
161 break;
162
163 ichar = cli_ch_process(cch, 0);
164 if (!ichar) {
165 while (!ichar && !tstc()) {
166 schedule();
167 mdelay(2);
168 ichar = cli_ch_process(cch, -ETIMEDOUT);
169 }
170 if (!ichar) {
171 ichar = getchar();
172 ichar = cli_ch_process(cch, ichar);
173 }
174 }
175
176 key = 0;
177 if (ichar) {
178 key = bootmenu_conv_key(ichar);
Simon Glass8579cb02023-10-01 19:13:36 -0600179 if (key == BKEY_NONE || key >= BKEY_FIRST_EXTRA)
Simon Glassa0874dc2023-06-01 10:23:02 -0600180 key = ichar;
181 }
182 if (!key)
183 continue;
184
185 ret = expo_send_key(exp, key);
186 if (ret)
187 break;
188
189 ret = expo_action_get(exp, &act);
190 if (!ret) {
191 switch (act.type) {
192 case EXPOACT_POINT_OBJ:
193 scene_set_highlight_id(scn, act.select.id);
194 cedit_arange(exp, vid_priv, scene_id);
195 break;
196 case EXPOACT_OPEN:
197 scene_set_open(scn, act.select.id, true);
198 cedit_arange(exp, vid_priv, scene_id);
199 break;
200 case EXPOACT_CLOSE:
201 scene_set_open(scn, act.select.id, false);
202 cedit_arange(exp, vid_priv, scene_id);
203 break;
204 case EXPOACT_SELECT:
205 scene_set_open(scn, scn->highlight_id, false);
206 cedit_arange(exp, vid_priv, scene_id);
207 break;
208 case EXPOACT_QUIT:
209 log_debug("quitting\n");
210 done = true;
211 break;
212 default:
213 break;
214 }
215 }
216 } while (!done);
217
218 if (ret)
219 return log_msg_ret("end", ret);
220
221 return 0;
222}
Simon Glass2dee81f2023-08-14 16:40:33 -0600223
224static int check_space(int ret, struct abuf *buf)
225{
226 if (ret == -FDT_ERR_NOSPACE) {
227 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
228 return log_msg_ret("spc", -ENOMEM);
229 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
230 abuf_size(buf));
231 if (ret)
232 return log_msg_ret("res", -EFAULT);
233 }
234
235 return 0;
236}
237
Simon Glass909c4862023-10-01 19:13:23 -0600238/**
239 * get_cur_menuitem_text() - Get the text of the currently selected item
240 *
241 * Looks up the object for the current item, finds text object for it and looks
242 * up the string for that text
243 *
244 * @menu: Menu to look at
245 * @strp: Returns a pointer to the next
246 * Return: 0 if OK, -ENOENT if something was not found
247 */
Simon Glassfc9c0e02023-08-14 16:40:35 -0600248static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
249 const char **strp)
250{
251 struct scene *scn = menu->obj.scene;
252 const struct scene_menitem *mi;
253 const struct scene_obj_txt *txt;
254 const char *str;
255
256 mi = scene_menuitem_find(menu, menu->cur_item_id);
257 if (!mi)
258 return log_msg_ret("mi", -ENOENT);
259
260 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
261 if (!txt)
262 return log_msg_ret("txt", -ENOENT);
263
264 str = expo_get_str(scn->expo, txt->str_id);
265 if (!str)
266 return log_msg_ret("str", -ENOENT);
267 *strp = str;
268
269 return 0;
270}
271
Simon Glass117617c2023-10-01 19:13:28 -0600272static int write_dt_string(struct abuf *buf, const char *name, const char *str)
273{
274 int ret, i;
275
276 /* write the text of the current item */
277 ret = -EAGAIN;
278 for (i = 0; ret && i < 2; i++) {
279 ret = fdt_property_string(abuf_data(buf), name, str);
280 if (!i) {
281 ret = check_space(ret, buf);
282 if (ret)
283 return log_msg_ret("rs2", -ENOMEM);
284 }
285 }
286
287 /* this should not happen */
288 if (ret)
289 return log_msg_ret("str", -EFAULT);
290
291 return 0;
292}
293
Simon Glass2dee81f2023-08-14 16:40:33 -0600294static int h_write_settings(struct scene_obj *obj, void *vpriv)
295{
296 struct cedit_iter_priv *priv = vpriv;
297 struct abuf *buf = priv->buf;
298
299 switch (obj->type) {
300 case SCENEOBJT_NONE:
301 case SCENEOBJT_IMAGE:
302 case SCENEOBJT_TEXT:
303 break;
304 case SCENEOBJT_MENU: {
305 const struct scene_obj_menu *menu;
Simon Glass2dee81f2023-08-14 16:40:33 -0600306 const char *str;
307 char name[80];
308 int ret, i;
309
Simon Glass117617c2023-10-01 19:13:28 -0600310 /* write the ID of the current item */
Simon Glass2dee81f2023-08-14 16:40:33 -0600311 menu = (struct scene_obj_menu *)obj;
312 ret = -EAGAIN;
313 for (i = 0; ret && i < 2; i++) {
314 ret = fdt_property_u32(abuf_data(buf), obj->name,
315 menu->cur_item_id);
316 if (!i) {
317 ret = check_space(ret, buf);
318 if (ret)
319 return log_msg_ret("res", -ENOMEM);
320 }
321 }
322 /* this should not happen */
323 if (ret)
324 return log_msg_ret("wrt", -EFAULT);
325
Simon Glassfc9c0e02023-08-14 16:40:35 -0600326 ret = get_cur_menuitem_text(menu, &str);
327 if (ret)
328 return log_msg_ret("mis", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600329
Simon Glass117617c2023-10-01 19:13:28 -0600330 /* write the text of the current item */
Simon Glass2dee81f2023-08-14 16:40:33 -0600331 snprintf(name, sizeof(name), "%s-str", obj->name);
Simon Glass117617c2023-10-01 19:13:28 -0600332 ret = write_dt_string(buf, name, str);
Simon Glass2dee81f2023-08-14 16:40:33 -0600333 if (ret)
Simon Glass117617c2023-10-01 19:13:28 -0600334 return log_msg_ret("wr2", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600335
336 break;
337 }
338 }
339
340 return 0;
341}
342
343int cedit_write_settings(struct expo *exp, struct abuf *buf)
344{
345 struct cedit_iter_priv priv;
346 void *fdt;
347 int ret;
348
349 abuf_init(buf);
350 if (!abuf_realloc(buf, CEDIT_SIZE_INC))
351 return log_msg_ret("buf", -ENOMEM);
352
353 fdt = abuf_data(buf);
354 ret = fdt_create(fdt, abuf_size(buf));
355 if (!ret)
356 ret = fdt_finish_reservemap(fdt);
357 if (!ret)
358 ret = fdt_begin_node(fdt, "");
359 if (!ret)
360 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
361 if (ret) {
362 log_debug("Failed to start FDT (err=%d)\n", ret);
363 return log_msg_ret("sta", -EINVAL);
364 }
365
366 /* write out the items */
367 priv.buf = buf;
368 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
369 if (ret) {
370 log_debug("Failed to write settings (err=%d)\n", ret);
371 return log_msg_ret("set", ret);
372 }
373
374 ret = fdt_end_node(fdt);
375 if (!ret)
376 ret = fdt_end_node(fdt);
377 if (!ret)
378 ret = fdt_finish(fdt);
379 if (ret) {
380 log_debug("Failed to finish FDT (err=%d)\n", ret);
381 return log_msg_ret("fin", -EINVAL);
382 }
383
384 return 0;
385}
Simon Glass472317c2023-08-14 16:40:34 -0600386
387static int h_read_settings(struct scene_obj *obj, void *vpriv)
388{
389 struct cedit_iter_priv *priv = vpriv;
390 ofnode node = priv->node;
391
392 switch (obj->type) {
393 case SCENEOBJT_NONE:
394 case SCENEOBJT_IMAGE:
395 case SCENEOBJT_TEXT:
396 break;
397 case SCENEOBJT_MENU: {
398 struct scene_obj_menu *menu;
399 uint val;
400
401 if (ofnode_read_u32(node, obj->name, &val))
402 return log_msg_ret("rd", -ENOENT);
403 menu = (struct scene_obj_menu *)obj;
404 menu->cur_item_id = val;
405
406 break;
407 }
408 }
409
410 return 0;
411}
412
413int cedit_read_settings(struct expo *exp, oftree tree)
414{
415 struct cedit_iter_priv priv;
416 ofnode root, node;
417 int ret;
418
419 root = oftree_root(tree);
420 if (!ofnode_valid(root))
421 return log_msg_ret("roo", -ENOENT);
422 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
423 if (!ofnode_valid(node))
424 return log_msg_ret("pat", -ENOENT);
425
426 /* read in the items */
427 priv.node = node;
428 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
429 if (ret) {
430 log_debug("Failed to read settings (err=%d)\n", ret);
431 return log_msg_ret("set", ret);
432 }
433
434 return 0;
435}
Simon Glassfc9c0e02023-08-14 16:40:35 -0600436
437static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
438{
439 const struct scene_obj_menu *menu;
440 struct cedit_iter_priv *priv = vpriv;
441 char name[80], var[60];
442 const char *str;
443 int val, ret;
444
Simon Glassfc9c0e02023-08-14 16:40:35 -0600445 snprintf(var, sizeof(var), "c.%s", obj->name);
446
Simon Glassfd6073a2023-10-01 19:13:24 -0600447 switch (obj->type) {
448 case SCENEOBJT_NONE:
449 case SCENEOBJT_IMAGE:
450 case SCENEOBJT_TEXT:
451 break;
452 case SCENEOBJT_MENU:
453 menu = (struct scene_obj_menu *)obj;
454 val = menu->cur_item_id;
Simon Glassfc9c0e02023-08-14 16:40:35 -0600455
Simon Glassfd6073a2023-10-01 19:13:24 -0600456 if (priv->verbose)
457 printf("%s=%d\n", var, val);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600458
Simon Glassfd6073a2023-10-01 19:13:24 -0600459 ret = env_set_ulong(var, val);
460 if (ret)
461 return log_msg_ret("set", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600462
Simon Glassfd6073a2023-10-01 19:13:24 -0600463 ret = get_cur_menuitem_text(menu, &str);
464 if (ret)
465 return log_msg_ret("mis", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600466
Simon Glassfd6073a2023-10-01 19:13:24 -0600467 snprintf(name, sizeof(name), "c.%s-str", obj->name);
468 if (priv->verbose)
469 printf("%s=%s\n", name, str);
470
471 ret = env_set(name, str);
472 if (ret)
473 return log_msg_ret("st2", ret);
474 break;
475 }
Simon Glassfc9c0e02023-08-14 16:40:35 -0600476
477 return 0;
478}
479
480int cedit_write_settings_env(struct expo *exp, bool verbose)
481{
482 struct cedit_iter_priv priv;
483 int ret;
484
485 /* write out the items */
486 priv.verbose = verbose;
487 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
488 if (ret) {
489 log_debug("Failed to write settings to env (err=%d)\n", ret);
490 return log_msg_ret("set", ret);
491 }
492
493 return 0;
494}
Simon Glassbcf2b722023-08-14 16:40:36 -0600495
496static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
497{
498 struct cedit_iter_priv *priv = vpriv;
499 struct scene_obj_menu *menu;
500 char var[60];
Simon Glasseb6c71b2023-08-14 16:40:37 -0600501 int val;
Simon Glassbcf2b722023-08-14 16:40:36 -0600502
Simon Glassbcf2b722023-08-14 16:40:36 -0600503 snprintf(var, sizeof(var), "c.%s", obj->name);
504
Simon Glassfd6073a2023-10-01 19:13:24 -0600505 switch (obj->type) {
506 case SCENEOBJT_NONE:
507 case SCENEOBJT_IMAGE:
508 case SCENEOBJT_TEXT:
509 break;
510 case SCENEOBJT_MENU:
511 menu = (struct scene_obj_menu *)obj;
512 val = env_get_ulong(var, 10, 0);
513 if (priv->verbose)
514 printf("%s=%d\n", var, val);
515 if (!val)
516 return log_msg_ret("get", -ENOENT);
Simon Glassbcf2b722023-08-14 16:40:36 -0600517
Simon Glassfd6073a2023-10-01 19:13:24 -0600518 /*
519 * note that no validation is done here, to make sure the ID is
520 * valid * and actually points to a menu item
521 */
522 menu->cur_item_id = val;
523 break;
524 }
Simon Glassbcf2b722023-08-14 16:40:36 -0600525
526 return 0;
527}
528
529int cedit_read_settings_env(struct expo *exp, bool verbose)
530{
531 struct cedit_iter_priv priv;
532 int ret;
533
534 /* write out the items */
535 priv.verbose = verbose;
536 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
537 if (ret) {
538 log_debug("Failed to read settings from env (err=%d)\n", ret);
539 return log_msg_ret("set", ret);
540 }
541
542 return 0;
543}
Simon Glasseb6c71b2023-08-14 16:40:37 -0600544
545/**
546 * get_cur_menuitem_seq() - Get the sequence number of a menu's current item
547 *
548 * Enumerates the items of a menu (0, 1, 2) and returns the sequence number of
549 * the currently selected item. If the first item is selected, this returns 0;
550 * if the second, 1; etc.
551 *
552 * @menu: Menu to check
553 * Return: Sequence number on success, else -ve error value
554 */
555static int get_cur_menuitem_seq(const struct scene_obj_menu *menu)
556{
557 const struct scene_menitem *mi;
558 int seq, found;
559
560 seq = 0;
561 found = -1;
562 list_for_each_entry(mi, &menu->item_head, sibling) {
563 if (mi->id == menu->cur_item_id) {
564 found = seq;
565 break;
566 }
567 seq++;
568 }
569
570 if (found == -1)
571 return log_msg_ret("nf", -ENOENT);
572
573 return found;
574}
575
576static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
577{
578 const struct scene_obj_menu *menu;
579 struct cedit_iter_priv *priv = vpriv;
580 int val, ret;
581 uint i, seq;
582
583 if (obj->type != SCENEOBJT_MENU)
584 return 0;
585
586 menu = (struct scene_obj_menu *)obj;
587 val = menu->cur_item_id;
588
589 ret = get_cur_menuitem_seq(menu);
590 if (ret < 0)
591 return log_msg_ret("cur", ret);
592 seq = ret;
593 log_debug("%s: seq=%d\n", menu->obj.name, seq);
594
595 /* figure out where to place this item */
596 if (!obj->bit_length)
597 return log_msg_ret("len", -EINVAL);
598 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
599 return log_msg_ret("bit", -E2BIG);
600
601 for (i = 0; i < obj->bit_length; i++, seq >>= 1) {
602 uint bitnum = obj->start_bit + i;
603
604 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
605 if (seq & 1)
606 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
607 log_debug("bit %x %x %x\n", bitnum,
608 priv->mask[CMOS_BYTE(bitnum)],
609 priv->value[CMOS_BYTE(bitnum)]);
610 }
611
612 return 0;
613}
614
615int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
616 bool verbose)
617{
618 struct cedit_iter_priv priv;
619 int ret, i, count, first, last;
620
621 /* write out the items */
622 priv.mask = calloc(1, CMOS_MAX_BYTES);
623 if (!priv.mask)
624 return log_msg_ret("mas", -ENOMEM);
625 priv.value = calloc(1, CMOS_MAX_BYTES);
626 if (!priv.value) {
627 free(priv.mask);
628 return log_msg_ret("val", -ENOMEM);
629 }
630
631 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
632 if (ret) {
633 log_debug("Failed to write CMOS (err=%d)\n", ret);
634 ret = log_msg_ret("set", ret);
635 goto done;
636 }
637
638 /* write the data to the RTC */
639 first = CMOS_MAX_BYTES;
640 last = -1;
641 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
642 if (priv.mask[i]) {
643 log_debug("Write byte %x: %x\n", i, priv.value[i]);
644 ret = rtc_write8(dev, i, priv.value[i]);
645 if (ret) {
646 ret = log_msg_ret("wri", ret);
647 goto done;
648 }
649 count++;
650 first = min(first, i);
651 last = max(last, i);
652 }
653 }
654 if (verbose) {
655 printf("Write %d bytes from offset %x to %x\n", count, first,
656 last);
657 }
658
659done:
660 free(priv.mask);
661 free(priv.value);
662 return ret;
663}
Simon Glasscfc402d2023-08-14 16:40:38 -0600664
665static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
666{
667 struct cedit_iter_priv *priv = vpriv;
668 const struct scene_menitem *mi;
669 struct scene_obj_menu *menu;
670 int val, ret;
671 uint i;
672
673 if (obj->type != SCENEOBJT_MENU)
674 return 0;
675
676 menu = (struct scene_obj_menu *)obj;
677
678 /* figure out where to place this item */
679 if (!obj->bit_length)
680 return log_msg_ret("len", -EINVAL);
681 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
682 return log_msg_ret("bit", -E2BIG);
683
684 val = 0;
685 for (i = 0; i < obj->bit_length; i++) {
686 uint bitnum = obj->start_bit + i;
687 uint offset = CMOS_BYTE(bitnum);
688
689 /* read the byte if not already read */
690 if (!priv->mask[offset]) {
691 ret = rtc_read8(priv->dev, offset);
692 if (ret < 0)
693 return log_msg_ret("rea", ret);
694 priv->value[offset] = ret;
695
696 /* mark it as read */
697 priv->mask[offset] = 0xff;
698 }
699
700 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
701 val |= BIT(i);
702 log_debug("bit %x %x\n", bitnum, val);
703 }
704
705 /* update the current item */
706 mi = scene_menuitem_find_seq(menu, val);
707 if (!mi)
708 return log_msg_ret("seq", -ENOENT);
709
710 menu->cur_item_id = mi->id;
711 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
712
713 return 0;
714}
715
716int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
717 bool verbose)
718{
719 struct cedit_iter_priv priv;
720 int ret, i, count, first, last;
721
722 /* read in the items */
723 priv.mask = calloc(1, CMOS_MAX_BYTES);
724 if (!priv.mask)
725 return log_msg_ret("mas", -ENOMEM);
726 priv.value = calloc(1, CMOS_MAX_BYTES);
727 if (!priv.value) {
728 free(priv.mask);
729 return log_msg_ret("val", -ENOMEM);
730 }
731 priv.dev = dev;
732
733 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
734 if (ret) {
735 log_debug("Failed to read CMOS (err=%d)\n", ret);
736 ret = log_msg_ret("set", ret);
737 goto done;
738 }
739
740 /* read the data to the RTC */
741 first = CMOS_MAX_BYTES;
742 last = -1;
743 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
744 if (priv.mask[i]) {
745 log_debug("Read byte %x: %x\n", i, priv.value[i]);
746 count++;
747 first = min(first, i);
748 last = max(last, i);
749 }
750 }
751 if (verbose) {
752 printf("Read %d bytes from offset %x to %x\n", count, first,
753 last);
754 }
755
756done:
757 free(priv.mask);
758 free(priv.value);
759 return ret;
760}