Commit 5644369450635fa5c2967bee55b1ac41f6e988d0
Exists in
master
and in
53 other branches
Merge branch 'agust@denx.de' of git://git.denx.de/u-boot-staging
Showing 10 changed files Side-by-side Diff
board/ait/cam_enc_4xx/cam_enc_4xx.c
... | ... | @@ -561,7 +561,8 @@ |
561 | 561 | char *s; |
562 | 562 | char temp[6][200]; |
563 | 563 | |
564 | - m = menu_create(display->title, display->timeout, 1, ait_menu_print); | |
564 | + m = menu_create(display->title, display->timeout, 1, ait_menu_print, | |
565 | + NULL, NULL); | |
565 | 566 | |
566 | 567 | for (i = 0; display->menulist[i]; i++) { |
567 | 568 | sprintf(key, "%d", i + 1); |
common/Makefile
... | ... | @@ -75,6 +75,7 @@ |
75 | 75 | COBJS-$(CONFIG_CMD_BDI) += cmd_bdinfo.o |
76 | 76 | COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o |
77 | 77 | COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o |
78 | +COBJS-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o | |
78 | 79 | COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o |
79 | 80 | COBJS-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o |
80 | 81 | COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o |
common/cmd_bootmenu.c
1 | +/* | |
2 | + * (C) Copyright 2011-2013 Pali Rohár <pali.rohar@gmail.com> | |
3 | + * | |
4 | + * See file CREDITS for list of people who contributed to this | |
5 | + * project. | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License as | |
9 | + * published by the Free Software Foundation; either version 2 of | |
10 | + * the License, or (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
20 | + * MA 02111-1307 USA | |
21 | + */ | |
22 | + | |
23 | +#include <common.h> | |
24 | +#include <command.h> | |
25 | +#include <ansi.h> | |
26 | +#include <menu.h> | |
27 | +#include <hush.h> | |
28 | +#include <watchdog.h> | |
29 | +#include <malloc.h> | |
30 | +#include <linux/string.h> | |
31 | + | |
32 | +/* maximum bootmenu entries */ | |
33 | +#define MAX_COUNT 99 | |
34 | + | |
35 | +/* maximal size of bootmenu env | |
36 | + * 9 = strlen("bootmenu_") | |
37 | + * 2 = strlen(MAX_COUNT) | |
38 | + * 1 = NULL term | |
39 | + */ | |
40 | +#define MAX_ENV_SIZE (9 + 2 + 1) | |
41 | + | |
42 | +struct bootmenu_entry { | |
43 | + unsigned short int num; /* unique number 0 .. MAX_COUNT */ | |
44 | + char key[3]; /* key identifier of number */ | |
45 | + char *title; /* title of entry */ | |
46 | + char *command; /* hush command of entry */ | |
47 | + struct bootmenu_data *menu; /* this bootmenu */ | |
48 | + struct bootmenu_entry *next; /* next menu entry (num+1) */ | |
49 | +}; | |
50 | + | |
51 | +struct bootmenu_data { | |
52 | + int delay; /* delay for autoboot */ | |
53 | + int active; /* active menu entry */ | |
54 | + int count; /* total count of menu entries */ | |
55 | + struct bootmenu_entry *first; /* first menu entry */ | |
56 | +}; | |
57 | + | |
58 | +enum bootmenu_key { | |
59 | + KEY_NONE = 0, | |
60 | + KEY_UP, | |
61 | + KEY_DOWN, | |
62 | + KEY_SELECT, | |
63 | +}; | |
64 | + | |
65 | +static char *bootmenu_getoption(unsigned short int n) | |
66 | +{ | |
67 | + char name[MAX_ENV_SIZE] = "bootmenu_"; | |
68 | + | |
69 | + if (n > MAX_COUNT) | |
70 | + return NULL; | |
71 | + | |
72 | + sprintf(name + 9, "%d", n); | |
73 | + return getenv(name); | |
74 | +} | |
75 | + | |
76 | +static void bootmenu_print_entry(void *data) | |
77 | +{ | |
78 | + struct bootmenu_entry *entry = data; | |
79 | + int reverse = (entry->menu->active == entry->num); | |
80 | + | |
81 | + /* | |
82 | + * Move cursor to line where the entry will be drown (entry->num) | |
83 | + * First 3 lines contain bootmenu header + 1 empty line | |
84 | + */ | |
85 | + printf(ANSI_CURSOR_POSITION, entry->num + 4, 1); | |
86 | + | |
87 | + puts(" "); | |
88 | + | |
89 | + if (reverse) | |
90 | + puts(ANSI_COLOR_REVERSE); | |
91 | + | |
92 | + puts(entry->title); | |
93 | + | |
94 | + if (reverse) | |
95 | + puts(ANSI_COLOR_RESET); | |
96 | +} | |
97 | + | |
98 | +static void bootmenu_autoboot_loop(struct bootmenu_data *menu, | |
99 | + enum bootmenu_key *key, int *esc) | |
100 | +{ | |
101 | + int i, c; | |
102 | + | |
103 | + if (menu->delay > 0) { | |
104 | + printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | |
105 | + printf(" Hit any key to stop autoboot: %2d ", menu->delay); | |
106 | + } | |
107 | + | |
108 | + while (menu->delay > 0) { | |
109 | + for (i = 0; i < 100; ++i) { | |
110 | + if (!tstc()) { | |
111 | + WATCHDOG_RESET(); | |
112 | + mdelay(10); | |
113 | + continue; | |
114 | + } | |
115 | + | |
116 | + menu->delay = -1; | |
117 | + c = getc(); | |
118 | + | |
119 | + switch (c) { | |
120 | + case '\e': | |
121 | + *esc = 1; | |
122 | + *key = KEY_NONE; | |
123 | + break; | |
124 | + case '\r': | |
125 | + *key = KEY_SELECT; | |
126 | + break; | |
127 | + default: | |
128 | + *key = KEY_NONE; | |
129 | + break; | |
130 | + } | |
131 | + | |
132 | + break; | |
133 | + } | |
134 | + | |
135 | + if (menu->delay < 0) | |
136 | + break; | |
137 | + | |
138 | + --menu->delay; | |
139 | + printf("\b\b\b%2d ", menu->delay); | |
140 | + } | |
141 | + | |
142 | + printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | |
143 | + puts(ANSI_CLEAR_LINE); | |
144 | + | |
145 | + if (menu->delay == 0) | |
146 | + *key = KEY_SELECT; | |
147 | +} | |
148 | + | |
149 | +static void bootmenu_loop(struct bootmenu_data *menu, | |
150 | + enum bootmenu_key *key, int *esc) | |
151 | +{ | |
152 | + int c; | |
153 | + | |
154 | + while (!tstc()) { | |
155 | + WATCHDOG_RESET(); | |
156 | + mdelay(10); | |
157 | + } | |
158 | + | |
159 | + c = getc(); | |
160 | + | |
161 | + switch (*esc) { | |
162 | + case 0: | |
163 | + /* First char of ANSI escape sequence '\e' */ | |
164 | + if (c == '\e') { | |
165 | + *esc = 1; | |
166 | + *key = KEY_NONE; | |
167 | + } | |
168 | + break; | |
169 | + case 1: | |
170 | + /* Second char of ANSI '[' */ | |
171 | + if (c == '[') { | |
172 | + *esc = 2; | |
173 | + *key = KEY_NONE; | |
174 | + } else { | |
175 | + *esc = 0; | |
176 | + } | |
177 | + break; | |
178 | + case 2: | |
179 | + case 3: | |
180 | + /* Third char of ANSI (number '1') - optional */ | |
181 | + if (*esc == 2 && c == '1') { | |
182 | + *esc = 3; | |
183 | + *key = KEY_NONE; | |
184 | + break; | |
185 | + } | |
186 | + | |
187 | + *esc = 0; | |
188 | + | |
189 | + /* ANSI 'A' - key up was pressed */ | |
190 | + if (c == 'A') | |
191 | + *key = KEY_UP; | |
192 | + /* ANSI 'B' - key down was pressed */ | |
193 | + else if (c == 'B') | |
194 | + *key = KEY_DOWN; | |
195 | + /* other key was pressed */ | |
196 | + else | |
197 | + *key = KEY_NONE; | |
198 | + | |
199 | + break; | |
200 | + } | |
201 | + | |
202 | + /* enter key was pressed */ | |
203 | + if (c == '\r') | |
204 | + *key = KEY_SELECT; | |
205 | +} | |
206 | + | |
207 | +static char *bootmenu_choice_entry(void *data) | |
208 | +{ | |
209 | + struct bootmenu_data *menu = data; | |
210 | + struct bootmenu_entry *iter; | |
211 | + enum bootmenu_key key = KEY_NONE; | |
212 | + int esc = 0; | |
213 | + int i; | |
214 | + | |
215 | + while (1) { | |
216 | + if (menu->delay >= 0) { | |
217 | + /* Autoboot was not stopped */ | |
218 | + bootmenu_autoboot_loop(menu, &key, &esc); | |
219 | + } else { | |
220 | + /* Some key was pressed, so autoboot was stopped */ | |
221 | + bootmenu_loop(menu, &key, &esc); | |
222 | + } | |
223 | + | |
224 | + switch (key) { | |
225 | + case KEY_UP: | |
226 | + if (menu->active > 0) | |
227 | + --menu->active; | |
228 | + /* no menu key selected, regenerate menu */ | |
229 | + return NULL; | |
230 | + case KEY_DOWN: | |
231 | + if (menu->active < menu->count - 1) | |
232 | + ++menu->active; | |
233 | + /* no menu key selected, regenerate menu */ | |
234 | + return NULL; | |
235 | + case KEY_SELECT: | |
236 | + iter = menu->first; | |
237 | + for (i = 0; i < menu->active; ++i) | |
238 | + iter = iter->next; | |
239 | + return iter->key; | |
240 | + default: | |
241 | + break; | |
242 | + } | |
243 | + } | |
244 | + | |
245 | + /* never happens */ | |
246 | + debug("bootmenu: this should not happen"); | |
247 | + return NULL; | |
248 | +} | |
249 | + | |
250 | +static void bootmenu_destroy(struct bootmenu_data *menu) | |
251 | +{ | |
252 | + struct bootmenu_entry *iter = menu->first; | |
253 | + struct bootmenu_entry *next; | |
254 | + | |
255 | + while (iter) { | |
256 | + next = iter->next; | |
257 | + free(iter->title); | |
258 | + free(iter->command); | |
259 | + free(iter); | |
260 | + iter = next; | |
261 | + } | |
262 | + free(menu); | |
263 | +} | |
264 | + | |
265 | +static struct bootmenu_data *bootmenu_create(int delay) | |
266 | +{ | |
267 | + unsigned short int i = 0; | |
268 | + const char *option; | |
269 | + struct bootmenu_data *menu; | |
270 | + struct bootmenu_entry *iter = NULL; | |
271 | + | |
272 | + int len; | |
273 | + char *sep; | |
274 | + struct bootmenu_entry *entry; | |
275 | + | |
276 | + menu = malloc(sizeof(struct bootmenu_data)); | |
277 | + if (!menu) | |
278 | + return NULL; | |
279 | + | |
280 | + menu->delay = delay; | |
281 | + menu->active = 0; | |
282 | + menu->first = NULL; | |
283 | + | |
284 | + while ((option = bootmenu_getoption(i))) { | |
285 | + sep = strchr(option, '='); | |
286 | + if (!sep) { | |
287 | + printf("Invalid bootmenu entry: %s\n", option); | |
288 | + break; | |
289 | + } | |
290 | + | |
291 | + entry = malloc(sizeof(struct bootmenu_entry)); | |
292 | + if (!entry) | |
293 | + goto cleanup; | |
294 | + | |
295 | + len = sep-option; | |
296 | + entry->title = malloc(len + 1); | |
297 | + if (!entry->title) { | |
298 | + free(entry); | |
299 | + goto cleanup; | |
300 | + } | |
301 | + memcpy(entry->title, option, len); | |
302 | + entry->title[len] = 0; | |
303 | + | |
304 | + len = strlen(sep + 1); | |
305 | + entry->command = malloc(len + 1); | |
306 | + if (!entry->command) { | |
307 | + free(entry->title); | |
308 | + free(entry); | |
309 | + goto cleanup; | |
310 | + } | |
311 | + memcpy(entry->command, sep + 1, len); | |
312 | + entry->command[len] = 0; | |
313 | + | |
314 | + sprintf(entry->key, "%d", i); | |
315 | + | |
316 | + entry->num = i; | |
317 | + entry->menu = menu; | |
318 | + entry->next = NULL; | |
319 | + | |
320 | + if (!iter) | |
321 | + menu->first = entry; | |
322 | + else | |
323 | + iter->next = entry; | |
324 | + | |
325 | + iter = entry; | |
326 | + ++i; | |
327 | + | |
328 | + if (i == MAX_COUNT - 1) | |
329 | + break; | |
330 | + } | |
331 | + | |
332 | + /* Add U-Boot console entry at the end */ | |
333 | + if (i <= MAX_COUNT - 1) { | |
334 | + entry = malloc(sizeof(struct bootmenu_entry)); | |
335 | + if (!entry) | |
336 | + goto cleanup; | |
337 | + | |
338 | + entry->title = strdup("U-Boot console"); | |
339 | + if (!entry->title) { | |
340 | + free(entry); | |
341 | + goto cleanup; | |
342 | + } | |
343 | + | |
344 | + entry->command = strdup(""); | |
345 | + if (!entry->command) { | |
346 | + free(entry->title); | |
347 | + free(entry); | |
348 | + goto cleanup; | |
349 | + } | |
350 | + | |
351 | + sprintf(entry->key, "%d", i); | |
352 | + | |
353 | + entry->num = i; | |
354 | + entry->menu = menu; | |
355 | + entry->next = NULL; | |
356 | + | |
357 | + if (!iter) | |
358 | + menu->first = entry; | |
359 | + else | |
360 | + iter->next = entry; | |
361 | + | |
362 | + iter = entry; | |
363 | + ++i; | |
364 | + } | |
365 | + | |
366 | + menu->count = i; | |
367 | + return menu; | |
368 | + | |
369 | +cleanup: | |
370 | + bootmenu_destroy(menu); | |
371 | + return NULL; | |
372 | +} | |
373 | + | |
374 | +static void bootmenu_show(int delay) | |
375 | +{ | |
376 | + int init = 0; | |
377 | + void *choice = NULL; | |
378 | + char *title = NULL; | |
379 | + char *command = NULL; | |
380 | + struct menu *menu; | |
381 | + struct bootmenu_data *bootmenu; | |
382 | + struct bootmenu_entry *iter; | |
383 | + char *option, *sep; | |
384 | + | |
385 | + /* If delay is 0 do not create menu, just run first entry */ | |
386 | + if (delay == 0) { | |
387 | + option = bootmenu_getoption(0); | |
388 | + if (!option) { | |
389 | + puts("bootmenu option 0 was not found\n"); | |
390 | + return; | |
391 | + } | |
392 | + sep = strchr(option, '='); | |
393 | + if (!sep) { | |
394 | + puts("bootmenu option 0 is invalid\n"); | |
395 | + return; | |
396 | + } | |
397 | + run_command(sep+1, 0); | |
398 | + return; | |
399 | + } | |
400 | + | |
401 | + bootmenu = bootmenu_create(delay); | |
402 | + if (!bootmenu) | |
403 | + return; | |
404 | + | |
405 | + menu = menu_create(NULL, bootmenu->delay, 1, bootmenu_print_entry, | |
406 | + bootmenu_choice_entry, bootmenu); | |
407 | + if (!menu) { | |
408 | + bootmenu_destroy(bootmenu); | |
409 | + return; | |
410 | + } | |
411 | + | |
412 | + for (iter = bootmenu->first; iter; iter = iter->next) { | |
413 | + if (!menu_item_add(menu, iter->key, iter)) | |
414 | + goto cleanup; | |
415 | + } | |
416 | + | |
417 | + /* Default menu entry is always first */ | |
418 | + menu_default_set(menu, "0"); | |
419 | + | |
420 | + puts(ANSI_CURSOR_HIDE); | |
421 | + puts(ANSI_CLEAR_CONSOLE); | |
422 | + printf(ANSI_CURSOR_POSITION, 1, 1); | |
423 | + | |
424 | + init = 1; | |
425 | + | |
426 | + if (menu_get_choice(menu, &choice)) { | |
427 | + iter = choice; | |
428 | + title = strdup(iter->title); | |
429 | + command = strdup(iter->command); | |
430 | + } | |
431 | + | |
432 | +cleanup: | |
433 | + menu_destroy(menu); | |
434 | + bootmenu_destroy(bootmenu); | |
435 | + | |
436 | + if (init) { | |
437 | + puts(ANSI_CURSOR_SHOW); | |
438 | + puts(ANSI_CLEAR_CONSOLE); | |
439 | + printf(ANSI_CURSOR_POSITION, 1, 1); | |
440 | + } | |
441 | + | |
442 | + if (title && command) { | |
443 | + debug("Starting entry '%s'\n", title); | |
444 | + free(title); | |
445 | + run_command(command, 0); | |
446 | + free(command); | |
447 | + } | |
448 | + | |
449 | +#ifdef CONFIG_POSTBOOTMENU | |
450 | + run_command(CONFIG_POSTBOOTMENU, 0); | |
451 | +#endif | |
452 | +} | |
453 | + | |
454 | +void menu_display_statusline(struct menu *m) | |
455 | +{ | |
456 | + struct bootmenu_entry *entry; | |
457 | + struct bootmenu_data *menu; | |
458 | + | |
459 | + if (menu_default_choice(m, (void *)&entry) < 0) | |
460 | + return; | |
461 | + | |
462 | + menu = entry->menu; | |
463 | + | |
464 | + printf(ANSI_CURSOR_POSITION, 1, 1); | |
465 | + puts(ANSI_CLEAR_LINE); | |
466 | + printf(ANSI_CURSOR_POSITION, 2, 1); | |
467 | + puts(" *** U-Boot Boot Menu ***"); | |
468 | + puts(ANSI_CLEAR_LINE_TO_END); | |
469 | + printf(ANSI_CURSOR_POSITION, 3, 1); | |
470 | + puts(ANSI_CLEAR_LINE); | |
471 | + | |
472 | + /* First 3 lines are bootmenu header + 2 empty lines between entries */ | |
473 | + printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); | |
474 | + puts(ANSI_CLEAR_LINE); | |
475 | + printf(ANSI_CURSOR_POSITION, menu->count + 6, 1); | |
476 | + puts(" Press UP/DOWN to move, ENTER to select"); | |
477 | + puts(ANSI_CLEAR_LINE_TO_END); | |
478 | + printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); | |
479 | + puts(ANSI_CLEAR_LINE); | |
480 | +} | |
481 | + | |
482 | +#ifdef CONFIG_MENU_SHOW | |
483 | +int menu_show(int bootdelay) | |
484 | +{ | |
485 | + bootmenu_show(bootdelay); | |
486 | + return -1; /* -1 - abort boot and run monitor code */ | |
487 | +} | |
488 | +#endif | |
489 | + | |
490 | +int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) | |
491 | +{ | |
492 | + char *delay_str = NULL; | |
493 | + int delay = 10; | |
494 | + | |
495 | +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) | |
496 | + delay = CONFIG_BOOTDELAY; | |
497 | +#endif | |
498 | + | |
499 | + if (argc >= 2) | |
500 | + delay_str = argv[1]; | |
501 | + | |
502 | + if (!delay_str) | |
503 | + delay_str = getenv("bootmenu_delay"); | |
504 | + | |
505 | + if (delay_str) | |
506 | + delay = (int)simple_strtol(delay_str, NULL, 10); | |
507 | + | |
508 | + bootmenu_show(delay); | |
509 | + return 0; | |
510 | +} | |
511 | + | |
512 | +U_BOOT_CMD( | |
513 | + bootmenu, 2, 1, do_bootmenu, | |
514 | + "ANSI terminal bootmenu", | |
515 | + "[delay]\n" | |
516 | + " - show ANSI terminal bootmenu with autoboot delay" | |
517 | +); |
common/cmd_pxe.c
... | ... | @@ -1280,7 +1280,8 @@ |
1280 | 1280 | /* |
1281 | 1281 | * Create a menu and add items for all the labels. |
1282 | 1282 | */ |
1283 | - m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print); | |
1283 | + m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print, | |
1284 | + NULL, NULL); | |
1284 | 1285 | |
1285 | 1286 | if (!m) |
1286 | 1287 | return NULL; |
common/menu.c
... | ... | @@ -47,6 +47,8 @@ |
47 | 47 | char *title; |
48 | 48 | int prompt; |
49 | 49 | void (*item_data_print)(void *); |
50 | + char *(*item_choice)(void *); | |
51 | + void *item_choice_data; | |
50 | 52 | struct list_head items; |
51 | 53 | }; |
52 | 54 | |
... | ... | @@ -174,7 +176,7 @@ |
174 | 176 | * Set *choice to point to the default item's data, if any default item was |
175 | 177 | * set, and returns 1. If no default item was set, returns -ENOENT. |
176 | 178 | */ |
177 | -static inline int menu_default_choice(struct menu *m, void **choice) | |
179 | +int menu_default_choice(struct menu *m, void **choice) | |
178 | 180 | { |
179 | 181 | if (m->default_item) { |
180 | 182 | *choice = m->default_item->data; |
181 | 183 | |
182 | 184 | |
... | ... | @@ -204,18 +206,26 @@ |
204 | 206 | |
205 | 207 | menu_display(m); |
206 | 208 | |
207 | - readret = readline_into_buffer("Enter choice: ", cbuf, | |
208 | - m->timeout / 10); | |
209 | + if (!m->item_choice) { | |
210 | + readret = readline_into_buffer("Enter choice: ", cbuf, | |
211 | + m->timeout / 10); | |
209 | 212 | |
210 | - if (readret >= 0) { | |
211 | - choice_item = menu_item_by_key(m, cbuf); | |
212 | - | |
213 | - if (!choice_item) { | |
214 | - printf("%s not found\n", cbuf); | |
215 | - m->timeout = 0; | |
213 | + if (readret >= 0) { | |
214 | + choice_item = menu_item_by_key(m, cbuf); | |
215 | + if (!choice_item) | |
216 | + printf("%s not found\n", cbuf); | |
217 | + } else { | |
218 | + return menu_default_choice(m, choice); | |
216 | 219 | } |
217 | - } else | |
218 | - return menu_default_choice(m, choice); | |
220 | + } else { | |
221 | + char *key = m->item_choice(m->item_choice_data); | |
222 | + | |
223 | + if (key) | |
224 | + choice_item = menu_item_by_key(m, key); | |
225 | + } | |
226 | + | |
227 | + if (!choice_item) | |
228 | + m->timeout = 0; | |
219 | 229 | } |
220 | 230 | |
221 | 231 | *choice = choice_item->data; |
222 | 232 | |
... | ... | @@ -348,11 +358,19 @@ |
348 | 358 | * what must be entered to select an item, the item_data_print function should |
349 | 359 | * make it obvious what the key for each entry is. |
350 | 360 | * |
361 | + * item_choice - If not NULL, will be called when asking the user to choose an | |
362 | + * item. Returns a key string corresponding to the choosen item or NULL if | |
363 | + * no item has been selected. | |
364 | + * | |
365 | + * item_choice_data - Will be passed as the argument to the item_choice function | |
366 | + * | |
351 | 367 | * Returns a pointer to the menu if successful, or NULL if there is |
352 | 368 | * insufficient memory available to create the menu. |
353 | 369 | */ |
354 | 370 | struct menu *menu_create(char *title, int timeout, int prompt, |
355 | - void (*item_data_print)(void *)) | |
371 | + void (*item_data_print)(void *), | |
372 | + char *(*item_choice)(void *), | |
373 | + void *item_choice_data) | |
356 | 374 | { |
357 | 375 | struct menu *m; |
358 | 376 | |
... | ... | @@ -365,6 +383,8 @@ |
365 | 383 | m->prompt = prompt; |
366 | 384 | m->timeout = timeout; |
367 | 385 | m->item_data_print = item_data_print; |
386 | + m->item_choice = item_choice; | |
387 | + m->item_choice_data = item_choice_data; | |
368 | 388 | |
369 | 389 | if (title) { |
370 | 390 | m->title = strdup(title); |
doc/README.bootmenu
1 | +/* | |
2 | + * (C) Copyright 2011-2012 Pali Rohár <pali.rohar@gmail.com> | |
3 | + * | |
4 | + * See file CREDITS for list of people who contributed to this | |
5 | + * project. | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License as | |
9 | + * published by the Free Software Foundation; either version 2 of | |
10 | + * the License, or (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
20 | + * MA 02111-1307 USA | |
21 | + */ | |
22 | + | |
23 | +ANSI terminal bootmenu command | |
24 | + | |
25 | +The "bootmenu" command uses U-Boot menu interfaces and provides | |
26 | +a simple mechanism for creating menus with different boot items. | |
27 | +The cursor keys "Up" and "Down" are used for navigation through | |
28 | +the items. Current active menu item is highlighted and can be | |
29 | +selected using the "Enter" key. The selection of the highlighted | |
30 | +menu entry invokes an U-Boot command (or a list of commands) | |
31 | +associated with this menu entry. | |
32 | + | |
33 | +The "bootmenu" command interprets ANSI escape sequencies, so | |
34 | +an ANSI terminal is required for proper menu rendering and item | |
35 | +selection. | |
36 | + | |
37 | +The assembling of the menu is done via a set of environment variables | |
38 | +"bootmenu_<num>" and "bootmenu_delay", i.e.: | |
39 | + | |
40 | + bootmenu_delay=<delay> | |
41 | + bootmenu_<num>="<title>=<commands>" | |
42 | + | |
43 | + <delay> is the autoboot delay in seconds, after which the first | |
44 | + menu entry will be selected automatically | |
45 | + | |
46 | + <num> is the boot menu entry number, starting from zero | |
47 | + | |
48 | + <title> is the text of the menu entry shown on the console | |
49 | + or on the boot screen | |
50 | + | |
51 | + <commands> are commands which will be executed when a menu | |
52 | + entry is selected | |
53 | + | |
54 | + (title and commands are separated by first appearance of '=' | |
55 | + character in the environment variable) | |
56 | + | |
57 | +First (optional) argument of the "bootmenu" command is a delay specifier | |
58 | +and it overrides the delay value defined by "bootmenu_delay" environment | |
59 | +variable. If the environment variable "bootmenu_delay" is not set or if | |
60 | +the argument of the "bootmenu" command is not specified, the default delay | |
61 | +will be CONFIG_BOOTDELAY. If delay is 0, no menu entries will be shown on | |
62 | +the console (or on the screen) and the command of the first menu entry will | |
63 | +be called immediately. If delay is less then 0, bootmenu will be shown and | |
64 | +autoboot will be disabled. | |
65 | + | |
66 | +Bootmenu always adds menu entry "U-Boot console" at the end of all menu | |
67 | +entries specified by environment variables. When selecting this entry | |
68 | +the bootmenu terminates and the usual U-Boot command prompt is presented | |
69 | +to the user. | |
70 | + | |
71 | +Example environment: | |
72 | + | |
73 | + setenv bootmenu_0 Boot 1. kernel=bootm 0x82000000 # Set first menu entry | |
74 | + setenv bootmenu_1 Boot 2. kernel=bootm 0x83000000 # Set second menu entry | |
75 | + setenv bootmenu_2 Reset board=reset # Set third menu entry | |
76 | + setenv bootmenu_3 U-Boot boot order=boot # Set fourth menu entry | |
77 | + bootmenu 20 # Run bootmenu with autoboot delay 20s | |
78 | + | |
79 | + | |
80 | +The above example will be rendered as below | |
81 | +(without decorating rectangle): | |
82 | + | |
83 | +┌──────────────────────────────────────────┐ | |
84 | +│ │ | |
85 | +│ *** U-Boot Boot Menu *** │ | |
86 | +│ │ | |
87 | +│ Boot 1. kernel │ | |
88 | +│ Boot 2. kernel │ | |
89 | +│ Reset board │ | |
90 | +│ U-Boot boot order │ | |
91 | +│ U-Boot console │ | |
92 | +│ │ | |
93 | +│ Hit any key to stop autoboot: 20 │ | |
94 | +│ Press UP/DOWN to move, ENTER to select │ | |
95 | +│ │ | |
96 | +└──────────────────────────────────────────┘ | |
97 | + | |
98 | +Selected menu entry will be highlighted - it will have inverted | |
99 | +background and text colors. | |
100 | + | |
101 | +To enable the "bootmenu" command add following definitions to the | |
102 | +board config file: | |
103 | + | |
104 | + #define CONFIG_CMD_BOOTMENU | |
105 | + #define CONFIG_MENU | |
106 | + | |
107 | +To run the bootmenu at startup add these additional definitions: | |
108 | + | |
109 | + #define CONFIG_AUTOBOOT_KEYED | |
110 | + #define CONFIG_BOOTDELAY 30 | |
111 | + #define CONFIG_MENU_SHOW | |
112 | + | |
113 | +When you intend to use the bootmenu on color frame buffer console, | |
114 | +make sure to additionally define CONFIG_CFB_CONSOLE_ANSI in the | |
115 | +board config file. |
doc/README.menu
... | ... | @@ -51,7 +51,9 @@ |
51 | 51 | * menu_create() - Creates a menu handle with default settings |
52 | 52 | */ |
53 | 53 | struct menu *menu_create(char *title, int timeout, int prompt, |
54 | - void (*item_data_print)(void *)); | |
54 | + void (*item_data_print)(void *), | |
55 | + char *(*item_choice)(void *), | |
56 | + void *item_choice_data); | |
55 | 57 | |
56 | 58 | /* |
57 | 59 | * menu_item_add() - Adds or replaces a menu item |
... | ... | @@ -62,6 +64,11 @@ |
62 | 64 | * menu_default_set() - Sets the default choice for the menu |
63 | 65 | */ |
64 | 66 | int menu_default_set(struct menu *m, char *item_key); |
67 | + | |
68 | +/* | |
69 | + * menu_default_choice() - Set *choice to point to the default item's data | |
70 | + */ | |
71 | +int menu_default_choice(struct menu *m, void **choice); | |
65 | 72 | |
66 | 73 | /* |
67 | 74 | * menu_get_choice() - Returns the user's selected menu entry, or the |
include/ansi.h
1 | +/* | |
2 | + * (C) Copyright 2012 | |
3 | + * Pali Rohár <pali.rohar@gmail.com> | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +/* | |
25 | + * ANSI terminal | |
26 | + */ | |
27 | + | |
28 | +#define ANSI_CURSOR_UP "\e[%dA" | |
29 | +#define ANSI_CURSOR_DOWN "\e[%dB" | |
30 | +#define ANSI_CURSOR_FORWARD "\e[%dC" | |
31 | +#define ANSI_CURSOR_BACK "\e[%dD" | |
32 | +#define ANSI_CURSOR_NEXTLINE "\e[%dE" | |
33 | +#define ANSI_CURSOR_PREVIOUSLINE "\e[%dF" | |
34 | +#define ANSI_CURSOR_COLUMN "\e[%dG" | |
35 | +#define ANSI_CURSOR_POSITION "\e[%d;%dH" | |
36 | +#define ANSI_CURSOR_SHOW "\e[?25h" | |
37 | +#define ANSI_CURSOR_HIDE "\e[?25l" | |
38 | +#define ANSI_CLEAR_CONSOLE "\e[2J" | |
39 | +#define ANSI_CLEAR_LINE_TO_END "\e[0K" | |
40 | +#define ANSI_CLEAR_LINE "\e[2K" | |
41 | +#define ANSI_COLOR_RESET "\e[0m" | |
42 | +#define ANSI_COLOR_REVERSE "\e[7m" |
include/configs/nokia_rx51.h
... | ... | @@ -148,6 +148,7 @@ |
148 | 148 | #define CONFIG_CMDLINE_EDITING /* add command line history */ |
149 | 149 | #define CONFIG_AUTO_COMPLETE /* add autocompletion support */ |
150 | 150 | |
151 | +#define CONFIG_CMD_BOOTMENU /* ANSI terminal Boot Menu */ | |
151 | 152 | #define CONFIG_CMD_CLEAR /* ANSI terminal clear screen command */ |
152 | 153 | |
153 | 154 | #ifdef ONENAND_SUPPORT |
... | ... | @@ -287,8 +288,6 @@ |
287 | 288 | #endif |
288 | 289 | |
289 | 290 | /* Environment information */ |
290 | -#define CONFIG_BOOTDELAY 3 | |
291 | - | |
292 | 291 | #define CONFIG_EXTRA_ENV_SETTINGS \ |
293 | 292 | "mtdparts=" MTDPARTS_DEFAULT "\0" \ |
294 | 293 | "usbtty=cdc_acm\0" \ |
295 | 294 | |
... | ... | @@ -360,10 +359,40 @@ |
360 | 359 | "fi\0" \ |
361 | 360 | "emmcboot=setenv mmcnum 1; run trymmcboot\0" \ |
362 | 361 | "sdboot=setenv mmcnum 0; run trymmcboot\0" \ |
362 | + "menucmd=bootmenu\0" \ | |
363 | + "bootmenu_0=Attached kernel=run attachboot\0" \ | |
364 | + "bootmenu_1=Internal eMMC=run emmcboot\0" \ | |
365 | + "bootmenu_2=External SD card=run sdboot\0" \ | |
366 | + "bootmenu_3=U-Boot boot order=boot\0" \ | |
367 | + "bootmenu_delay=30\0" \ | |
363 | 368 | "" |
364 | 369 | |
365 | 370 | #define CONFIG_PREBOOT \ |
366 | - "if run slide; then true; else run attachboot; fi;" \ | |
371 | + "setenv mmcnum 1; setenv mmcpart 1;" \ | |
372 | + "setenv mmcscriptfile bootmenu.scr;" \ | |
373 | + "if run switchmmc; then " \ | |
374 | + "setenv mmcdone true;" \ | |
375 | + "setenv mmctype fat;" \ | |
376 | + "if run scriptload; then true; else " \ | |
377 | + "setenv mmctype ext2;" \ | |
378 | + "if run scriptload; then true; else " \ | |
379 | + "setenv mmctype ext4;" \ | |
380 | + "if run scriptload; then true; else " \ | |
381 | + "setenv mmcdone false;" \ | |
382 | + "fi;" \ | |
383 | + "fi;" \ | |
384 | + "fi;" \ | |
385 | + "if ${mmcdone}; then " \ | |
386 | + "run scriptboot;" \ | |
387 | + "fi;" \ | |
388 | + "fi;" \ | |
389 | + "if run slide; then true; else " \ | |
390 | + "setenv bootmenu_delay 0;" \ | |
391 | + "setenv bootdelay 0;" \ | |
392 | + "fi" | |
393 | + | |
394 | +#define CONFIG_POSTBOOTMENU \ | |
395 | + "echo;" \ | |
367 | 396 | "echo Extra commands:;" \ |
368 | 397 | "echo run sercon - Use serial port for control.;" \ |
369 | 398 | "echo run usbcon - Use usbtty for control.;" \ |
... | ... | @@ -378,6 +407,11 @@ |
378 | 407 | "run emmcboot;" \ |
379 | 408 | "run attachboot;" \ |
380 | 409 | "echo" |
410 | + | |
411 | +#define CONFIG_BOOTDELAY 30 | |
412 | +#define CONFIG_AUTOBOOT_KEYED | |
413 | +#define CONFIG_MENU | |
414 | +#define CONFIG_MENU_SHOW | |
381 | 415 | |
382 | 416 | /* |
383 | 417 | * Miscellaneous configurable options |
include/menu.h
... | ... | @@ -21,12 +21,15 @@ |
21 | 21 | struct menu; |
22 | 22 | |
23 | 23 | struct menu *menu_create(char *title, int timeout, int prompt, |
24 | - void (*item_data_print)(void *)); | |
24 | + void (*item_data_print)(void *), | |
25 | + char *(*item_choice)(void *), | |
26 | + void *item_choice_data); | |
25 | 27 | int menu_default_set(struct menu *m, char *item_key); |
26 | 28 | int menu_get_choice(struct menu *m, void **choice); |
27 | 29 | int menu_item_add(struct menu *m, char *item_key, void *item_data); |
28 | 30 | int menu_destroy(struct menu *m); |
29 | 31 | void menu_display_statusline(struct menu *m); |
32 | +int menu_default_choice(struct menu *m, void **choice); | |
30 | 33 | |
31 | 34 | #if defined(CONFIG_MENU_SHOW) |
32 | 35 | int menu_show(int bootdelay); |