]> Git Repo - J-u-boot.git/blame - boot/cedit.c
ddr: altera: include u-boot/schedule.h
[J-u-boot.git] / boot / cedit.c
CommitLineData
a0874dc4
SG
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Implementation of configuration editor
4 *
5 * Copyright 2023 Google LLC
6 * Written by Simon Glass <[email protected]>
7 */
8
8d0f890a
SG
9#define LOG_CATEGORY LOGC_EXPO
10
2dee81fe 11#include <abuf.h>
040b0468 12#include <cedit.h>
a0874dc4
SG
13#include <cli.h>
14#include <dm.h>
fc9c0e07 15#include <env.h>
a0874dc4 16#include <expo.h>
eb6c71b5 17#include <malloc.h>
a0874dc4 18#include <menu.h>
eb6c71b5 19#include <rtc.h>
a0874dc4
SG
20#include <video.h>
21#include <linux/delay.h>
22#include "scene_internal.h"
23
eb6c71b5
SG
24enum {
25 CMOS_MAX_BITS = 2048,
26 CMOS_MAX_BYTES = CMOS_MAX_BITS / 8,
27};
28
29#define CMOS_BYTE(bit) ((bit) / 8)
30#define CMOS_BIT(bit) ((bit) % 8)
31
2dee81fe
SG
32/**
33 * struct cedit_iter_priv - private data for cedit operations
34 *
35 * @buf: Buffer to use when writing settings to the devicetree
472317cb 36 * @node: Node to read from when reading settings from devicetree
fc9c0e07 37 * @verbose: true to show writing to environment variables
eb6c71b5
SG
38 * @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it
39 * will be written
40 * @value: Value bits for CMOS RAM. This is the actual value written
cfc402db 41 * @dev: RTC device to write to
2dee81fe
SG
42 */
43struct cedit_iter_priv {
44 struct abuf *buf;
472317cb 45 ofnode node;
fc9c0e07 46 bool verbose;
eb6c71b5
SG
47 u8 *mask;
48 u8 *value;
cfc402db 49 struct udevice *dev;
2dee81fe
SG
50};
51
a0874dc4
SG
52int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
53{
54eca1d3 54 struct expo_arrange_info arr;
a0874dc4
SG
55 struct scene_obj_txt *txt;
56 struct scene_obj *obj;
57 struct scene *scn;
54eca1d3 58 int y, ret;
a0874dc4
SG
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
54eca1d3
SG
72 memset(&arr, '\0', sizeof(arr));
73 ret = scene_calc_arrange(scn, &arr);
74 if (ret < 0)
75 return log_msg_ret("arr", ret);
76
a0874dc4
SG
77 y = 100;
78 list_for_each_entry(obj, &scn->obj_head, sibling) {
fd6073ac
SG
79 switch (obj->type) {
80 case SCENEOBJT_NONE:
81 case SCENEOBJT_IMAGE:
82 case SCENEOBJT_TEXT:
83 break;
84 case SCENEOBJT_MENU:
a0874dc4 85 scene_obj_set_pos(scn, obj->id, 50, y);
54eca1d3
SG
86 scene_menu_arrange(scn, &arr,
87 (struct scene_obj_menu *)obj);
a0874dc4 88 y += 50;
fd6073ac 89 break;
fe553660
SG
90 case SCENEOBJT_TEXTLINE:
91 scene_obj_set_pos(scn, obj->id, 50, y);
54eca1d3 92 scene_textline_arrange(scn, &arr,
fe553660
SG
93 (struct scene_obj_textline *)obj);
94 y += 50;
95 break;
a0874dc4
SG
96 }
97 }
98
99 return 0;
100}
101
8d0f890a
SG
102int cedit_prepare(struct expo *exp, struct video_priv **vid_privp,
103 struct scene **scnp)
a0874dc4 104{
a0874dc4 105 struct video_priv *vid_priv;
a0874dc4
SG
106 struct udevice *dev;
107 struct scene *scn;
8d0f890a 108 uint scene_id;
a0874dc4
SG
109 int ret;
110
a0874dc4
SG
111 /* For now we only support a video console */
112 ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
113 if (ret)
114 return log_msg_ret("vid", ret);
115 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
8d0f890a
SG
145 *vid_privp = vid_priv;
146 *scnp = scn;
147
148 return scene_id;
149}
150
151int cedit_run(struct expo *exp)
152{
153 struct cli_ch_state s_cch, *cch = &s_cch;
154 struct video_priv *vid_priv;
155 uint scene_id;
156 struct scene *scn;
d8ff97ce 157 bool done, save;
8d0f890a
SG
158 int ret;
159
160 cli_ch_init(cch);
161 ret = cedit_prepare(exp, &vid_priv, &scn);
162 if (ret < 0)
163 return log_msg_ret("prep", ret);
164 scene_id = ret;
165
a0874dc4 166 done = false;
d8ff97ce 167 save = false;
a0874dc4
SG
168 do {
169 struct expo_action act;
170 int ichar, key;
171
172 ret = expo_render(exp);
173 if (ret)
174 break;
175
176 ichar = cli_ch_process(cch, 0);
177 if (!ichar) {
178 while (!ichar && !tstc()) {
179 schedule();
180 mdelay(2);
181 ichar = cli_ch_process(cch, -ETIMEDOUT);
182 }
183 if (!ichar) {
184 ichar = getchar();
185 ichar = cli_ch_process(cch, ichar);
186 }
187 }
188
189 key = 0;
190 if (ichar) {
191 key = bootmenu_conv_key(ichar);
8579cb01 192 if (key == BKEY_NONE || key >= BKEY_FIRST_EXTRA)
a0874dc4
SG
193 key = ichar;
194 }
195 if (!key)
196 continue;
197
198 ret = expo_send_key(exp, key);
199 if (ret)
200 break;
201
202 ret = expo_action_get(exp, &act);
203 if (!ret) {
204 switch (act.type) {
205 case EXPOACT_POINT_OBJ:
206 scene_set_highlight_id(scn, act.select.id);
207 cedit_arange(exp, vid_priv, scene_id);
208 break;
209 case EXPOACT_OPEN:
210 scene_set_open(scn, act.select.id, true);
211 cedit_arange(exp, vid_priv, scene_id);
d8ff97ce
SG
212 switch (scn->highlight_id) {
213 case EXPOID_SAVE:
214 done = true;
215 save = true;
216 break;
217 case EXPOID_DISCARD:
218 done = true;
219 break;
220 }
a0874dc4
SG
221 break;
222 case EXPOACT_CLOSE:
223 scene_set_open(scn, act.select.id, false);
224 cedit_arange(exp, vid_priv, scene_id);
225 break;
226 case EXPOACT_SELECT:
227 scene_set_open(scn, scn->highlight_id, false);
228 cedit_arange(exp, vid_priv, scene_id);
229 break;
230 case EXPOACT_QUIT:
231 log_debug("quitting\n");
232 done = true;
233 break;
234 default:
235 break;
236 }
237 }
238 } while (!done);
239
240 if (ret)
241 return log_msg_ret("end", ret);
d8ff97ce
SG
242 if (!save)
243 return -EACCES;
a0874dc4
SG
244
245 return 0;
246}
2dee81fe
SG
247
248static int check_space(int ret, struct abuf *buf)
249{
250 if (ret == -FDT_ERR_NOSPACE) {
251 if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
252 return log_msg_ret("spc", -ENOMEM);
253 ret = fdt_resize(abuf_data(buf), abuf_data(buf),
254 abuf_size(buf));
255 if (ret)
256 return log_msg_ret("res", -EFAULT);
257 }
258
259 return 0;
260}
261
909c486d
SG
262/**
263 * get_cur_menuitem_text() - Get the text of the currently selected item
264 *
265 * Looks up the object for the current item, finds text object for it and looks
266 * up the string for that text
267 *
268 * @menu: Menu to look at
269 * @strp: Returns a pointer to the next
270 * Return: 0 if OK, -ENOENT if something was not found
271 */
fc9c0e07
SG
272static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
273 const char **strp)
274{
275 struct scene *scn = menu->obj.scene;
276 const struct scene_menitem *mi;
277 const struct scene_obj_txt *txt;
278 const char *str;
279
280 mi = scene_menuitem_find(menu, menu->cur_item_id);
281 if (!mi)
282 return log_msg_ret("mi", -ENOENT);
283
284 txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
285 if (!txt)
286 return log_msg_ret("txt", -ENOENT);
287
288 str = expo_get_str(scn->expo, txt->str_id);
289 if (!str)
290 return log_msg_ret("str", -ENOENT);
291 *strp = str;
292
293 return 0;
294}
295
55a9de57
SG
296/**
297 * get_cur_menuitem_val() - Get the value of a menu's current item
298 *
299 * Obtains the value of the current item in the menu. If no value, then
300 * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
301 * the currently selected item. If the first item is selected, this returns 0;
302 * if the second, 1; etc.
303 *
304 * @menu: Menu to check
305 * @valp: Returns current-item value / sequence number
306 * Return: 0 on success, else -ve error value
307 */
308static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
309{
310 const struct scene_menitem *mi;
311 int seq;
312
313 seq = 0;
314 list_for_each_entry(mi, &menu->item_head, sibling) {
315 if (mi->id == menu->cur_item_id) {
316 *valp = mi->value == INT_MAX ? seq : mi->value;
317 return 0;
318 }
319 seq++;
320 }
321
322 return log_msg_ret("nf", -ENOENT);
323}
324
325/**
326 * write_dt_string() - Write a string to the devicetree, expanding if needed
327 *
328 * If this fails, it tries again after expanding the devicetree a little
329 *
330 * @buf: Buffer containing the devicetree
331 * @name: Property name to use
332 * @str: String value
333 * Return: 0 if OK, -EFAULT if something went horribly wrong
334 */
117617c7
SG
335static int write_dt_string(struct abuf *buf, const char *name, const char *str)
336{
337 int ret, i;
338
117617c7
SG
339 ret = -EAGAIN;
340 for (i = 0; ret && i < 2; i++) {
341 ret = fdt_property_string(abuf_data(buf), name, str);
342 if (!i) {
343 ret = check_space(ret, buf);
344 if (ret)
345 return log_msg_ret("rs2", -ENOMEM);
346 }
347 }
348
349 /* this should not happen */
350 if (ret)
351 return log_msg_ret("str", -EFAULT);
352
353 return 0;
354}
355
55a9de57
SG
356/**
357 * write_dt_u32() - Write an int to the devicetree, expanding if needed
358 *
359 * If this fails, it tries again after expanding the devicetree a little
360 *
361 * @buf: Buffer containing the devicetree
362 * @name: Property name to use
363 * @lva: Integer value
364 * Return: 0 if OK, -EFAULT if something went horribly wrong
365 */
366static int write_dt_u32(struct abuf *buf, const char *name, uint val)
367{
368 int ret, i;
369
370 /* write the text of the current item */
371 ret = -EAGAIN;
372 for (i = 0; ret && i < 2; i++) {
373 ret = fdt_property_u32(abuf_data(buf), name, val);
374 if (!i) {
375 ret = check_space(ret, buf);
376 if (ret)
377 return log_msg_ret("rs2", -ENOMEM);
378 }
379 }
380
381 /* this should not happen */
382 if (ret)
383 return log_msg_ret("str", -EFAULT);
384
385 return 0;
386}
387
2dee81fe
SG
388static int h_write_settings(struct scene_obj *obj, void *vpriv)
389{
390 struct cedit_iter_priv *priv = vpriv;
391 struct abuf *buf = priv->buf;
fe553660 392 int ret;
2dee81fe
SG
393
394 switch (obj->type) {
395 case SCENEOBJT_NONE:
396 case SCENEOBJT_IMAGE:
397 case SCENEOBJT_TEXT:
398 break;
fe553660
SG
399 case SCENEOBJT_TEXTLINE: {
400 const struct scene_obj_textline *tline;
401
402 tline = (struct scene_obj_textline *)obj;
403 ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf));
404 if (ret)
405 return log_msg_ret("wr2", ret);
406 break;
407 }
2dee81fe
SG
408 case SCENEOBJT_MENU: {
409 const struct scene_obj_menu *menu;
2dee81fe
SG
410 const char *str;
411 char name[80];
55a9de57 412 int val;
2dee81fe 413
117617c7 414 /* write the ID of the current item */
2dee81fe 415 menu = (struct scene_obj_menu *)obj;
55a9de57 416 ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
2dee81fe 417 if (ret)
55a9de57
SG
418 return log_msg_ret("wrt", ret);
419
420 snprintf(name, sizeof(name), "%s-value", obj->name);
421 ret = get_cur_menuitem_val(menu, &val);
422 if (ret < 0)
423 return log_msg_ret("cur", ret);
424 ret = write_dt_u32(buf, name, val);
425 if (ret)
426 return log_msg_ret("wr2", ret);
2dee81fe 427
fc9c0e07
SG
428 ret = get_cur_menuitem_text(menu, &str);
429 if (ret)
430 return log_msg_ret("mis", ret);
2dee81fe 431
117617c7 432 /* write the text of the current item */
2dee81fe 433 snprintf(name, sizeof(name), "%s-str", obj->name);
117617c7 434 ret = write_dt_string(buf, name, str);
2dee81fe 435 if (ret)
117617c7 436 return log_msg_ret("wr2", ret);
2dee81fe
SG
437
438 break;
439 }
440 }
441
442 return 0;
443}
444
445int cedit_write_settings(struct expo *exp, struct abuf *buf)
446{
447 struct cedit_iter_priv priv;
448 void *fdt;
449 int ret;
450
451 abuf_init(buf);
452 if (!abuf_realloc(buf, CEDIT_SIZE_INC))
453 return log_msg_ret("buf", -ENOMEM);
454
455 fdt = abuf_data(buf);
456 ret = fdt_create(fdt, abuf_size(buf));
457 if (!ret)
458 ret = fdt_finish_reservemap(fdt);
459 if (!ret)
460 ret = fdt_begin_node(fdt, "");
461 if (!ret)
462 ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
463 if (ret) {
464 log_debug("Failed to start FDT (err=%d)\n", ret);
465 return log_msg_ret("sta", -EINVAL);
466 }
467
468 /* write out the items */
469 priv.buf = buf;
470 ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
471 if (ret) {
472 log_debug("Failed to write settings (err=%d)\n", ret);
473 return log_msg_ret("set", ret);
474 }
475
476 ret = fdt_end_node(fdt);
477 if (!ret)
478 ret = fdt_end_node(fdt);
479 if (!ret)
480 ret = fdt_finish(fdt);
481 if (ret) {
482 log_debug("Failed to finish FDT (err=%d)\n", ret);
483 return log_msg_ret("fin", -EINVAL);
484 }
485
486 return 0;
487}
472317cb
SG
488
489static int h_read_settings(struct scene_obj *obj, void *vpriv)
490{
491 struct cedit_iter_priv *priv = vpriv;
492 ofnode node = priv->node;
493
494 switch (obj->type) {
495 case SCENEOBJT_NONE:
496 case SCENEOBJT_IMAGE:
497 case SCENEOBJT_TEXT:
498 break;
fe553660
SG
499 case SCENEOBJT_TEXTLINE: {
500 const struct scene_obj_textline *tline;
501 const char *val;
502 int len;
503
504 tline = (struct scene_obj_textline *)obj;
505
506 val = ofnode_read_prop(node, obj->name, &len);
507 if (len >= tline->max_chars)
508 return log_msg_ret("str", -ENOSPC);
509 strcpy(abuf_data(&tline->buf), val);
510 break;
511 }
472317cb
SG
512 case SCENEOBJT_MENU: {
513 struct scene_obj_menu *menu;
514 uint val;
515
516 if (ofnode_read_u32(node, obj->name, &val))
517 return log_msg_ret("rd", -ENOENT);
518 menu = (struct scene_obj_menu *)obj;
519 menu->cur_item_id = val;
520
521 break;
522 }
523 }
524
525 return 0;
526}
527
528int cedit_read_settings(struct expo *exp, oftree tree)
529{
530 struct cedit_iter_priv priv;
531 ofnode root, node;
532 int ret;
533
534 root = oftree_root(tree);
535 if (!ofnode_valid(root))
536 return log_msg_ret("roo", -ENOENT);
537 node = ofnode_find_subnode(root, CEDIT_NODE_NAME);
538 if (!ofnode_valid(node))
539 return log_msg_ret("pat", -ENOENT);
540
541 /* read in the items */
542 priv.node = node;
543 ret = expo_iter_scene_objs(exp, h_read_settings, &priv);
544 if (ret) {
545 log_debug("Failed to read settings (err=%d)\n", ret);
546 return log_msg_ret("set", ret);
547 }
548
549 return 0;
550}
fc9c0e07
SG
551
552static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
553{
554 const struct scene_obj_menu *menu;
555 struct cedit_iter_priv *priv = vpriv;
556 char name[80], var[60];
557 const char *str;
558 int val, ret;
559
d8ff97ce
SG
560 if (obj->id < EXPOID_BASE_ID)
561 return 0;
562
fc9c0e07
SG
563 snprintf(var, sizeof(var), "c.%s", obj->name);
564
fd6073ac
SG
565 switch (obj->type) {
566 case SCENEOBJT_NONE:
567 case SCENEOBJT_IMAGE:
568 case SCENEOBJT_TEXT:
569 break;
570 case SCENEOBJT_MENU:
571 menu = (struct scene_obj_menu *)obj;
572 val = menu->cur_item_id;
fc9c0e07 573
fd6073ac
SG
574 if (priv->verbose)
575 printf("%s=%d\n", var, val);
fc9c0e07 576
fd6073ac
SG
577 ret = env_set_ulong(var, val);
578 if (ret)
579 return log_msg_ret("set", ret);
fc9c0e07 580
fd6073ac
SG
581 ret = get_cur_menuitem_text(menu, &str);
582 if (ret)
583 return log_msg_ret("mis", ret);
fc9c0e07 584
fd6073ac
SG
585 snprintf(name, sizeof(name), "c.%s-str", obj->name);
586 if (priv->verbose)
587 printf("%s=%s\n", name, str);
588
589 ret = env_set(name, str);
590 if (ret)
591 return log_msg_ret("st2", ret);
55a9de57
SG
592
593 ret = get_cur_menuitem_val(menu, &val);
594 if (ret < 0)
595 return log_msg_ret("cur", ret);
596 snprintf(name, sizeof(name), "c.%s-value", obj->name);
597 if (priv->verbose)
598 printf("%s=%d\n", name, val);
599
fd6073ac 600 break;
fe553660
SG
601 case SCENEOBJT_TEXTLINE: {
602 const struct scene_obj_textline *tline;
603
604 tline = (struct scene_obj_textline *)obj;
605 str = abuf_data(&tline->buf);
606 ret = env_set(var, str);
607 if (ret)
608 return log_msg_ret("set", ret);
609
610 if (priv->verbose)
611 printf("%s=%s\n", var, str);
612
613 break;
614 }
fd6073ac 615 }
fc9c0e07
SG
616
617 return 0;
618}
619
620int cedit_write_settings_env(struct expo *exp, bool verbose)
621{
622 struct cedit_iter_priv priv;
623 int ret;
624
625 /* write out the items */
626 priv.verbose = verbose;
627 ret = expo_iter_scene_objs(exp, h_write_settings_env, &priv);
628 if (ret) {
629 log_debug("Failed to write settings to env (err=%d)\n", ret);
630 return log_msg_ret("set", ret);
631 }
632
633 return 0;
634}
bcf2b720
SG
635
636static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
637{
638 struct cedit_iter_priv *priv = vpriv;
639 struct scene_obj_menu *menu;
640 char var[60];
eb6c71b5 641 int val;
bcf2b720 642
d8ff97ce
SG
643 if (obj->id < EXPOID_BASE_ID)
644 return 0;
645
bcf2b720
SG
646 snprintf(var, sizeof(var), "c.%s", obj->name);
647
fd6073ac
SG
648 switch (obj->type) {
649 case SCENEOBJT_NONE:
650 case SCENEOBJT_IMAGE:
651 case SCENEOBJT_TEXT:
652 break;
653 case SCENEOBJT_MENU:
654 menu = (struct scene_obj_menu *)obj;
655 val = env_get_ulong(var, 10, 0);
656 if (priv->verbose)
657 printf("%s=%d\n", var, val);
658 if (!val)
659 return log_msg_ret("get", -ENOENT);
660
661 /*
662 * note that no validation is done here, to make sure the ID is
f698786c 663 * valid and actually points to a menu item
fd6073ac
SG
664 */
665 menu->cur_item_id = val;
666 break;
fe553660
SG
667 case SCENEOBJT_TEXTLINE: {
668 const struct scene_obj_textline *tline;
669 const char *value;
670
671 tline = (struct scene_obj_textline *)obj;
672 value = env_get(var);
673 if (value && strlen(value) >= tline->max_chars)
674 return log_msg_ret("str", -ENOSPC);
675 if (!value)
676 value = "";
677 if (priv->verbose)
678 printf("%s=%s\n", var, value);
679 strcpy(abuf_data(&tline->buf), value);
680 break;
681 }
fd6073ac 682 }
bcf2b720
SG
683
684 return 0;
685}
686
687int cedit_read_settings_env(struct expo *exp, bool verbose)
688{
689 struct cedit_iter_priv priv;
690 int ret;
691
692 /* write out the items */
693 priv.verbose = verbose;
694 ret = expo_iter_scene_objs(exp, h_read_settings_env, &priv);
695 if (ret) {
696 log_debug("Failed to read settings from env (err=%d)\n", ret);
697 return log_msg_ret("set", ret);
698 }
699
700 return 0;
701}
eb6c71b5 702
eb6c71b5
SG
703static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
704{
705 const struct scene_obj_menu *menu;
706 struct cedit_iter_priv *priv = vpriv;
707 int val, ret;
55a9de57 708 uint i;
eb6c71b5 709
d8ff97ce 710 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
eb6c71b5
SG
711 return 0;
712
713 menu = (struct scene_obj_menu *)obj;
714 val = menu->cur_item_id;
715
55a9de57 716 ret = get_cur_menuitem_val(menu, &val);
eb6c71b5
SG
717 if (ret < 0)
718 return log_msg_ret("cur", ret);
55a9de57 719 log_debug("%s: val=%d\n", menu->obj.name, val);
eb6c71b5
SG
720
721 /* figure out where to place this item */
722 if (!obj->bit_length)
723 return log_msg_ret("len", -EINVAL);
724 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
725 return log_msg_ret("bit", -E2BIG);
726
55a9de57 727 for (i = 0; i < obj->bit_length; i++, val >>= 1) {
eb6c71b5
SG
728 uint bitnum = obj->start_bit + i;
729
730 priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
55a9de57 731 if (val & 1)
eb6c71b5
SG
732 priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
733 log_debug("bit %x %x %x\n", bitnum,
734 priv->mask[CMOS_BYTE(bitnum)],
735 priv->value[CMOS_BYTE(bitnum)]);
736 }
737
738 return 0;
739}
740
741int cedit_write_settings_cmos(struct expo *exp, struct udevice *dev,
742 bool verbose)
743{
744 struct cedit_iter_priv priv;
745 int ret, i, count, first, last;
746
747 /* write out the items */
748 priv.mask = calloc(1, CMOS_MAX_BYTES);
749 if (!priv.mask)
750 return log_msg_ret("mas", -ENOMEM);
751 priv.value = calloc(1, CMOS_MAX_BYTES);
752 if (!priv.value) {
753 free(priv.mask);
754 return log_msg_ret("val", -ENOMEM);
755 }
756
757 ret = expo_iter_scene_objs(exp, h_write_settings_cmos, &priv);
758 if (ret) {
759 log_debug("Failed to write CMOS (err=%d)\n", ret);
760 ret = log_msg_ret("set", ret);
761 goto done;
762 }
763
764 /* write the data to the RTC */
f698786c 765 log_debug("Writing CMOS\n");
eb6c71b5
SG
766 first = CMOS_MAX_BYTES;
767 last = -1;
768 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
769 if (priv.mask[i]) {
770 log_debug("Write byte %x: %x\n", i, priv.value[i]);
771 ret = rtc_write8(dev, i, priv.value[i]);
772 if (ret) {
773 ret = log_msg_ret("wri", ret);
774 goto done;
775 }
776 count++;
777 first = min(first, i);
778 last = max(last, i);
779 }
780 }
781 if (verbose) {
782 printf("Write %d bytes from offset %x to %x\n", count, first,
783 last);
784 }
785
786done:
787 free(priv.mask);
788 free(priv.value);
789 return ret;
790}
cfc402db
SG
791
792static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
793{
794 struct cedit_iter_priv *priv = vpriv;
795 const struct scene_menitem *mi;
796 struct scene_obj_menu *menu;
797 int val, ret;
798 uint i;
799
d8ff97ce 800 if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
cfc402db
SG
801 return 0;
802
803 menu = (struct scene_obj_menu *)obj;
804
805 /* figure out where to place this item */
806 if (!obj->bit_length)
807 return log_msg_ret("len", -EINVAL);
808 if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
809 return log_msg_ret("bit", -E2BIG);
810
811 val = 0;
812 for (i = 0; i < obj->bit_length; i++) {
813 uint bitnum = obj->start_bit + i;
814 uint offset = CMOS_BYTE(bitnum);
815
816 /* read the byte if not already read */
817 if (!priv->mask[offset]) {
818 ret = rtc_read8(priv->dev, offset);
819 if (ret < 0)
820 return log_msg_ret("rea", ret);
821 priv->value[offset] = ret;
822
823 /* mark it as read */
824 priv->mask[offset] = 0xff;
825 }
826
827 if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
828 val |= BIT(i);
829 log_debug("bit %x %x\n", bitnum, val);
830 }
831
832 /* update the current item */
f698786c 833 log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
55a9de57 834 mi = scene_menuitem_find_val(menu, val);
cfc402db
SG
835 if (!mi)
836 return log_msg_ret("seq", -ENOENT);
837
838 menu->cur_item_id = mi->id;
839 log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
840
841 return 0;
842}
843
844int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
845 bool verbose)
846{
847 struct cedit_iter_priv priv;
848 int ret, i, count, first, last;
849
850 /* read in the items */
851 priv.mask = calloc(1, CMOS_MAX_BYTES);
852 if (!priv.mask)
853 return log_msg_ret("mas", -ENOMEM);
854 priv.value = calloc(1, CMOS_MAX_BYTES);
855 if (!priv.value) {
856 free(priv.mask);
857 return log_msg_ret("val", -ENOMEM);
858 }
859 priv.dev = dev;
860
861 ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
862 if (ret) {
863 log_debug("Failed to read CMOS (err=%d)\n", ret);
864 ret = log_msg_ret("set", ret);
865 goto done;
866 }
867
f698786c 868 /* indicate what bytes were read from the RTC */
cfc402db
SG
869 first = CMOS_MAX_BYTES;
870 last = -1;
871 for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
872 if (priv.mask[i]) {
873 log_debug("Read byte %x: %x\n", i, priv.value[i]);
874 count++;
875 first = min(first, i);
876 last = max(last, i);
877 }
878 }
879 if (verbose) {
880 printf("Read %d bytes from offset %x to %x\n", count, first,
881 last);
882 }
883
884done:
885 free(priv.mask);
886 free(priv.value);
887 return ret;
888}
This page took 0.197522 seconds and 4 git commands to generate.