expo: Support menu-item values in cedit
Update the cedit read/write functions to support menu items with
values.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/boot/cedit.c b/boot/cedit.c
index 9d48d3e..d12892f 100644
--- a/boot/cedit.c
+++ b/boot/cedit.c
@@ -293,11 +293,49 @@
return 0;
}
+/**
+ * get_cur_menuitem_val() - Get the value of a menu's current item
+ *
+ * Obtains the value of the current item in the menu. If no value, then
+ * enumerates the items of a menu (0, 1, 2) and returns the sequence number of
+ * the currently selected item. If the first item is selected, this returns 0;
+ * if the second, 1; etc.
+ *
+ * @menu: Menu to check
+ * @valp: Returns current-item value / sequence number
+ * Return: 0 on success, else -ve error value
+ */
+static int get_cur_menuitem_val(const struct scene_obj_menu *menu, int *valp)
+{
+ const struct scene_menitem *mi;
+ int seq;
+
+ seq = 0;
+ list_for_each_entry(mi, &menu->item_head, sibling) {
+ if (mi->id == menu->cur_item_id) {
+ *valp = mi->value == INT_MAX ? seq : mi->value;
+ return 0;
+ }
+ seq++;
+ }
+
+ return log_msg_ret("nf", -ENOENT);
+}
+
+/**
+ * write_dt_string() - Write a string to the devicetree, expanding if needed
+ *
+ * If this fails, it tries again after expanding the devicetree a little
+ *
+ * @buf: Buffer containing the devicetree
+ * @name: Property name to use
+ * @str: String value
+ * Return: 0 if OK, -EFAULT if something went horribly wrong
+ */
static int write_dt_string(struct abuf *buf, const char *name, const char *str)
{
int ret, i;
- /* write the text of the current item */
ret = -EAGAIN;
for (i = 0; ret && i < 2; i++) {
ret = fdt_property_string(abuf_data(buf), name, str);
@@ -315,6 +353,38 @@
return 0;
}
+/**
+ * write_dt_u32() - Write an int to the devicetree, expanding if needed
+ *
+ * If this fails, it tries again after expanding the devicetree a little
+ *
+ * @buf: Buffer containing the devicetree
+ * @name: Property name to use
+ * @lva: Integer value
+ * Return: 0 if OK, -EFAULT if something went horribly wrong
+ */
+static int write_dt_u32(struct abuf *buf, const char *name, uint val)
+{
+ int ret, i;
+
+ /* write the text of the current item */
+ ret = -EAGAIN;
+ for (i = 0; ret && i < 2; i++) {
+ ret = fdt_property_u32(abuf_data(buf), name, val);
+ if (!i) {
+ ret = check_space(ret, buf);
+ if (ret)
+ return log_msg_ret("rs2", -ENOMEM);
+ }
+ }
+
+ /* this should not happen */
+ if (ret)
+ return log_msg_ret("str", -EFAULT);
+
+ return 0;
+}
+
static int h_write_settings(struct scene_obj *obj, void *vpriv)
{
struct cedit_iter_priv *priv = vpriv;
@@ -339,23 +409,21 @@
const struct scene_obj_menu *menu;
const char *str;
char name[80];
- int i;
+ int val;
/* write the ID of the current item */
menu = (struct scene_obj_menu *)obj;
- ret = -EAGAIN;
- for (i = 0; ret && i < 2; i++) {
- ret = fdt_property_u32(abuf_data(buf), obj->name,
- menu->cur_item_id);
- if (!i) {
- ret = check_space(ret, buf);
- if (ret)
- return log_msg_ret("res", -ENOMEM);
- }
- }
- /* this should not happen */
+ ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
if (ret)
- return log_msg_ret("wrt", -EFAULT);
+ return log_msg_ret("wrt", ret);
+
+ snprintf(name, sizeof(name), "%s-value", obj->name);
+ ret = get_cur_menuitem_val(menu, &val);
+ if (ret < 0)
+ return log_msg_ret("cur", ret);
+ ret = write_dt_u32(buf, name, val);
+ if (ret)
+ return log_msg_ret("wr2", ret);
ret = get_cur_menuitem_text(menu, &str);
if (ret)
@@ -521,6 +589,14 @@
ret = env_set(name, str);
if (ret)
return log_msg_ret("st2", ret);
+
+ ret = get_cur_menuitem_val(menu, &val);
+ if (ret < 0)
+ return log_msg_ret("cur", ret);
+ snprintf(name, sizeof(name), "c.%s-value", obj->name);
+ if (priv->verbose)
+ printf("%s=%d\n", name, val);
+
break;
case SCENEOBJT_TEXTLINE: {
const struct scene_obj_textline *tline;
@@ -624,43 +700,12 @@
return 0;
}
-/**
- * get_cur_menuitem_seq() - Get the sequence number of a menu's current item
- *
- * Enumerates the items of a menu (0, 1, 2) and returns the sequence number of
- * the currently selected item. If the first item is selected, this returns 0;
- * if the second, 1; etc.
- *
- * @menu: Menu to check
- * Return: Sequence number on success, else -ve error value
- */
-static int get_cur_menuitem_seq(const struct scene_obj_menu *menu)
-{
- const struct scene_menitem *mi;
- int seq, found;
-
- seq = 0;
- found = -1;
- list_for_each_entry(mi, &menu->item_head, sibling) {
- if (mi->id == menu->cur_item_id) {
- found = seq;
- break;
- }
- seq++;
- }
-
- if (found == -1)
- return log_msg_ret("nf", -ENOENT);
-
- return found;
-}
-
static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
{
const struct scene_obj_menu *menu;
struct cedit_iter_priv *priv = vpriv;
int val, ret;
- uint i, seq;
+ uint i;
if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
return 0;
@@ -668,11 +713,10 @@
menu = (struct scene_obj_menu *)obj;
val = menu->cur_item_id;
- ret = get_cur_menuitem_seq(menu);
+ ret = get_cur_menuitem_val(menu, &val);
if (ret < 0)
return log_msg_ret("cur", ret);
- seq = ret;
- log_debug("%s: seq=%d\n", menu->obj.name, seq);
+ log_debug("%s: val=%d\n", menu->obj.name, val);
/* figure out where to place this item */
if (!obj->bit_length)
@@ -680,11 +724,11 @@
if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
return log_msg_ret("bit", -E2BIG);
- for (i = 0; i < obj->bit_length; i++, seq >>= 1) {
+ for (i = 0; i < obj->bit_length; i++, val >>= 1) {
uint bitnum = obj->start_bit + i;
priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
- if (seq & 1)
+ if (val & 1)
priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
log_debug("bit %x %x %x\n", bitnum,
priv->mask[CMOS_BYTE(bitnum)],
@@ -787,7 +831,7 @@
/* update the current item */
log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
- mi = scene_menuitem_find_seq(menu, val);
+ mi = scene_menuitem_find_val(menu, val);
if (!mi)
return log_msg_ret("seq", -ENOENT);
diff --git a/boot/scene_menu.c b/boot/scene_menu.c
index 04ff159..17150af 100644
--- a/boot/scene_menu.c
+++ b/boot/scene_menu.c
@@ -69,7 +69,7 @@
i = 0;
list_for_each_entry(item, &menu->item_head, sibling) {
- if (item->value == val)
+ if (item->value == INT_MAX ? val == i : item->value == val)
return item;
i++;
}
diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst
index 5670805..f29f1b3 100644
--- a/doc/usage/cmd/cedit.rst
+++ b/doc/usage/cmd/cedit.rst
@@ -107,8 +107,10 @@
/ {
cedit-values {
cpu-speed = <0x00000006>;
+ cpu-speed-value = <0x00000003>;
cpu-speed-str = "2 GHz";
power-loss = <0x0000000a>;
+ power-loss-value = <0x00000000>;
power-loss-str = "Always Off";
};
}
@@ -118,16 +120,23 @@
This shows settings being stored in the environment::
=> cedit write_env -v
- c.cpu-speed=7
+ c.cpu-speed=11
c.cpu-speed-str=2.5 GHz
- c.power-loss=12
- c.power-loss-str=Memory
+ c.cpu-speed-value=3
+ c.power-loss=14
+ c.power-loss-str=Always Off
+ c.power-loss-value=0
+ c.machine-name=my-machine
+ c.cpu-speed=11
+ c.power-loss=14
+ c.machine-name=my-machine
=> print
...
c.cpu-speed=6
c.cpu-speed-str=2 GHz
c.power-loss=10
c.power-loss-str=Always Off
+ c.machine-name=my-machine
...
=> cedit read_env -v
diff --git a/test/boot/cedit.c b/test/boot/cedit.c
index 0f2c2e7..4d1b99b 100644
--- a/test/boot/cedit.c
+++ b/test/boot/cedit.c
@@ -96,14 +96,16 @@
ut_asserteq(ID_CPU_SPEED_2,
ofnode_read_u32_default(node, "cpu-speed", 0));
+ ut_asserteq(3,
+ ofnode_read_u32_default(node, "cpu-speed-value", 0));
ut_asserteq_str("2.5 GHz", ofnode_read_string(node, "cpu-speed-str"));
ut_asserteq_str("my-machine", ofnode_read_string(node, "machine-name"));
- /* There should only be 5 properties */
+ /* There should only be 7 properties */
for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop);
i++, ofnode_next_property(&prop))
;
- ut_asserteq(5, i);
+ ut_asserteq(7, i);
ut_assert_console_end();
@@ -151,8 +153,10 @@
ut_assertok(run_command("cedit write_env -v", 0));
ut_assert_nextlinen("c.cpu-speed=11");
ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz");
+ ut_assert_nextlinen("c.cpu-speed-value=3");
ut_assert_nextlinen("c.power-loss=14");
ut_assert_nextlinen("c.power-loss-str=Always Off");
+ ut_assert_nextlinen("c.power-loss-value=0");
ut_assert_nextlinen("c.machine-name=my-machine");
ut_assert_console_end();
diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts
index ebe5adb..9bc1e49 100644
--- a/test/boot/files/expo_layout.dts
+++ b/test/boot/files/expo_layout.dts
@@ -40,10 +40,10 @@
ID_CPU_SPEED_3>;
/* values for the menu items */
- item-value = <(-1) 3 6>;
+ item-value = <0 3 6>;
start-bit = <0x400>;
- bit-length = <2>;
+ bit-length = <3>;
};
power-loss {