blob: b7329c3245ee5cecf063c202d8aa3145253aca86 [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);
179 if (key == BKEY_NONE)
180 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 Glass2dee81f2023-08-14 16:40:33 -0600272static int h_write_settings(struct scene_obj *obj, void *vpriv)
273{
274 struct cedit_iter_priv *priv = vpriv;
275 struct abuf *buf = priv->buf;
276
277 switch (obj->type) {
278 case SCENEOBJT_NONE:
279 case SCENEOBJT_IMAGE:
280 case SCENEOBJT_TEXT:
281 break;
282 case SCENEOBJT_MENU: {
283 const struct scene_obj_menu *menu;
Simon Glass2dee81f2023-08-14 16:40:33 -0600284 const char *str;
285 char name[80];
286 int ret, i;
287
288 menu = (struct scene_obj_menu *)obj;
289 ret = -EAGAIN;
290 for (i = 0; ret && i < 2; i++) {
291 ret = fdt_property_u32(abuf_data(buf), obj->name,
292 menu->cur_item_id);
293 if (!i) {
294 ret = check_space(ret, buf);
295 if (ret)
296 return log_msg_ret("res", -ENOMEM);
297 }
298 }
299 /* this should not happen */
300 if (ret)
301 return log_msg_ret("wrt", -EFAULT);
302
Simon Glassfc9c0e02023-08-14 16:40:35 -0600303 ret = get_cur_menuitem_text(menu, &str);
304 if (ret)
305 return log_msg_ret("mis", ret);
Simon Glass2dee81f2023-08-14 16:40:33 -0600306
307 snprintf(name, sizeof(name), "%s-str", obj->name);
308 ret = -EAGAIN;
309 for (i = 0; ret && i < 2; i++) {
310 ret = fdt_property_string(abuf_data(buf), name, str);
311 if (!i) {
312 ret = check_space(ret, buf);
313 if (ret)
314 return log_msg_ret("rs2", -ENOMEM);
315 }
316 }
317
318 /* this should not happen */
319 if (ret)
320 return log_msg_ret("wr2", -EFAULT);
321
322 break;
323 }
324 }
325
326 return 0;
327}
328
329int cedit_write_settings(struct expo *exp, struct abuf *buf)
330{
331 struct cedit_iter_priv priv;
332 void *fdt;
333 int ret;
334
335 abuf_init(buf);
336 if (!abuf_realloc(buf, CEDIT_SIZE_INC))
337 return log_msg_ret("buf", -ENOMEM);
338
339 fdt = abuf_data(buf);
340 ret = fdt_create(fdt, abuf_size(buf));
341 if (!ret)
342 ret = fdt_finish_reservemap(fdt);
343 if (!ret)
344 ret = fdt_begin_node(fdt, "");
345 if (!ret)
346 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
347 if (ret) {
348 log_debug("Failed to start FDT (err=%d)\n", ret);
349 return log_msg_ret("sta", -EINVAL);
350 }
351
352 /* write out the items */
353 priv.buf = buf;
354 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
355 if (ret) {
356 log_debug("Failed to write settings (err=%d)\n", ret);
357 return log_msg_ret("set", ret);
358 }
359
360 ret = fdt_end_node(fdt);
361 if (!ret)
362 ret = fdt_end_node(fdt);
363 if (!ret)
364 ret = fdt_finish(fdt);
365 if (ret) {
366 log_debug("Failed to finish FDT (err=%d)\n", ret);
367 return log_msg_ret("fin", -EINVAL);
368 }
369
370 return 0;
371}
Simon Glass472317c2023-08-14 16:40:34 -0600372
373static int h_read_settings(struct scene_obj *obj, void *vpriv)
374{
375 struct cedit_iter_priv *priv = vpriv;
376 ofnode node = priv->node;
377
378 switch (obj->type) {
379 case SCENEOBJT_NONE:
380 case SCENEOBJT_IMAGE:
381 case SCENEOBJT_TEXT:
382 break;
383 case SCENEOBJT_MENU: {
384 struct scene_obj_menu *menu;
385 uint val;
386
387 if (ofnode_read_u32(node, obj->name, &val))
388 return log_msg_ret("rd", -ENOENT);
389 menu = (struct scene_obj_menu *)obj;
390 menu->cur_item_id = val;
391
392 break;
393 }
394 }
395
396 return 0;
397}
398
399int cedit_read_settings(struct expo *exp, oftree tree)
400{
401 struct cedit_iter_priv priv;
402 ofnode root, node;
403 int ret;
404
405 root = oftree_root(tree);
406 if (!ofnode_valid(root))
407 return log_msg_ret("roo", -ENOENT);
408 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
409 if (!ofnode_valid(node))
410 return log_msg_ret("pat", -ENOENT);
411
412 /* read in the items */
413 priv.node = node;
414 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
415 if (ret) {
416 log_debug("Failed to read settings (err=%d)\n", ret);
417 return log_msg_ret("set", ret);
418 }
419
420 return 0;
421}
Simon Glassfc9c0e02023-08-14 16:40:35 -0600422
423static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
424{
425 const struct scene_obj_menu *menu;
426 struct cedit_iter_priv *priv = vpriv;
427 char name[80], var[60];
428 const char *str;
429 int val, ret;
430
Simon Glassfc9c0e02023-08-14 16:40:35 -0600431 snprintf(var, sizeof(var), "c.%s", obj->name);
432
Simon Glassfd6073a2023-10-01 19:13:24 -0600433 switch (obj->type) {
434 case SCENEOBJT_NONE:
435 case SCENEOBJT_IMAGE:
436 case SCENEOBJT_TEXT:
437 break;
438 case SCENEOBJT_MENU:
439 menu = (struct scene_obj_menu *)obj;
440 val = menu->cur_item_id;
Simon Glassfc9c0e02023-08-14 16:40:35 -0600441
Simon Glassfd6073a2023-10-01 19:13:24 -0600442 if (priv->verbose)
443 printf("%s=%d\n", var, val);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600444
Simon Glassfd6073a2023-10-01 19:13:24 -0600445 ret = env_set_ulong(var, val);
446 if (ret)
447 return log_msg_ret("set", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600448
Simon Glassfd6073a2023-10-01 19:13:24 -0600449 ret = get_cur_menuitem_text(menu, &str);
450 if (ret)
451 return log_msg_ret("mis", ret);
Simon Glassfc9c0e02023-08-14 16:40:35 -0600452
Simon Glassfd6073a2023-10-01 19:13:24 -0600453 snprintf(name, sizeof(name), "c.%s-str", obj->name);
454 if (priv->verbose)
455 printf("%s=%s\n", name, str);
456
457 ret = env_set(name, str);
458 if (ret)
459 return log_msg_ret("st2", ret);
460 break;
461 }
Simon Glassfc9c0e02023-08-14 16:40:35 -0600462
463 return 0;
464}
465
466int cedit_write_settings_env(struct expo *exp, bool verbose)
467{
468 struct cedit_iter_priv priv;
469 int ret;
470
471 /* write out the items */
472 priv.verbose = verbose;
473 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
474 if (ret) {
475 log_debug("Failed to write settings to env (err=%d)\n", ret);
476 return log_msg_ret("set", ret);
477 }
478
479 return 0;
480}
Simon Glassbcf2b722023-08-14 16:40:36 -0600481
482static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
483{
484 struct cedit_iter_priv *priv = vpriv;
485 struct scene_obj_menu *menu;
486 char var[60];
Simon Glasseb6c71b2023-08-14 16:40:37 -0600487 int val;
Simon Glassbcf2b722023-08-14 16:40:36 -0600488
Simon Glassbcf2b722023-08-14 16:40:36 -0600489 snprintf(var, sizeof(var), "c.%s", obj->name);
490
Simon Glassfd6073a2023-10-01 19:13:24 -0600491 switch (obj->type) {
492 case SCENEOBJT_NONE:
493 case SCENEOBJT_IMAGE:
494 case SCENEOBJT_TEXT:
495 break;
496 case SCENEOBJT_MENU:
497 menu = (struct scene_obj_menu *)obj;
498 val = env_get_ulong(var, 10, 0);
499 if (priv->verbose)
500 printf("%s=%d\n", var, val);
501 if (!val)
502 return log_msg_ret("get", -ENOENT);
Simon Glassbcf2b722023-08-14 16:40:36 -0600503
Simon Glassfd6073a2023-10-01 19:13:24 -0600504 /*
505 * note that no validation is done here, to make sure the ID is
506 * valid * and actually points to a menu item
507 */
508 menu->cur_item_id = val;
509 break;
510 }
Simon Glassbcf2b722023-08-14 16:40:36 -0600511
512 return 0;
513}
514
515int cedit_read_settings_env(struct expo *exp, bool verbose)
516{
517 struct cedit_iter_priv priv;
518 int ret;
519
520 /* write out the items */
521 priv.verbose = verbose;
522 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
523 if (ret) {
524 log_debug("Failed to read settings from env (err=%d)\n", ret);
525 return log_msg_ret("set", ret);
526 }
527
528 return 0;
529}
Simon Glasseb6c71b2023-08-14 16:40:37 -0600530
531/**
532 * get_cur_menuitem_seq() - Get the sequence number of a menu's current item
533 *
534 * Enumerates the items of a menu (0, 1, 2) and returns the sequence number of
535 * the currently selected item. If the first item is selected, this returns 0;
536 * if the second, 1; etc.
537 *
538 * @menu: Menu to check
539 * Return: Sequence number on success, else -ve error value
540 */
541static int get_cur_menuitem_seq(const struct scene_obj_menu *menu)
542{
543 const struct scene_menitem *mi;
544 int seq, found;
545
546 seq = 0;
547 found = -1;
548 list_for_each_entry(mi, &menu->item_head, sibling) {
549 if (mi->id == menu->cur_item_id) {
550 found = seq;
551 break;
552 }
553 seq++;
554 }
555
556 if (found == -1)
557 return log_msg_ret("nf", -ENOENT);
558
559 return found;
560}
561
562static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
563{
564 const struct scene_obj_menu *menu;
565 struct cedit_iter_priv *priv = vpriv;
566 int val, ret;
567 uint i, seq;
568
569 if (obj->type != SCENEOBJT_MENU)
570 return 0;
571
572 menu = (struct scene_obj_menu *)obj;
573 val = menu->cur_item_id;
574
575 ret = get_cur_menuitem_seq(menu);
576 if (ret < 0)
577 return log_msg_ret("cur", ret);
578 seq = ret;
579 log_debug("%s: seq=%d\n", menu->obj.name, seq);
580
581 /* figure out where to place this item */
582 if (!obj->bit_length)
583 return log_msg_ret("len", -EINVAL);
584 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
585 return log_msg_ret("bit", -E2BIG);
586
587 for (i = 0; i < obj->bit_length; i++, seq >>= 1) {
588 uint bitnum = obj->start_bit + i;
589
590 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
591 if (seq & 1)
592 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
593 log_debug("bit %x %x %x\n", bitnum,
594 priv->mask[CMOS_BYTE(bitnum)],
595 priv->value[CMOS_BYTE(bitnum)]);
596 }
597
598 return 0;
599}
600
601int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
602 bool verbose)
603{
604 struct cedit_iter_priv priv;
605 int ret, i, count, first, last;
606
607 /* write out the items */
608 priv.mask = calloc(1, CMOS_MAX_BYTES);
609 if (!priv.mask)
610 return log_msg_ret("mas", -ENOMEM);
611 priv.value = calloc(1, CMOS_MAX_BYTES);
612 if (!priv.value) {
613 free(priv.mask);
614 return log_msg_ret("val", -ENOMEM);
615 }
616
617 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
618 if (ret) {
619 log_debug("Failed to write CMOS (err=%d)\n", ret);
620 ret = log_msg_ret("set", ret);
621 goto done;
622 }
623
624 /* write the data to the RTC */
625 first = CMOS_MAX_BYTES;
626 last = -1;
627 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
628 if (priv.mask[i]) {
629 log_debug("Write byte %x: %x\n", i, priv.value[i]);
630 ret = rtc_write8(dev, i, priv.value[i]);
631 if (ret) {
632 ret = log_msg_ret("wri", ret);
633 goto done;
634 }
635 count++;
636 first = min(first, i);
637 last = max(last, i);
638 }
639 }
640 if (verbose) {
641 printf("Write %d bytes from offset %x to %x\n", count, first,
642 last);
643 }
644
645done:
646 free(priv.mask);
647 free(priv.value);
648 return ret;
649}
Simon Glasscfc402d2023-08-14 16:40:38 -0600650
651static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
652{
653 struct cedit_iter_priv *priv = vpriv;
654 const struct scene_menitem *mi;
655 struct scene_obj_menu *menu;
656 int val, ret;
657 uint i;
658
659 if (obj->type != SCENEOBJT_MENU)
660 return 0;
661
662 menu = (struct scene_obj_menu *)obj;
663
664 /* figure out where to place this item */
665 if (!obj->bit_length)
666 return log_msg_ret("len", -EINVAL);
667 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
668 return log_msg_ret("bit", -E2BIG);
669
670 val = 0;
671 for (i = 0; i < obj->bit_length; i++) {
672 uint bitnum = obj->start_bit + i;
673 uint offset = CMOS_BYTE(bitnum);
674
675 /* read the byte if not already read */
676 if (!priv->mask[offset]) {
677 ret = rtc_read8(priv->dev, offset);
678 if (ret < 0)
679 return log_msg_ret("rea", ret);
680 priv->value[offset] = ret;
681
682 /* mark it as read */
683 priv->mask[offset] = 0xff;
684 }
685
686 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
687 val |= BIT(i);
688 log_debug("bit %x %x\n", bitnum, val);
689 }
690
691 /* update the current item */
692 mi = scene_menuitem_find_seq(menu, val);
693 if (!mi)
694 return log_msg_ret("seq", -ENOENT);
695
696 menu->cur_item_id = mi->id;
697 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
698
699 return 0;
700}
701
702int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
703 bool verbose)
704{
705 struct cedit_iter_priv priv;
706 int ret, i, count, first, last;
707
708 /* read in the items */
709 priv.mask = calloc(1, CMOS_MAX_BYTES);
710 if (!priv.mask)
711 return log_msg_ret("mas", -ENOMEM);
712 priv.value = calloc(1, CMOS_MAX_BYTES);
713 if (!priv.value) {
714 free(priv.mask);
715 return log_msg_ret("val", -ENOMEM);
716 }
717 priv.dev = dev;
718
719 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
720 if (ret) {
721 log_debug("Failed to read CMOS (err=%d)\n", ret);
722 ret = log_msg_ret("set", ret);
723 goto done;
724 }
725
726 /* read the data to the RTC */
727 first = CMOS_MAX_BYTES;
728 last = -1;
729 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
730 if (priv.mask[i]) {
731 log_debug("Read byte %x: %x\n", i, priv.value[i]);
732 count++;
733 first = min(first, i);
734 last = max(last, i);
735 }
736 }
737 if (verbose) {
738 printf("Read %d bytes from offset %x to %x\n", count, first,
739 last);
740 }
741
742done:
743 free(priv.mask);
744 free(priv.value);
745 return ret;
746}