2 * bootmenu.c - Boot menu
4 * Copyright (C) 2006-2007 by OpenMoko, Inc.
5 * Written by Werner Almesberger <werner@openmoko.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 extern const char version_string
[];
37 #define ANSI_CLEAR "\e[2J"
38 #define ANSI_REVERSE "\e[7m"
39 #define ANSI_NORMAL "\e[m"
40 #define ANSI_GOTOYX "\e[%d;%dH"
43 * MIN_BOOT_MENU_TIMEOUT ensures that users can't by accident set the timeout
46 #define MIN_BOOT_MENU_TIMEOUT 10 /* 10 seconds */
47 #define BOOT_MENU_TIMEOUT 60 /* 60 seconds */
48 #define AFTER_COMMAND_WAIT 3 /* wait (2,3] after running commands */
49 #define MAX_MENU_ITEMS 10 /* cut off after that many */
52 #define MENU_0_ROW (TOP_ROW+5)
57 void (*fn
)(void *user
); /* run_command if NULL */
62 static const struct bootmenu_setup
*setup
;
63 static struct option options
[MAX_MENU_ITEMS
];
64 static int num_options
= 0;
65 static int max_width
= 0;
67 static device_t
*bm_con
;
70 static void bm_printf(const char *fmt
, ...)
73 char printbuffer
[CFG_PBSIZE
];
76 vsprintf(printbuffer
, fmt
, args
);
79 bm_con
->puts(printbuffer
);
83 static char *get_option(int n
)
85 char name
[] = "menu_XX";
87 sprintf(name
+5, "%d", n
);
92 static void print_option(const struct option
*option
, int reverse
)
94 int n
= option
-options
;
96 bm_printf(ANSI_GOTOYX
, MENU_0_ROW
+n
, 1);
98 bm_printf(ANSI_REVERSE
);
99 bm_printf(" %-*s ", max_width
, option
->label
);
101 bm_printf(ANSI_NORMAL
);
105 static int get_var_positive_int(char *var
, int default_value
)
113 return default_value
;
114 n
= simple_strtoul(s
, &end
, 0);
115 if (!*s
|| *end
|| n
< 1)
116 return default_value
;
121 static void show_bootmenu(void)
123 const struct option
*option
;
125 bm_printf(ANSI_CLEAR ANSI_GOTOYX
"%s", TOP_ROW
, 1, version_string
);
127 bm_printf(ANSI_GOTOYX
"*** BOOT MENU (%s) ***",
128 TOP_ROW
+3, 1, setup
->comment
);
130 bm_printf(ANSI_GOTOYX
"*** BOOT MENU ***", TOP_ROW
+3, 1);
131 bm_printf(ANSI_GOTOYX
, MENU_0_ROW
, 1);
133 for (option
= options
; option
!= options
+num_options
; option
++)
134 print_option(option
, option
== options
);
136 bm_printf("\n\n%s to select, %s to execute.\n",
137 setup
->next_key_action
, setup
->enter_key_name
);
141 static void redirect_console(int grab
)
143 static device_t
*orig_stdout
, *orig_stderr
;
146 orig_stdout
= stdio_devices
[stdout
];
147 orig_stderr
= stdio_devices
[stderr
];
148 stdio_devices
[stdout
] = bm_con
;
149 stdio_devices
[stderr
] = bm_con
;
153 * Make this conditional, because the command may also change
156 if (stdio_devices
[stdout
] == bm_con
)
157 stdio_devices
[stdout
] = orig_stdout
;
158 if (stdio_devices
[stderr
] == bm_con
)
159 stdio_devices
[stderr
] = orig_stderr
;
164 static void do_option(const struct option
*option
)
168 bm_printf(ANSI_CLEAR ANSI_GOTOYX
, 1, 1);
172 option
->fn(option
->user
);
174 run_command(option
->user
, 0);
177 seconds
= get_var_positive_int("after_command_wait",
180 bm_printf("\n%s to %s.", setup
->next_key_action
,
181 option
? "return to boot menu" : "power off");
182 next
= 1; /* require up-down transition */
186 tmp
= setup
->next_key(setup
->user
);
190 if (setup
->seconds(setup
->user
))
194 setup
->idle_action(setup
->idle_action
);
199 static void bootmenu_hook(int activity
)
201 static int next
= 1, on
= 1;
202 static const struct option
*option
= options
;
203 static int seconds
= 0;
208 tmp
= setup
->next_key(setup
->user
);
210 print_option(option
, 0);
212 if (option
== options
+num_options
)
214 print_option(option
, 1);
218 tmp
= setup
->enter_key(setup
->user
);
225 if (setup
->seconds(setup
->user
)) {
228 timeout
= get_var_positive_int("boot_menu_timeout",
230 if (timeout
< MIN_BOOT_MENU_TIMEOUT
)
231 timeout
= MIN_BOOT_MENU_TIMEOUT
;
232 if (++seconds
> timeout
) {
233 setup
->idle_action(setup
->idle_action
);
240 static device_t
*find_console(const char *name
)
244 for (i
= 1; i
!= ListNumItems(devlist
); i
++) {
245 device_t
*dev
= ListGetPtrToItem(devlist
, i
);
247 if (!strcmp(name
, dev
->name
))
248 if (dev
->flags
& DEV_FLAGS_OUTPUT
)
255 void bootmenu_add(const char *label
, void (*fn
)(void *user
), void *user
)
259 options
[num_options
].label
= label
;
260 options
[num_options
].fn
= fn
;
261 options
[num_options
].user
= user
;
270 void bootmenu_init(struct bootmenu_setup
*__setup
)
275 for (n
= 1; n
!= MAX_MENU_ITEMS
+1; n
++) {
276 const char *spec
, *colon
;
278 spec
= get_option(n
);
281 colon
= strchr(spec
, ':');
283 bootmenu_add(spec
, NULL
, (char *) spec
);
286 int len
= colon
-spec
;
288 label
= malloc(len
+1);
291 memcpy(label
, spec
, len
);
293 bootmenu_add(label
, NULL
, (char *) colon
+1);
301 bm_con
= find_console("vga");
302 if (bm_con
&& bm_con
->start
&& bm_con
->start() < 0)
305 bm_con
= stdio_devices
[stdout
];
309 console_assign(stdout
, "vga");
310 console_assign(stderr
, "vga");
313 console_poll_hook
= bootmenu_hook
;
316 #endif /* CFG_BOOTMENU */