mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-23 05:08:24 +00:00
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>
This commit is contained in:
parent
f698786cff
commit
55a9de574c
5 changed files with 117 additions and 60 deletions
148
boot/cedit.c
148
boot/cedit.c
|
@ -293,14 +293,84 @@ static int get_cur_menuitem_text(const struct scene_obj_menu *menu,
|
||||||
return 0;
|
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)
|
static int write_dt_string(struct abuf *buf, const char *name, const char *str)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
ret = -EAGAIN;
|
||||||
|
for (i = 0; ret && i < 2; i++) {
|
||||||
|
ret = fdt_property_string(abuf_data(buf), name, str);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
/* write the text of the current item */
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
for (i = 0; ret && i < 2; i++) {
|
for (i = 0; ret && i < 2; i++) {
|
||||||
ret = fdt_property_string(abuf_data(buf), name, str);
|
ret = fdt_property_u32(abuf_data(buf), name, val);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
ret = check_space(ret, buf);
|
ret = check_space(ret, buf);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -339,23 +409,21 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv)
|
||||||
const struct scene_obj_menu *menu;
|
const struct scene_obj_menu *menu;
|
||||||
const char *str;
|
const char *str;
|
||||||
char name[80];
|
char name[80];
|
||||||
int i;
|
int val;
|
||||||
|
|
||||||
/* write the ID of the current item */
|
/* write the ID of the current item */
|
||||||
menu = (struct scene_obj_menu *)obj;
|
menu = (struct scene_obj_menu *)obj;
|
||||||
ret = -EAGAIN;
|
ret = write_dt_u32(buf, obj->name, menu->cur_item_id);
|
||||||
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 */
|
|
||||||
if (ret)
|
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);
|
ret = get_cur_menuitem_text(menu, &str);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -521,6 +589,14 @@ static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
|
||||||
ret = env_set(name, str);
|
ret = env_set(name, str);
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("st2", 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;
|
break;
|
||||||
case SCENEOBJT_TEXTLINE: {
|
case SCENEOBJT_TEXTLINE: {
|
||||||
const struct scene_obj_textline *tline;
|
const struct scene_obj_textline *tline;
|
||||||
|
@ -624,43 +700,12 @@ int cedit_read_settings_env(struct expo *exp, bool verbose)
|
||||||
return 0;
|
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)
|
static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
|
||||||
{
|
{
|
||||||
const struct scene_obj_menu *menu;
|
const struct scene_obj_menu *menu;
|
||||||
struct cedit_iter_priv *priv = vpriv;
|
struct cedit_iter_priv *priv = vpriv;
|
||||||
int val, ret;
|
int val, ret;
|
||||||
uint i, seq;
|
uint i;
|
||||||
|
|
||||||
if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
|
if (obj->type != SCENEOBJT_MENU || obj->id < EXPOID_BASE_ID)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -668,11 +713,10 @@ static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
|
||||||
menu = (struct scene_obj_menu *)obj;
|
menu = (struct scene_obj_menu *)obj;
|
||||||
val = menu->cur_item_id;
|
val = menu->cur_item_id;
|
||||||
|
|
||||||
ret = get_cur_menuitem_seq(menu);
|
ret = get_cur_menuitem_val(menu, &val);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return log_msg_ret("cur", ret);
|
return log_msg_ret("cur", ret);
|
||||||
seq = ret;
|
log_debug("%s: val=%d\n", menu->obj.name, val);
|
||||||
log_debug("%s: seq=%d\n", menu->obj.name, seq);
|
|
||||||
|
|
||||||
/* figure out where to place this item */
|
/* figure out where to place this item */
|
||||||
if (!obj->bit_length)
|
if (!obj->bit_length)
|
||||||
|
@ -680,11 +724,11 @@ static int h_write_settings_cmos(struct scene_obj *obj, void *vpriv)
|
||||||
if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
|
if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
|
||||||
return log_msg_ret("bit", -E2BIG);
|
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;
|
uint bitnum = obj->start_bit + i;
|
||||||
|
|
||||||
priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
|
priv->mask[CMOS_BYTE(bitnum)] |= 1 << CMOS_BIT(bitnum);
|
||||||
if (seq & 1)
|
if (val & 1)
|
||||||
priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
|
priv->value[CMOS_BYTE(bitnum)] |= BIT(CMOS_BIT(bitnum));
|
||||||
log_debug("bit %x %x %x\n", bitnum,
|
log_debug("bit %x %x %x\n", bitnum,
|
||||||
priv->mask[CMOS_BYTE(bitnum)],
|
priv->mask[CMOS_BYTE(bitnum)],
|
||||||
|
@ -787,7 +831,7 @@ static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
|
||||||
|
|
||||||
/* update the current item */
|
/* update the current item */
|
||||||
log_debug("look for menuitem value %d in menu %d\n", val, menu->obj.id);
|
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)
|
if (!mi)
|
||||||
return log_msg_ret("seq", -ENOENT);
|
return log_msg_ret("seq", -ENOENT);
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu *menu,
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
list_for_each_entry(item, &menu->item_head, sibling) {
|
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;
|
return item;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,10 @@ That results in::
|
||||||
/ {
|
/ {
|
||||||
cedit-values {
|
cedit-values {
|
||||||
cpu-speed = <0x00000006>;
|
cpu-speed = <0x00000006>;
|
||||||
|
cpu-speed-value = <0x00000003>;
|
||||||
cpu-speed-str = "2 GHz";
|
cpu-speed-str = "2 GHz";
|
||||||
power-loss = <0x0000000a>;
|
power-loss = <0x0000000a>;
|
||||||
|
power-loss-value = <0x00000000>;
|
||||||
power-loss-str = "Always Off";
|
power-loss-str = "Always Off";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -118,16 +120,23 @@ That results in::
|
||||||
This shows settings being stored in the environment::
|
This shows settings being stored in the environment::
|
||||||
|
|
||||||
=> cedit write_env -v
|
=> cedit write_env -v
|
||||||
c.cpu-speed=7
|
c.cpu-speed=11
|
||||||
c.cpu-speed-str=2.5 GHz
|
c.cpu-speed-str=2.5 GHz
|
||||||
c.power-loss=12
|
c.cpu-speed-value=3
|
||||||
c.power-loss-str=Memory
|
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
|
=> print
|
||||||
...
|
...
|
||||||
c.cpu-speed=6
|
c.cpu-speed=6
|
||||||
c.cpu-speed-str=2 GHz
|
c.cpu-speed-str=2 GHz
|
||||||
c.power-loss=10
|
c.power-loss=10
|
||||||
c.power-loss-str=Always Off
|
c.power-loss-str=Always Off
|
||||||
|
c.machine-name=my-machine
|
||||||
...
|
...
|
||||||
|
|
||||||
=> cedit read_env -v
|
=> cedit read_env -v
|
||||||
|
|
|
@ -96,14 +96,16 @@ static int cedit_fdt(struct unit_test_state *uts)
|
||||||
|
|
||||||
ut_asserteq(ID_CPU_SPEED_2,
|
ut_asserteq(ID_CPU_SPEED_2,
|
||||||
ofnode_read_u32_default(node, "cpu-speed", 0));
|
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("2.5 GHz", ofnode_read_string(node, "cpu-speed-str"));
|
||||||
ut_asserteq_str("my-machine", ofnode_read_string(node, "machine-name"));
|
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);
|
for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop);
|
||||||
i++, ofnode_next_property(&prop))
|
i++, ofnode_next_property(&prop))
|
||||||
;
|
;
|
||||||
ut_asserteq(5, i);
|
ut_asserteq(7, i);
|
||||||
|
|
||||||
ut_assert_console_end();
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
@ -151,8 +153,10 @@ static int cedit_env(struct unit_test_state *uts)
|
||||||
ut_assertok(run_command("cedit write_env -v", 0));
|
ut_assertok(run_command("cedit write_env -v", 0));
|
||||||
ut_assert_nextlinen("c.cpu-speed=11");
|
ut_assert_nextlinen("c.cpu-speed=11");
|
||||||
ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz");
|
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=14");
|
||||||
ut_assert_nextlinen("c.power-loss-str=Always Off");
|
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_nextlinen("c.machine-name=my-machine");
|
||||||
ut_assert_console_end();
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
ID_CPU_SPEED_3>;
|
ID_CPU_SPEED_3>;
|
||||||
|
|
||||||
/* values for the menu items */
|
/* values for the menu items */
|
||||||
item-value = <(-1) 3 6>;
|
item-value = <0 3 6>;
|
||||||
|
|
||||||
start-bit = <0x400>;
|
start-bit = <0x400>;
|
||||||
bit-length = <2>;
|
bit-length = <3>;
|
||||||
};
|
};
|
||||||
|
|
||||||
power-loss {
|
power-loss {
|
||||||
|
|
Loading…
Add table
Reference in a new issue