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