xref: /rk3399_rockchip-uboot/cmd/bootmenu.c (revision 2e192b245ed36a63bab0ef576999a95e23f60ecd)
1*2e192b24SSimon Glass /*
2*2e192b24SSimon Glass  * (C) Copyright 2011-2013 Pali Rohár <pali.rohar@gmail.com>
3*2e192b24SSimon Glass  *
4*2e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
5*2e192b24SSimon Glass  */
6*2e192b24SSimon Glass 
7*2e192b24SSimon Glass #include <common.h>
8*2e192b24SSimon Glass #include <command.h>
9*2e192b24SSimon Glass #include <ansi.h>
10*2e192b24SSimon Glass #include <menu.h>
11*2e192b24SSimon Glass #include <watchdog.h>
12*2e192b24SSimon Glass #include <malloc.h>
13*2e192b24SSimon Glass #include <linux/string.h>
14*2e192b24SSimon Glass 
15*2e192b24SSimon Glass /* maximum bootmenu entries */
16*2e192b24SSimon Glass #define MAX_COUNT	99
17*2e192b24SSimon Glass 
18*2e192b24SSimon Glass /* maximal size of bootmenu env
19*2e192b24SSimon Glass  *  9 = strlen("bootmenu_")
20*2e192b24SSimon Glass  *  2 = strlen(MAX_COUNT)
21*2e192b24SSimon Glass  *  1 = NULL term
22*2e192b24SSimon Glass  */
23*2e192b24SSimon Glass #define MAX_ENV_SIZE	(9 + 2 + 1)
24*2e192b24SSimon Glass 
25*2e192b24SSimon Glass struct bootmenu_entry {
26*2e192b24SSimon Glass 	unsigned short int num;		/* unique number 0 .. MAX_COUNT */
27*2e192b24SSimon Glass 	char key[3];			/* key identifier of number */
28*2e192b24SSimon Glass 	char *title;			/* title of entry */
29*2e192b24SSimon Glass 	char *command;			/* hush command of entry */
30*2e192b24SSimon Glass 	struct bootmenu_data *menu;	/* this bootmenu */
31*2e192b24SSimon Glass 	struct bootmenu_entry *next;	/* next menu entry (num+1) */
32*2e192b24SSimon Glass };
33*2e192b24SSimon Glass 
34*2e192b24SSimon Glass struct bootmenu_data {
35*2e192b24SSimon Glass 	int delay;			/* delay for autoboot */
36*2e192b24SSimon Glass 	int active;			/* active menu entry */
37*2e192b24SSimon Glass 	int count;			/* total count of menu entries */
38*2e192b24SSimon Glass 	struct bootmenu_entry *first;	/* first menu entry */
39*2e192b24SSimon Glass };
40*2e192b24SSimon Glass 
41*2e192b24SSimon Glass enum bootmenu_key {
42*2e192b24SSimon Glass 	KEY_NONE = 0,
43*2e192b24SSimon Glass 	KEY_UP,
44*2e192b24SSimon Glass 	KEY_DOWN,
45*2e192b24SSimon Glass 	KEY_SELECT,
46*2e192b24SSimon Glass };
47*2e192b24SSimon Glass 
48*2e192b24SSimon Glass static char *bootmenu_getoption(unsigned short int n)
49*2e192b24SSimon Glass {
50*2e192b24SSimon Glass 	char name[MAX_ENV_SIZE];
51*2e192b24SSimon Glass 
52*2e192b24SSimon Glass 	if (n > MAX_COUNT)
53*2e192b24SSimon Glass 		return NULL;
54*2e192b24SSimon Glass 
55*2e192b24SSimon Glass 	sprintf(name, "bootmenu_%d", n);
56*2e192b24SSimon Glass 	return getenv(name);
57*2e192b24SSimon Glass }
58*2e192b24SSimon Glass 
59*2e192b24SSimon Glass static void bootmenu_print_entry(void *data)
60*2e192b24SSimon Glass {
61*2e192b24SSimon Glass 	struct bootmenu_entry *entry = data;
62*2e192b24SSimon Glass 	int reverse = (entry->menu->active == entry->num);
63*2e192b24SSimon Glass 
64*2e192b24SSimon Glass 	/*
65*2e192b24SSimon Glass 	 * Move cursor to line where the entry will be drown (entry->num)
66*2e192b24SSimon Glass 	 * First 3 lines contain bootmenu header + 1 empty line
67*2e192b24SSimon Glass 	 */
68*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, entry->num + 4, 1);
69*2e192b24SSimon Glass 
70*2e192b24SSimon Glass 	puts("     ");
71*2e192b24SSimon Glass 
72*2e192b24SSimon Glass 	if (reverse)
73*2e192b24SSimon Glass 		puts(ANSI_COLOR_REVERSE);
74*2e192b24SSimon Glass 
75*2e192b24SSimon Glass 	puts(entry->title);
76*2e192b24SSimon Glass 
77*2e192b24SSimon Glass 	if (reverse)
78*2e192b24SSimon Glass 		puts(ANSI_COLOR_RESET);
79*2e192b24SSimon Glass }
80*2e192b24SSimon Glass 
81*2e192b24SSimon Glass static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
82*2e192b24SSimon Glass 				enum bootmenu_key *key, int *esc)
83*2e192b24SSimon Glass {
84*2e192b24SSimon Glass 	int i, c;
85*2e192b24SSimon Glass 
86*2e192b24SSimon Glass 	if (menu->delay > 0) {
87*2e192b24SSimon Glass 		printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
88*2e192b24SSimon Glass 		printf("  Hit any key to stop autoboot: %2d ", menu->delay);
89*2e192b24SSimon Glass 	}
90*2e192b24SSimon Glass 
91*2e192b24SSimon Glass 	while (menu->delay > 0) {
92*2e192b24SSimon Glass 		for (i = 0; i < 100; ++i) {
93*2e192b24SSimon Glass 			if (!tstc()) {
94*2e192b24SSimon Glass 				WATCHDOG_RESET();
95*2e192b24SSimon Glass 				mdelay(10);
96*2e192b24SSimon Glass 				continue;
97*2e192b24SSimon Glass 			}
98*2e192b24SSimon Glass 
99*2e192b24SSimon Glass 			menu->delay = -1;
100*2e192b24SSimon Glass 			c = getc();
101*2e192b24SSimon Glass 
102*2e192b24SSimon Glass 			switch (c) {
103*2e192b24SSimon Glass 			case '\e':
104*2e192b24SSimon Glass 				*esc = 1;
105*2e192b24SSimon Glass 				*key = KEY_NONE;
106*2e192b24SSimon Glass 				break;
107*2e192b24SSimon Glass 			case '\r':
108*2e192b24SSimon Glass 				*key = KEY_SELECT;
109*2e192b24SSimon Glass 				break;
110*2e192b24SSimon Glass 			default:
111*2e192b24SSimon Glass 				*key = KEY_NONE;
112*2e192b24SSimon Glass 				break;
113*2e192b24SSimon Glass 			}
114*2e192b24SSimon Glass 
115*2e192b24SSimon Glass 			break;
116*2e192b24SSimon Glass 		}
117*2e192b24SSimon Glass 
118*2e192b24SSimon Glass 		if (menu->delay < 0)
119*2e192b24SSimon Glass 			break;
120*2e192b24SSimon Glass 
121*2e192b24SSimon Glass 		--menu->delay;
122*2e192b24SSimon Glass 		printf("\b\b\b%2d ", menu->delay);
123*2e192b24SSimon Glass 	}
124*2e192b24SSimon Glass 
125*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
126*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE);
127*2e192b24SSimon Glass 
128*2e192b24SSimon Glass 	if (menu->delay == 0)
129*2e192b24SSimon Glass 		*key = KEY_SELECT;
130*2e192b24SSimon Glass }
131*2e192b24SSimon Glass 
132*2e192b24SSimon Glass static void bootmenu_loop(struct bootmenu_data *menu,
133*2e192b24SSimon Glass 		enum bootmenu_key *key, int *esc)
134*2e192b24SSimon Glass {
135*2e192b24SSimon Glass 	int c;
136*2e192b24SSimon Glass 
137*2e192b24SSimon Glass 	while (!tstc()) {
138*2e192b24SSimon Glass 		WATCHDOG_RESET();
139*2e192b24SSimon Glass 		mdelay(10);
140*2e192b24SSimon Glass 	}
141*2e192b24SSimon Glass 
142*2e192b24SSimon Glass 	c = getc();
143*2e192b24SSimon Glass 
144*2e192b24SSimon Glass 	switch (*esc) {
145*2e192b24SSimon Glass 	case 0:
146*2e192b24SSimon Glass 		/* First char of ANSI escape sequence '\e' */
147*2e192b24SSimon Glass 		if (c == '\e') {
148*2e192b24SSimon Glass 			*esc = 1;
149*2e192b24SSimon Glass 			*key = KEY_NONE;
150*2e192b24SSimon Glass 		}
151*2e192b24SSimon Glass 		break;
152*2e192b24SSimon Glass 	case 1:
153*2e192b24SSimon Glass 		/* Second char of ANSI '[' */
154*2e192b24SSimon Glass 		if (c == '[') {
155*2e192b24SSimon Glass 			*esc = 2;
156*2e192b24SSimon Glass 			*key = KEY_NONE;
157*2e192b24SSimon Glass 		} else {
158*2e192b24SSimon Glass 			*esc = 0;
159*2e192b24SSimon Glass 		}
160*2e192b24SSimon Glass 		break;
161*2e192b24SSimon Glass 	case 2:
162*2e192b24SSimon Glass 	case 3:
163*2e192b24SSimon Glass 		/* Third char of ANSI (number '1') - optional */
164*2e192b24SSimon Glass 		if (*esc == 2 && c == '1') {
165*2e192b24SSimon Glass 			*esc = 3;
166*2e192b24SSimon Glass 			*key = KEY_NONE;
167*2e192b24SSimon Glass 			break;
168*2e192b24SSimon Glass 		}
169*2e192b24SSimon Glass 
170*2e192b24SSimon Glass 		*esc = 0;
171*2e192b24SSimon Glass 
172*2e192b24SSimon Glass 		/* ANSI 'A' - key up was pressed */
173*2e192b24SSimon Glass 		if (c == 'A')
174*2e192b24SSimon Glass 			*key = KEY_UP;
175*2e192b24SSimon Glass 		/* ANSI 'B' - key down was pressed */
176*2e192b24SSimon Glass 		else if (c == 'B')
177*2e192b24SSimon Glass 			*key = KEY_DOWN;
178*2e192b24SSimon Glass 		/* other key was pressed */
179*2e192b24SSimon Glass 		else
180*2e192b24SSimon Glass 			*key = KEY_NONE;
181*2e192b24SSimon Glass 
182*2e192b24SSimon Glass 		break;
183*2e192b24SSimon Glass 	}
184*2e192b24SSimon Glass 
185*2e192b24SSimon Glass 	/* enter key was pressed */
186*2e192b24SSimon Glass 	if (c == '\r')
187*2e192b24SSimon Glass 		*key = KEY_SELECT;
188*2e192b24SSimon Glass }
189*2e192b24SSimon Glass 
190*2e192b24SSimon Glass static char *bootmenu_choice_entry(void *data)
191*2e192b24SSimon Glass {
192*2e192b24SSimon Glass 	struct bootmenu_data *menu = data;
193*2e192b24SSimon Glass 	struct bootmenu_entry *iter;
194*2e192b24SSimon Glass 	enum bootmenu_key key = KEY_NONE;
195*2e192b24SSimon Glass 	int esc = 0;
196*2e192b24SSimon Glass 	int i;
197*2e192b24SSimon Glass 
198*2e192b24SSimon Glass 	while (1) {
199*2e192b24SSimon Glass 		if (menu->delay >= 0) {
200*2e192b24SSimon Glass 			/* Autoboot was not stopped */
201*2e192b24SSimon Glass 			bootmenu_autoboot_loop(menu, &key, &esc);
202*2e192b24SSimon Glass 		} else {
203*2e192b24SSimon Glass 			/* Some key was pressed, so autoboot was stopped */
204*2e192b24SSimon Glass 			bootmenu_loop(menu, &key, &esc);
205*2e192b24SSimon Glass 		}
206*2e192b24SSimon Glass 
207*2e192b24SSimon Glass 		switch (key) {
208*2e192b24SSimon Glass 		case KEY_UP:
209*2e192b24SSimon Glass 			if (menu->active > 0)
210*2e192b24SSimon Glass 				--menu->active;
211*2e192b24SSimon Glass 			/* no menu key selected, regenerate menu */
212*2e192b24SSimon Glass 			return NULL;
213*2e192b24SSimon Glass 		case KEY_DOWN:
214*2e192b24SSimon Glass 			if (menu->active < menu->count - 1)
215*2e192b24SSimon Glass 				++menu->active;
216*2e192b24SSimon Glass 			/* no menu key selected, regenerate menu */
217*2e192b24SSimon Glass 			return NULL;
218*2e192b24SSimon Glass 		case KEY_SELECT:
219*2e192b24SSimon Glass 			iter = menu->first;
220*2e192b24SSimon Glass 			for (i = 0; i < menu->active; ++i)
221*2e192b24SSimon Glass 				iter = iter->next;
222*2e192b24SSimon Glass 			return iter->key;
223*2e192b24SSimon Glass 		default:
224*2e192b24SSimon Glass 			break;
225*2e192b24SSimon Glass 		}
226*2e192b24SSimon Glass 	}
227*2e192b24SSimon Glass 
228*2e192b24SSimon Glass 	/* never happens */
229*2e192b24SSimon Glass 	debug("bootmenu: this should not happen");
230*2e192b24SSimon Glass 	return NULL;
231*2e192b24SSimon Glass }
232*2e192b24SSimon Glass 
233*2e192b24SSimon Glass static void bootmenu_destroy(struct bootmenu_data *menu)
234*2e192b24SSimon Glass {
235*2e192b24SSimon Glass 	struct bootmenu_entry *iter = menu->first;
236*2e192b24SSimon Glass 	struct bootmenu_entry *next;
237*2e192b24SSimon Glass 
238*2e192b24SSimon Glass 	while (iter) {
239*2e192b24SSimon Glass 		next = iter->next;
240*2e192b24SSimon Glass 		free(iter->title);
241*2e192b24SSimon Glass 		free(iter->command);
242*2e192b24SSimon Glass 		free(iter);
243*2e192b24SSimon Glass 		iter = next;
244*2e192b24SSimon Glass 	}
245*2e192b24SSimon Glass 	free(menu);
246*2e192b24SSimon Glass }
247*2e192b24SSimon Glass 
248*2e192b24SSimon Glass static struct bootmenu_data *bootmenu_create(int delay)
249*2e192b24SSimon Glass {
250*2e192b24SSimon Glass 	unsigned short int i = 0;
251*2e192b24SSimon Glass 	const char *option;
252*2e192b24SSimon Glass 	struct bootmenu_data *menu;
253*2e192b24SSimon Glass 	struct bootmenu_entry *iter = NULL;
254*2e192b24SSimon Glass 
255*2e192b24SSimon Glass 	int len;
256*2e192b24SSimon Glass 	char *sep;
257*2e192b24SSimon Glass 	struct bootmenu_entry *entry;
258*2e192b24SSimon Glass 
259*2e192b24SSimon Glass 	menu = malloc(sizeof(struct bootmenu_data));
260*2e192b24SSimon Glass 	if (!menu)
261*2e192b24SSimon Glass 		return NULL;
262*2e192b24SSimon Glass 
263*2e192b24SSimon Glass 	menu->delay = delay;
264*2e192b24SSimon Glass 	menu->active = 0;
265*2e192b24SSimon Glass 	menu->first = NULL;
266*2e192b24SSimon Glass 
267*2e192b24SSimon Glass 	while ((option = bootmenu_getoption(i))) {
268*2e192b24SSimon Glass 		sep = strchr(option, '=');
269*2e192b24SSimon Glass 		if (!sep) {
270*2e192b24SSimon Glass 			printf("Invalid bootmenu entry: %s\n", option);
271*2e192b24SSimon Glass 			break;
272*2e192b24SSimon Glass 		}
273*2e192b24SSimon Glass 
274*2e192b24SSimon Glass 		entry = malloc(sizeof(struct bootmenu_entry));
275*2e192b24SSimon Glass 		if (!entry)
276*2e192b24SSimon Glass 			goto cleanup;
277*2e192b24SSimon Glass 
278*2e192b24SSimon Glass 		len = sep-option;
279*2e192b24SSimon Glass 		entry->title = malloc(len + 1);
280*2e192b24SSimon Glass 		if (!entry->title) {
281*2e192b24SSimon Glass 			free(entry);
282*2e192b24SSimon Glass 			goto cleanup;
283*2e192b24SSimon Glass 		}
284*2e192b24SSimon Glass 		memcpy(entry->title, option, len);
285*2e192b24SSimon Glass 		entry->title[len] = 0;
286*2e192b24SSimon Glass 
287*2e192b24SSimon Glass 		len = strlen(sep + 1);
288*2e192b24SSimon Glass 		entry->command = malloc(len + 1);
289*2e192b24SSimon Glass 		if (!entry->command) {
290*2e192b24SSimon Glass 			free(entry->title);
291*2e192b24SSimon Glass 			free(entry);
292*2e192b24SSimon Glass 			goto cleanup;
293*2e192b24SSimon Glass 		}
294*2e192b24SSimon Glass 		memcpy(entry->command, sep + 1, len);
295*2e192b24SSimon Glass 		entry->command[len] = 0;
296*2e192b24SSimon Glass 
297*2e192b24SSimon Glass 		sprintf(entry->key, "%d", i);
298*2e192b24SSimon Glass 
299*2e192b24SSimon Glass 		entry->num = i;
300*2e192b24SSimon Glass 		entry->menu = menu;
301*2e192b24SSimon Glass 		entry->next = NULL;
302*2e192b24SSimon Glass 
303*2e192b24SSimon Glass 		if (!iter)
304*2e192b24SSimon Glass 			menu->first = entry;
305*2e192b24SSimon Glass 		else
306*2e192b24SSimon Glass 			iter->next = entry;
307*2e192b24SSimon Glass 
308*2e192b24SSimon Glass 		iter = entry;
309*2e192b24SSimon Glass 		++i;
310*2e192b24SSimon Glass 
311*2e192b24SSimon Glass 		if (i == MAX_COUNT - 1)
312*2e192b24SSimon Glass 			break;
313*2e192b24SSimon Glass 	}
314*2e192b24SSimon Glass 
315*2e192b24SSimon Glass 	/* Add U-Boot console entry at the end */
316*2e192b24SSimon Glass 	if (i <= MAX_COUNT - 1) {
317*2e192b24SSimon Glass 		entry = malloc(sizeof(struct bootmenu_entry));
318*2e192b24SSimon Glass 		if (!entry)
319*2e192b24SSimon Glass 			goto cleanup;
320*2e192b24SSimon Glass 
321*2e192b24SSimon Glass 		entry->title = strdup("U-Boot console");
322*2e192b24SSimon Glass 		if (!entry->title) {
323*2e192b24SSimon Glass 			free(entry);
324*2e192b24SSimon Glass 			goto cleanup;
325*2e192b24SSimon Glass 		}
326*2e192b24SSimon Glass 
327*2e192b24SSimon Glass 		entry->command = strdup("");
328*2e192b24SSimon Glass 		if (!entry->command) {
329*2e192b24SSimon Glass 			free(entry->title);
330*2e192b24SSimon Glass 			free(entry);
331*2e192b24SSimon Glass 			goto cleanup;
332*2e192b24SSimon Glass 		}
333*2e192b24SSimon Glass 
334*2e192b24SSimon Glass 		sprintf(entry->key, "%d", i);
335*2e192b24SSimon Glass 
336*2e192b24SSimon Glass 		entry->num = i;
337*2e192b24SSimon Glass 		entry->menu = menu;
338*2e192b24SSimon Glass 		entry->next = NULL;
339*2e192b24SSimon Glass 
340*2e192b24SSimon Glass 		if (!iter)
341*2e192b24SSimon Glass 			menu->first = entry;
342*2e192b24SSimon Glass 		else
343*2e192b24SSimon Glass 			iter->next = entry;
344*2e192b24SSimon Glass 
345*2e192b24SSimon Glass 		iter = entry;
346*2e192b24SSimon Glass 		++i;
347*2e192b24SSimon Glass 	}
348*2e192b24SSimon Glass 
349*2e192b24SSimon Glass 	menu->count = i;
350*2e192b24SSimon Glass 	return menu;
351*2e192b24SSimon Glass 
352*2e192b24SSimon Glass cleanup:
353*2e192b24SSimon Glass 	bootmenu_destroy(menu);
354*2e192b24SSimon Glass 	return NULL;
355*2e192b24SSimon Glass }
356*2e192b24SSimon Glass 
357*2e192b24SSimon Glass static void bootmenu_show(int delay)
358*2e192b24SSimon Glass {
359*2e192b24SSimon Glass 	int init = 0;
360*2e192b24SSimon Glass 	void *choice = NULL;
361*2e192b24SSimon Glass 	char *title = NULL;
362*2e192b24SSimon Glass 	char *command = NULL;
363*2e192b24SSimon Glass 	struct menu *menu;
364*2e192b24SSimon Glass 	struct bootmenu_data *bootmenu;
365*2e192b24SSimon Glass 	struct bootmenu_entry *iter;
366*2e192b24SSimon Glass 	char *option, *sep;
367*2e192b24SSimon Glass 
368*2e192b24SSimon Glass 	/* If delay is 0 do not create menu, just run first entry */
369*2e192b24SSimon Glass 	if (delay == 0) {
370*2e192b24SSimon Glass 		option = bootmenu_getoption(0);
371*2e192b24SSimon Glass 		if (!option) {
372*2e192b24SSimon Glass 			puts("bootmenu option 0 was not found\n");
373*2e192b24SSimon Glass 			return;
374*2e192b24SSimon Glass 		}
375*2e192b24SSimon Glass 		sep = strchr(option, '=');
376*2e192b24SSimon Glass 		if (!sep) {
377*2e192b24SSimon Glass 			puts("bootmenu option 0 is invalid\n");
378*2e192b24SSimon Glass 			return;
379*2e192b24SSimon Glass 		}
380*2e192b24SSimon Glass 		run_command(sep+1, 0);
381*2e192b24SSimon Glass 		return;
382*2e192b24SSimon Glass 	}
383*2e192b24SSimon Glass 
384*2e192b24SSimon Glass 	bootmenu = bootmenu_create(delay);
385*2e192b24SSimon Glass 	if (!bootmenu)
386*2e192b24SSimon Glass 		return;
387*2e192b24SSimon Glass 
388*2e192b24SSimon Glass 	menu = menu_create(NULL, bootmenu->delay, 1, bootmenu_print_entry,
389*2e192b24SSimon Glass 			   bootmenu_choice_entry, bootmenu);
390*2e192b24SSimon Glass 	if (!menu) {
391*2e192b24SSimon Glass 		bootmenu_destroy(bootmenu);
392*2e192b24SSimon Glass 		return;
393*2e192b24SSimon Glass 	}
394*2e192b24SSimon Glass 
395*2e192b24SSimon Glass 	for (iter = bootmenu->first; iter; iter = iter->next) {
396*2e192b24SSimon Glass 		if (!menu_item_add(menu, iter->key, iter))
397*2e192b24SSimon Glass 			goto cleanup;
398*2e192b24SSimon Glass 	}
399*2e192b24SSimon Glass 
400*2e192b24SSimon Glass 	/* Default menu entry is always first */
401*2e192b24SSimon Glass 	menu_default_set(menu, "0");
402*2e192b24SSimon Glass 
403*2e192b24SSimon Glass 	puts(ANSI_CURSOR_HIDE);
404*2e192b24SSimon Glass 	puts(ANSI_CLEAR_CONSOLE);
405*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, 1, 1);
406*2e192b24SSimon Glass 
407*2e192b24SSimon Glass 	init = 1;
408*2e192b24SSimon Glass 
409*2e192b24SSimon Glass 	if (menu_get_choice(menu, &choice)) {
410*2e192b24SSimon Glass 		iter = choice;
411*2e192b24SSimon Glass 		title = strdup(iter->title);
412*2e192b24SSimon Glass 		command = strdup(iter->command);
413*2e192b24SSimon Glass 	}
414*2e192b24SSimon Glass 
415*2e192b24SSimon Glass cleanup:
416*2e192b24SSimon Glass 	menu_destroy(menu);
417*2e192b24SSimon Glass 	bootmenu_destroy(bootmenu);
418*2e192b24SSimon Glass 
419*2e192b24SSimon Glass 	if (init) {
420*2e192b24SSimon Glass 		puts(ANSI_CURSOR_SHOW);
421*2e192b24SSimon Glass 		puts(ANSI_CLEAR_CONSOLE);
422*2e192b24SSimon Glass 		printf(ANSI_CURSOR_POSITION, 1, 1);
423*2e192b24SSimon Glass 	}
424*2e192b24SSimon Glass 
425*2e192b24SSimon Glass 	if (title && command) {
426*2e192b24SSimon Glass 		debug("Starting entry '%s'\n", title);
427*2e192b24SSimon Glass 		free(title);
428*2e192b24SSimon Glass 		run_command(command, 0);
429*2e192b24SSimon Glass 		free(command);
430*2e192b24SSimon Glass 	}
431*2e192b24SSimon Glass 
432*2e192b24SSimon Glass #ifdef CONFIG_POSTBOOTMENU
433*2e192b24SSimon Glass 	run_command(CONFIG_POSTBOOTMENU, 0);
434*2e192b24SSimon Glass #endif
435*2e192b24SSimon Glass }
436*2e192b24SSimon Glass 
437*2e192b24SSimon Glass void menu_display_statusline(struct menu *m)
438*2e192b24SSimon Glass {
439*2e192b24SSimon Glass 	struct bootmenu_entry *entry;
440*2e192b24SSimon Glass 	struct bootmenu_data *menu;
441*2e192b24SSimon Glass 
442*2e192b24SSimon Glass 	if (menu_default_choice(m, (void *)&entry) < 0)
443*2e192b24SSimon Glass 		return;
444*2e192b24SSimon Glass 
445*2e192b24SSimon Glass 	menu = entry->menu;
446*2e192b24SSimon Glass 
447*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, 1, 1);
448*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE);
449*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, 2, 1);
450*2e192b24SSimon Glass 	puts("  *** U-Boot Boot Menu ***");
451*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE_TO_END);
452*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, 3, 1);
453*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE);
454*2e192b24SSimon Glass 
455*2e192b24SSimon Glass 	/* First 3 lines are bootmenu header + 2 empty lines between entries */
456*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
457*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE);
458*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, menu->count + 6, 1);
459*2e192b24SSimon Glass 	puts("  Press UP/DOWN to move, ENTER to select");
460*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE_TO_END);
461*2e192b24SSimon Glass 	printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
462*2e192b24SSimon Glass 	puts(ANSI_CLEAR_LINE);
463*2e192b24SSimon Glass }
464*2e192b24SSimon Glass 
465*2e192b24SSimon Glass #ifdef CONFIG_MENU_SHOW
466*2e192b24SSimon Glass int menu_show(int bootdelay)
467*2e192b24SSimon Glass {
468*2e192b24SSimon Glass 	bootmenu_show(bootdelay);
469*2e192b24SSimon Glass 	return -1; /* -1 - abort boot and run monitor code */
470*2e192b24SSimon Glass }
471*2e192b24SSimon Glass #endif
472*2e192b24SSimon Glass 
473*2e192b24SSimon Glass int do_bootmenu(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
474*2e192b24SSimon Glass {
475*2e192b24SSimon Glass 	char *delay_str = NULL;
476*2e192b24SSimon Glass 	int delay = 10;
477*2e192b24SSimon Glass 
478*2e192b24SSimon Glass #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
479*2e192b24SSimon Glass 	delay = CONFIG_BOOTDELAY;
480*2e192b24SSimon Glass #endif
481*2e192b24SSimon Glass 
482*2e192b24SSimon Glass 	if (argc >= 2)
483*2e192b24SSimon Glass 		delay_str = argv[1];
484*2e192b24SSimon Glass 
485*2e192b24SSimon Glass 	if (!delay_str)
486*2e192b24SSimon Glass 		delay_str = getenv("bootmenu_delay");
487*2e192b24SSimon Glass 
488*2e192b24SSimon Glass 	if (delay_str)
489*2e192b24SSimon Glass 		delay = (int)simple_strtol(delay_str, NULL, 10);
490*2e192b24SSimon Glass 
491*2e192b24SSimon Glass 	bootmenu_show(delay);
492*2e192b24SSimon Glass 	return 0;
493*2e192b24SSimon Glass }
494*2e192b24SSimon Glass 
495*2e192b24SSimon Glass U_BOOT_CMD(
496*2e192b24SSimon Glass 	bootmenu, 2, 1, do_bootmenu,
497*2e192b24SSimon Glass 	"ANSI terminal bootmenu",
498*2e192b24SSimon Glass 	"[delay]\n"
499*2e192b24SSimon Glass 	"    - show ANSI terminal bootmenu with autoboot delay"
500*2e192b24SSimon Glass );
501