1 board/neo1973/bootmenu.c: simple configurable boot menu
2 board/neo1973/neo1973.c (neo1973_new_second): return 1 if a new second has
3 started since the last call
4 board/neo1973/neo1973.c (neo1973_on_key_pressed): return 1 if the $POWER key is
6 board/neo1973/neo1973.c (board_late_init): make use of neo1973_new_second and
8 board/neo1973/neo1973.h: added function prototypes
9 u-boot/board/neo1973/neo1973.c (board_late_init): enter the boot menu when
10 "AUX" was pressed at least half the time
11 u-boot/board/neo1973/neo1973.c (board_late_init): minor code cleanup
12 u-boot/common/console.c, include/console.h: added "console_poll_hook" to be
13 called when waiting for console in put in "getc" and "tstc"
14 board/neo1973/neo1973.c (board_late_init): poll for the boot menu also on RAM
15 boot, reset, or unknown cause
16 board/neo1973/neo1973.c (board_late_init): don't look for the power key if
17 woken up by the charger
18 board/neo1973/neo1973.h, board/neo1973/neo1973.c, board/neo1973/bootmenu.c:
19 renamed neo1973_911_key_pressed to neo1973_aux_key_pressed
21 - Werner Almesberger <werner@openmoko.org>
23 Index: u-boot/board/neo1973/common/bootmenu.c
24 ===================================================================
26 +++ u-boot/board/neo1973/common/bootmenu.c
29 + * bootmenu.c - Boot menu
31 + * Copyright (C) 2006-2007 by Openmoko, Inc.
32 + * Written by Werner Almesberger <werner@openmoko.org>
33 + * All Rights Reserved
35 + * This program is free software; you can redistribute it and/or modify
36 + * it under the terms of the GNU General Public License as published by
37 + * the Free Software Foundation; either version 2 of the License, or
38 + * (at your option) any later version.
40 + * This program is distributed in the hope that it will be useful,
41 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 + * GNU General Public License for more details.
45 + * You should have received a copy of the GNU General Public License along
46 + * with this program; if not, write to the Free Software Foundation, Inc.,
47 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
52 +#include <environment.h>
53 +#include <bootmenu.h>
54 +#include <asm/atomic.h>
56 +#ifdef CONFIG_USBD_DFU
57 +#include "usbdcore.h"
64 +#define DEBOUNCE_LOOPS 1000 /* wild guess */
67 +static int debounce(int (*fn)(void), int *last)
74 + for (i = DEBOUNCE_LOOPS; i; i--)
82 +static int aux_key(void *user)
84 + static int last_aux = -1;
86 + return debounce(neo1973_aux_key_pressed, &last_aux);
90 +static int on_key(void *user)
92 + static int last_on = -1;
94 + return debounce(neo1973_on_key_pressed, &last_on);
98 +static void factory_reset(void *user)
101 + run_command("dynpart", 0);
102 + run_command("bootd", 0);
106 +static int seconds(void *user)
108 + return neo1973_new_second();
112 +static int system_idle(void)
114 +#ifdef CONFIG_USBD_DFU
115 + if (system_dfu_state)
116 + return *system_dfu_state == DFU_STATE_appIDLE;
122 +static void poweroff_if_idle(void *user)
124 + unsigned long flags;
126 + local_irq_save(flags);
128 + neo1973_poweroff();
129 + local_irq_restore(flags);
133 +static struct bootmenu_setup bootmenu_setup = {
134 + .next_key = aux_key,
135 + .enter_key = on_key,
136 + .seconds = seconds,
137 + .idle_action = poweroff_if_idle,
141 +void neo1973_bootmenu(void)
143 + bootmenu_add("Boot", NULL, "bootd");
144 + bootmenu_init(&bootmenu_setup);
145 + bootmenu_add("Factory reset", factory_reset, NULL);
148 Index: u-boot/board/neo1973/gta01/gta01.c
149 ===================================================================
150 --- u-boot.orig/board/neo1973/gta01/gta01.c
151 +++ u-boot/board/neo1973/gta01/gta01.c
152 @@ -229,10 +229,15 @@ int board_late_init(void)
153 extern unsigned char booted_from_nand;
156 + int menu_vote = 0; /* <= 0: no, > 0: yes */
159 /* Initialize the Power Management Unit with a safe register set */
162 + /* if there's no other reason, must be regular reset */
163 + neo1973_wakeup_cause = NEO1973_WAKEUP_RESET;
165 if (!booted_from_nand)
168 @@ -242,45 +247,41 @@ int board_late_init(void)
169 setenv("pcf50606_int1", buf);
171 if (tmp & PCF50606_INT1_ALARM) {
172 - /* we've been woken up by RTC alarm or charger insert, boot */
173 + /* we've been woken up by RTC alarm, boot */
174 neo1973_wakeup_cause = NEO1973_WAKEUP_ALARM;
177 if (tmp & PCF50606_INT1_EXTONR) {
178 + /* we've been woken up by charger insert */
179 neo1973_wakeup_cause = NEO1973_WAKEUP_CHARGER;
182 if (tmp & PCF50606_INT1_ONKEYF) {
184 - neo1973_wakeup_cause = NEO1973_WAKEUP_POWER_KEY;
185 /* we've been woken up by a falling edge of the onkey */
186 + neo1973_wakeup_cause = NEO1973_WAKEUP_POWER_KEY;
189 - /* we can't just setenv(bootdelay,-1) because that would
190 - * accidentially become permanent if the user does saveenv */
191 - if (neo1973_911_key_pressed())
195 - u_int8_t int1, oocs;
197 - oocs = pcf50606_reg_read(PCF50606_REG_OOCS);
198 - if (oocs & PFC50606_OOCS_ONKEY)
201 - int1 = pcf50606_reg_read(PCF50606_REG_INT1);
202 - if (int1 & PCF50606_INT1_SECOND)
205 - if (seconds >= POWER_KEY_SECONDS)
206 - goto continue_boot;
208 - /* Power off if minimum number of seconds not reached */
209 - neo1973_poweroff();
210 + if (neo1973_wakeup_cause == NEO1973_WAKEUP_CHARGER) {
211 + /* if we still think it was only a charger insert, boot */
212 + goto continue_boot;
216 - /* if there's no other reason, must be regular reset */
217 - neo1973_wakeup_cause = NEO1973_WAKEUP_RESET;
219 + while (neo1973_wakeup_cause == NEO1973_WAKEUP_RESET ||
220 + neo1973_on_key_pressed()) {
221 + if (neo1973_aux_key_pressed())
226 + if (neo1973_new_second())
228 + if (seconds >= POWER_KEY_SECONDS)
229 + goto continue_boot;
231 + /* Power off if minimum number of seconds not reached */
232 + neo1973_poweroff();
236 @@ -304,6 +305,11 @@ continue_boot:
240 + if (menu_vote > 0) {
241 + neo1973_bootmenu();
248 @@ -369,7 +375,17 @@ void neo1973_vibrator(int on)
252 -int neo1973_911_key_pressed(void)
253 +int neo1973_new_second(void)
255 + return pcf50606_reg_read(PCF50606_REG_INT1) & PCF50606_INT1_SECOND;
258 +int neo1973_on_key_pressed(void)
260 + return !(pcf50606_reg_read(PCF50606_REG_OOCS) & PFC50606_OOCS_ONKEY);
263 +int neo1973_aux_key_pressed(void)
265 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
266 if (gpio->GPFDAT & (1 << 6))
267 Index: u-boot/board/neo1973/gta01/Makefile
268 ===================================================================
269 --- u-boot.orig/board/neo1973/gta01/Makefile
270 +++ u-boot/board/neo1973/gta01/Makefile
271 @@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk
275 -OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o ../common/udc.o
276 +OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o ../common/udc.o ../common/bootmenu.o
277 SOBJS := ../common/lowlevel_init.o
280 Index: u-boot/board/neo1973/common/neo1973.h
281 ===================================================================
282 --- u-boot.orig/board/neo1973/common/neo1973.h
283 +++ u-boot/board/neo1973/common/neo1973.h
284 @@ -29,4 +29,10 @@ int neo1973_911_key_pressed(void);
285 const char *neo1973_get_charge_status(void);
286 int neo1973_set_charge_mode(enum neo1973_charger_cmd cmd);
288 +int neo1973_new_second(void);
289 +int neo1973_on_key_pressed(void);
290 +int neo1973_aux_key_pressed(void);
292 +void neo1973_bootmenu(void);
295 Index: u-boot/common/console.c
296 ===================================================================
297 --- u-boot.orig/common/console.c
298 +++ u-boot/common/console.c
299 @@ -160,8 +160,12 @@ void fprintf (int file, const char *fmt,
301 /** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
303 +void (*console_poll_hook)(int activity);
307 + while (console_poll_hook && !tstc());
309 if (gd->flags & GD_FLG_DEVINIT) {
310 /* Get from the standard input */
311 return fgetc (stdin);
312 @@ -171,7 +175,7 @@ int getc (void)
313 return serial_getc ();
317 +static int do_tstc (void)
319 if (gd->flags & GD_FLG_DEVINIT) {
320 /* Test the standard input */
321 @@ -182,6 +186,16 @@ int tstc (void)
322 return serial_tstc ();
330 + if (console_poll_hook)
331 + console_poll_hook(ret);
335 void putc (const char c)
337 #ifdef CONFIG_SILENT_CONSOLE
338 Index: u-boot/include/console.h
339 ===================================================================
340 --- u-boot.orig/include/console.h
341 +++ u-boot/include/console.h
343 extern device_t *stdio_devices[] ;
344 extern char *stdio_names[MAX_FILES] ;
346 +extern void (*console_poll_hook)(int activity);
348 int console_realloc(int top);
351 Index: u-boot/common/Makefile
352 ===================================================================
353 --- u-boot.orig/common/Makefile
354 +++ u-boot/common/Makefile
355 @@ -50,7 +50,8 @@ COBJS = main.o ACEX1K.o altera.o bedbug.
356 memsize.o miiphybb.o miiphyutil.o \
357 s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \
358 usb.o usb_kbd.o usb_storage.o \
359 - virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_mfsl.o
360 + virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_mfsl.o \
363 SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
364 OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
365 Index: u-boot/common/bootmenu.c
366 ===================================================================
368 +++ u-boot/common/bootmenu.c
371 + * bootmenu.c - Boot menu
373 + * Copyright (C) 2006-2007 by Openmoko, Inc.
374 + * Written by Werner Almesberger <werner@openmoko.org>
375 + * All Rights Reserved
377 + * This program is free software; you can redistribute it and/or modify
378 + * it under the terms of the GNU General Public License as published by
379 + * the Free Software Foundation; either version 2 of the License, or
380 + * (at your option) any later version.
382 + * This program is distributed in the hope that it will be useful,
383 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
384 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
385 + * GNU General Public License for more details.
387 + * You should have received a copy of the GNU General Public License along
388 + * with this program; if not, write to the Free Software Foundation, Inc.,
389 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
398 +#include <devices.h>
399 +#include <console.h>
400 +#include <bootmenu.h>
403 +extern const char version_string[];
406 +#define ANSI_CLEAR "\e[2J"
407 +#define ANSI_REVERSE "\e[7m"
408 +#define ANSI_NORMAL "\e[m"
409 +#define ANSI_GOTOYX "\e[%d;%dH"
412 + * MIN_BOOT_MENU_TIMEOUT ensures that users can't by accident set the timeout
415 +#define MIN_BOOT_MENU_TIMEOUT 10 /* 10 seconds */
416 +#define BOOT_MENU_TIMEOUT 60 /* 60 seconds */
417 +#define AFTER_COMMAND_WAIT 3 /* wait (2,3] after running commands */
418 +#define MAX_MENU_ITEMS 10 /* cut off after that many */
421 +#define MENU_0_ROW (TOP_ROW+5)
426 + void (*fn)(void *user); /* run_command if NULL */
431 +static const struct bootmenu_setup *setup;
432 +static struct option options[MAX_MENU_ITEMS];
433 +static int num_options = 0;
434 +static int max_width = 0;
436 +static device_t *bm_con;
439 +static void bm_printf(const char *fmt, ...)
442 + char printbuffer[CFG_PBSIZE];
444 + va_start(args, fmt);
445 + vsprintf(printbuffer, fmt, args);
448 + bm_con->puts(printbuffer);
452 +static char *get_option(int n)
454 + char name[] = "menu_XX";
456 + sprintf(name+5, "%d", n);
457 + return getenv(name);
461 +static void print_option(const struct option *option, int reverse)
463 + int n = option-options;
465 + bm_printf(ANSI_GOTOYX, MENU_0_ROW+n, 1);
467 + bm_printf(ANSI_REVERSE);
468 + bm_printf(" %-*s ", max_width, option->label);
470 + bm_printf(ANSI_NORMAL);
474 +static int get_var_positive_int(char *var, int default_value)
482 + return default_value;
483 + n = simple_strtoul(s, &end, 0);
484 + if (!*s || *end || n < 1)
485 + return default_value;
490 +static void show_bootmenu(void)
492 + const struct option *option;
494 + bm_printf(ANSI_CLEAR ANSI_GOTOYX "%s", TOP_ROW, 1, version_string);
495 + bm_printf(ANSI_GOTOYX "*** BOOT MENU ***", TOP_ROW+3, 1);
496 + bm_printf(ANSI_GOTOYX, MENU_0_ROW, 1);
498 + for (option = options; option != options+num_options; option++)
499 + print_option(option, option == options);
501 + bm_printf("\n\nPress [AUX] to select, [POWER] to execute.\n");
505 +static void redirect_console(int grab)
507 + static device_t *orig_stdout, *orig_stderr;
510 + orig_stdout = stdio_devices[stdout];
511 + orig_stderr = stdio_devices[stderr];
512 + stdio_devices[stdout] = bm_con;
513 + stdio_devices[stderr] = bm_con;
517 + * Make this conditional, because the command may also change
520 + if (stdio_devices[stdout] == bm_con)
521 + stdio_devices[stdout] = orig_stdout;
522 + if (stdio_devices[stderr] == bm_con)
523 + stdio_devices[stderr] = orig_stderr;
528 +static void do_option(const struct option *option)
532 + bm_printf(ANSI_CLEAR ANSI_GOTOYX, 1, 1);
533 + redirect_console(1);
536 + option->fn(option->user);
538 + run_command(option->user, 0);
540 + redirect_console(0);
541 + seconds = get_var_positive_int("after_command_wait",
542 + AFTER_COMMAND_WAIT);
544 + bm_printf("\nPress [AUX] to %s.",
545 + option ? "return to boot menu" : "power off");
546 + aux = 1; /* require up-down transition */
550 + tmp = setup->next_key(setup->user);
554 + if (setup->seconds(setup->user))
558 + setup->idle_action(setup->idle_action);
563 +static void bootmenu_hook(int activity)
565 + static int aux = 1, on = 1;
566 + static const struct option *option = options;
567 + static int seconds = 0;
572 + tmp = setup->next_key(setup->user);
574 + print_option(option, 0);
576 + if (option == options+num_options)
578 + print_option(option, 1);
582 + tmp = setup->enter_key(setup->user);
589 + if (setup->seconds(setup->user)) {
592 + timeout = get_var_positive_int("boot_menu_timeout",
593 + BOOT_MENU_TIMEOUT);
594 + if (timeout < MIN_BOOT_MENU_TIMEOUT)
595 + timeout = MIN_BOOT_MENU_TIMEOUT;
596 + if (++seconds > timeout) {
597 + setup->idle_action(setup->idle_action);
604 +static device_t *find_console(const char *name)
608 + for (i = 1; i != ListNumItems(devlist); i++) {
609 + device_t *dev = ListGetPtrToItem(devlist, i);
611 + if (!strcmp(name, dev->name))
612 + if (dev->flags & DEV_FLAGS_OUTPUT)
619 +void bootmenu_add(const char *label, void (*fn)(void *user), void *user)
623 + options[num_options].label = label;
624 + options[num_options].fn = fn;
625 + options[num_options].user = user;
628 + len = strlen(label);
629 + if (len > max_width)
634 +void bootmenu_init(struct bootmenu_setup *__setup)
639 + for (n = 1; n != MAX_MENU_ITEMS+1; n++) {
640 + const char *spec, *colon;
642 + spec = get_option(n);
645 + colon = strchr(spec, ':');
647 + bootmenu_add(spec, NULL, (char *) spec);
650 + int len = colon-spec;
652 + label = malloc(len+1);
655 + memcpy(label, spec, len);
657 + bootmenu_add(label, NULL, (char *) colon+1);
665 + bm_con = find_console("vga");
666 + if (bm_con && bm_con->start && bm_con->start() < 0)
669 + bm_con = stdio_devices[stdout];
673 + console_assign(stdout, "vga");
674 + console_assign(stderr, "vga");
677 + console_poll_hook = bootmenu_hook;
680 +#endif /* CFG_BOOTMENU */
681 Index: u-boot/include/bootmenu.h
682 ===================================================================
684 +++ u-boot/include/bootmenu.h
687 + * bootmenu.h - Boot menu
689 + * Copyright (C) 2006-2007 by Openmoko, Inc.
690 + * Written by Werner Almesberger <werner@openmoko.org>
691 + * All Rights Reserved
693 + * This program is free software; you can redistribute it and/or modify
694 + * it under the terms of the GNU General Public License as published by
695 + * the Free Software Foundation; either version 2 of the License, or
696 + * (at your option) any later version.
698 + * This program is distributed in the hope that it will be useful,
699 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
700 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
701 + * GNU General Public License for more details.
703 + * You should have received a copy of the GNU General Public License along
704 + * with this program; if not, write to the Free Software Foundation, Inc.,
705 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
711 +#define MIN_BOOT_MENU_TIMEOUT 10 /* 10 seconds */
712 +#define BOOT_MENU_TIMEOUT 60 /* 60 seconds */
713 +#define AFTER_COMMAND_WAIT 3 /* wait (2,3] after running commands */
714 +#define MAX_MENU_ITEMS 10 /* cut off after that many */
717 +struct bootmenu_setup {
718 + /* non-zero while the "next" key is being pressed */
719 + int (*next_key)(void *user);
721 + /* non-zero while the "enter" key is being pressed */
722 + int (*enter_key)(void *user);
724 + /* return the number of seconds that have passed since the last call
725 + to "seconds". It's okay to limit the range to [0, 1]. */
726 + int (*seconds)(void *user);
728 + /* action to take if the boot menu times out */
729 + void (*idle_action)(void *user);
731 + /* user-specific data, passes "as is" to the functions above */
737 + * Initialize the menu from the environment.
740 +void bootmenu_init(struct bootmenu_setup *setup);
743 + * To add entries on top of the boot menu, call bootmenu_add before
744 + * bootmenu_init. To add entries at the end, call it after bootmenu_init.
745 + * If "fn" is NULL, the command specified in "user" is executed.
748 +void bootmenu_add(const char *label, void (*fn)(void *user), void *user);
751 + * Run the boot menu.
754 +void bootmenu(void);
756 +#endif /* !BOOTMENU_H */
757 Index: u-boot/include/configs/neo1973_gta01.h
758 ===================================================================
759 --- u-boot.orig/include/configs/neo1973_gta01.h
760 +++ u-boot/include/configs/neo1973_gta01.h
762 /* valid baudrates */
763 #define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 }
765 +#define CFG_BOOTMENU
767 /*-----------------------------------------------------------------------