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