doc: usage: load: document part as hexadecimal
[platform/kernel/u-boot.git] / common / menu.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2010-2011 Calxeda, Inc.
4  * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
5  */
6
7 #include <ansi.h>
8 #include <common.h>
9 #include <cli.h>
10 #include <malloc.h>
11 #include <errno.h>
12 #include <linux/delay.h>
13 #include <linux/list.h>
14 #include <watchdog.h>
15
16 #include "menu.h"
17
18 #define ansi 1
19
20 /*
21  * Internally, each item in a menu is represented by a struct menu_item.
22  *
23  * These items will be alloc'd and initialized by menu_item_add and destroyed
24  * by menu_item_destroy, and the consumer of the interface never sees that
25  * this struct is used at all.
26  */
27 struct menu_item {
28         char *key;
29         void *data;
30         struct list_head list;
31 };
32
33 /*
34  * The menu is composed of a list of items along with settings and callbacks
35  * provided by the user. An incomplete definition of this struct is available
36  * in menu.h, but the full definition is here to prevent consumers from
37  * relying on its contents.
38  */
39 struct menu {
40         struct menu_item *default_item;
41         int timeout;
42         char *title;
43         int prompt;
44         void (*display_statusline)(struct menu *);
45         void (*item_data_print)(void *);
46         char *(*item_choice)(void *);
47         void *item_choice_data;
48         struct list_head items;
49         int item_cnt;
50 };
51
52 /*
53  * An iterator function for menu items. callback will be called for each item
54  * in m, with m, a pointer to the item, and extra being passed to callback. If
55  * callback returns a value other than NULL, iteration stops and the value
56  * return by callback is returned from menu_items_iter.  This allows it to be
57  * used for search type operations. It is also safe for callback to remove the
58  * item from the list of items.
59  */
60 static inline void *menu_items_iter(struct menu *m,
61                 void *(*callback)(struct menu *, struct menu_item *, void *),
62                 void *extra)
63 {
64         struct list_head *pos, *n;
65         struct menu_item *item;
66         void *ret;
67
68         list_for_each_safe(pos, n, &m->items) {
69                 item = list_entry(pos, struct menu_item, list);
70
71                 ret = callback(m, item, extra);
72
73                 if (ret)
74                         return ret;
75         }
76
77         return NULL;
78 }
79
80 /*
81  * Print a menu_item. If the consumer provided an item_data_print function
82  * when creating the menu, call it with a pointer to the item's private data.
83  * Otherwise, print the key of the item.
84  */
85 static inline void *menu_item_print(struct menu *m,
86                                 struct menu_item *item,
87                                 void *extra)
88 {
89         if (!m->item_data_print) {
90                 puts(item->key);
91                 putc('\n');
92         } else {
93                 m->item_data_print(item->data);
94         }
95
96         return NULL;
97 }
98
99 /*
100  * Free the memory used by a menu item. This includes the memory used by its
101  * key.
102  */
103 static inline void *menu_item_destroy(struct menu *m,
104                                 struct menu_item *item,
105                                 void *extra)
106 {
107         if (item->key)
108                 free(item->key);
109
110         free(item);
111
112         return NULL;
113 }
114
115 /*
116  * Display a menu so the user can make a choice of an item. First display its
117  * title, if any, and then each item in the menu.
118  */
119 static inline void menu_display(struct menu *m)
120 {
121         if (m->title) {
122                 puts(m->title);
123                 putc('\n');
124         }
125         if (m->display_statusline)
126                 m->display_statusline(m);
127
128         menu_items_iter(m, menu_item_print, NULL);
129 }
130
131 /*
132  * Check if an item's key matches a provided string, pointed to by extra. If
133  * extra is NULL, an item with a NULL key will match. Otherwise, the item's
134  * key has to match according to strcmp.
135  *
136  * This is called via menu_items_iter, so it returns a pointer to the item if
137  * the key matches, and returns NULL otherwise.
138  */
139 static inline void *menu_item_key_match(struct menu *m,
140                         struct menu_item *item, void *extra)
141 {
142         char *item_key = extra;
143
144         if (!item_key || !item->key) {
145                 if (item_key == item->key)
146                         return item;
147
148                 return NULL;
149         }
150
151         if (strcmp(item->key, item_key) == 0)
152                 return item;
153
154         return NULL;
155 }
156
157 /*
158  * Find the first item with a key matching item_key, if any exists.
159  */
160 static inline struct menu_item *menu_item_by_key(struct menu *m,
161                                                         char *item_key)
162 {
163         return menu_items_iter(m, menu_item_key_match, item_key);
164 }
165
166 /*
167  * Set *choice to point to the default item's data, if any default item was
168  * set, and returns 1. If no default item was set, returns -ENOENT.
169  */
170 int menu_default_choice(struct menu *m, void **choice)
171 {
172         if (m->default_item) {
173                 *choice = m->default_item->data;
174                 return 1;
175         }
176
177         return -ENOENT;
178 }
179
180 /*
181  * Displays the menu and asks the user to choose an item. *choice will point
182  * to the private data of the item the user chooses. The user makes a choice
183  * by inputting a string matching the key of an item. Invalid choices will
184  * cause the user to be prompted again, repeatedly, until the user makes a
185  * valid choice. The user can exit the menu without making a choice via ^c.
186  *
187  * Returns 1 if the user made a choice, or -EINTR if they bail via ^c.
188  */
189 static inline int menu_interactive_choice(struct menu *m, void **choice)
190 {
191         char cbuf[CONFIG_SYS_CBSIZE];
192         struct menu_item *choice_item = NULL;
193         int readret;
194
195         while (!choice_item) {
196                 cbuf[0] = '\0';
197
198                 menu_display(m);
199
200                 if (!m->item_choice) {
201                         readret = cli_readline_into_buffer("Enter choice: ",
202                                                            cbuf, m->timeout);
203
204                         if (readret >= 0) {
205                                 choice_item = menu_item_by_key(m, cbuf);
206                                 if (!choice_item)
207                                         printf("%s not found\n", cbuf);
208                         } else if (readret == -1)  {
209                                 printf("<INTERRUPT>\n");
210                                 return -EINTR;
211                         } else {
212                                 return menu_default_choice(m, choice);
213                         }
214                 } else {
215                         char *key = m->item_choice(m->item_choice_data);
216
217                         if (key)
218                                 choice_item = menu_item_by_key(m, key);
219                 }
220
221                 if (!choice_item)
222                         m->timeout = 0;
223         }
224
225         *choice = choice_item->data;
226
227         return 1;
228 }
229
230 /*
231  * menu_default_set() - Sets the default choice for the menu. This is safe to
232  * call more than once on a menu.
233  *
234  * m - Points to a menu created by menu_create().
235  *
236  * item_key - Points to a string that, when compared using strcmp, matches the
237  * key for an existing item in the menu.
238  *
239  * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a
240  * key matching item_key is found.
241  */
242 int menu_default_set(struct menu *m, char *item_key)
243 {
244         struct menu_item *item;
245
246         if (!m)
247                 return -EINVAL;
248
249         item = menu_item_by_key(m, item_key);
250
251         if (!item)
252                 return -ENOENT;
253
254         m->default_item = item;
255
256         return 1;
257 }
258
259 /*
260  * menu_get_choice() - Returns the user's selected menu entry, or the default
261  * if the menu is set to not prompt or the timeout expires. This is safe to
262  * call more than once.
263  *
264  * m - Points to a menu created by menu_create().
265  *
266  * choice - Points to a location that will store a pointer to the selected
267  * menu item. If no item is selected or there is an error, no value will be
268  * written at the location it points to.
269  *
270  * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no
271  * default has been set and the menu is set to not prompt or the timeout
272  * expires, or -EINTR if the user exits the menu via ^c.
273  */
274 int menu_get_choice(struct menu *m, void **choice)
275 {
276         if (!m || !choice)
277                 return -EINVAL;
278
279         if (!m->item_cnt)
280                 return -ENOENT;
281
282         if (!m->prompt)
283                 return menu_default_choice(m, choice);
284
285         return menu_interactive_choice(m, choice);
286 }
287
288 /*
289  * menu_item_add() - Adds or replaces a menu item. Note that this replaces the
290  * data of an item if it already exists, but doesn't change the order of the
291  * item.
292  *
293  * m - Points to a menu created by menu_create().
294  *
295  * item_key - Points to a string that will uniquely identify the item.  The
296  * string will be copied to internal storage, and is safe to discard after
297  * passing to menu_item_add.
298  *
299  * item_data - An opaque pointer associated with an item. It is never
300  * dereferenced internally, but will be passed to the item_data_print, and
301  * will be returned from menu_get_choice if the menu item is selected.
302  *
303  * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is
304  * insufficient memory to add the menu item.
305  */
306 int menu_item_add(struct menu *m, char *item_key, void *item_data)
307 {
308         struct menu_item *item;
309
310         if (!m)
311                 return -EINVAL;
312
313         item = menu_item_by_key(m, item_key);
314
315         if (item) {
316                 item->data = item_data;
317                 return 1;
318         }
319
320         item = malloc(sizeof *item);
321         if (!item)
322                 return -ENOMEM;
323
324         item->key = strdup(item_key);
325
326         if (!item->key) {
327                 free(item);
328                 return -ENOMEM;
329         }
330
331         item->data = item_data;
332
333         list_add_tail(&item->list, &m->items);
334         m->item_cnt++;
335
336         return 1;
337 }
338
339 /*
340  * menu_create() - Creates a menu handle with default settings
341  *
342  * title - If not NULL, points to a string that will be displayed before the
343  * list of menu items. It will be copied to internal storage, and is safe to
344  * discard after passing to menu_create().
345  *
346  * timeout - A delay in seconds to wait for user input. If 0, timeout is
347  * disabled, and the default choice will be returned unless prompt is 1.
348  *
349  * prompt - If 0, don't ask for user input unless there is an interrupted
350  * timeout. If 1, the user will be prompted for input regardless of the value
351  * of timeout.
352  *
353  * display_statusline - If not NULL, will be called to show a statusline when
354  * the menu is displayed.
355  *
356  * item_data_print - If not NULL, will be called for each item when the menu
357  * is displayed, with the pointer to the item's data passed as the argument.
358  * If NULL, each item's key will be printed instead.  Since an item's key is
359  * what must be entered to select an item, the item_data_print function should
360  * make it obvious what the key for each entry is.
361  *
362  * item_choice - If not NULL, will be called when asking the user to choose an
363  * item. Returns a key string corresponding to the chosen item or NULL if
364  * no item has been selected.
365  *
366  * item_choice_data - Will be passed as the argument to the item_choice function
367  *
368  * Returns a pointer to the menu if successful, or NULL if there is
369  * insufficient memory available to create the menu.
370  */
371 struct menu *menu_create(char *title, int timeout, int prompt,
372                                 void (*display_statusline)(struct menu *),
373                                 void (*item_data_print)(void *),
374                                 char *(*item_choice)(void *),
375                                 void *item_choice_data)
376 {
377         struct menu *m;
378
379         m = malloc(sizeof *m);
380
381         if (!m)
382                 return NULL;
383
384         m->default_item = NULL;
385         m->prompt = prompt;
386         m->timeout = timeout;
387         m->display_statusline = display_statusline;
388         m->item_data_print = item_data_print;
389         m->item_choice = item_choice;
390         m->item_choice_data = item_choice_data;
391         m->item_cnt = 0;
392
393         if (title) {
394                 m->title = strdup(title);
395                 if (!m->title) {
396                         free(m);
397                         return NULL;
398                 }
399         } else
400                 m->title = NULL;
401
402
403         INIT_LIST_HEAD(&m->items);
404
405         return m;
406 }
407
408 /*
409  * menu_destroy() - frees the memory used by a menu and its items.
410  *
411  * m - Points to a menu created by menu_create().
412  *
413  * Returns 1 if successful, or -EINVAL if m is NULL.
414  */
415 int menu_destroy(struct menu *m)
416 {
417         if (!m)
418                 return -EINVAL;
419
420         menu_items_iter(m, menu_item_destroy, NULL);
421
422         if (m->title)
423                 free(m->title);
424
425         free(m);
426
427         return 1;
428 }
429
430 enum bootmenu_key bootmenu_autoboot_loop(struct bootmenu_data *menu,
431                                          struct cli_ch_state *cch)
432 {
433         enum bootmenu_key key = BKEY_NONE;
434         int i, c;
435
436         while (menu->delay > 0) {
437                 if (ansi)
438                         printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
439                 printf("Hit any key to stop autoboot: %d ", menu->delay);
440                 for (i = 0; i < 100; ++i) {
441                         int ichar;
442
443                         if (!tstc()) {
444                                 schedule();
445                                 mdelay(10);
446                                 continue;
447                         }
448
449                         menu->delay = -1;
450                         c = getchar();
451
452                         ichar = cli_ch_process(cch, c);
453
454                         switch (ichar) {
455                         case '\0':
456                                 key = BKEY_NONE;
457                                 break;
458                         case '\n':
459                                 key = BKEY_SELECT;
460                                 break;
461                         case 0x3: /* ^C */
462                                 key = BKEY_QUIT;
463                                 break;
464                         default:
465                                 key = BKEY_NONE;
466                                 break;
467                         }
468                         break;
469                 }
470
471                 if (menu->delay < 0)
472                         break;
473
474                 --menu->delay;
475         }
476
477         if (ansi)
478                 printf(ANSI_CURSOR_POSITION ANSI_CLEAR_LINE, menu->count + 5, 1);
479
480         if (menu->delay == 0)
481                 key = BKEY_SELECT;
482
483         return key;
484 }
485
486 enum bootmenu_key bootmenu_conv_key(int ichar)
487 {
488         enum bootmenu_key key;
489
490         switch (ichar) {
491         case '\n':
492                 /* enter key was pressed */
493                 key = BKEY_SELECT;
494                 break;
495         case CTL_CH('c'):
496         case '\e':
497                 /* ^C was pressed */
498                 key = BKEY_QUIT;
499                 break;
500         case CTL_CH('p'):
501                 key = BKEY_UP;
502                 break;
503         case CTL_CH('n'):
504                 key = BKEY_DOWN;
505                 break;
506         case CTL_CH('s'):
507                 key = BKEY_SAVE;
508                 break;
509         case '+':
510                 key = BKEY_PLUS;
511                 break;
512         case '-':
513                 key = BKEY_MINUS;
514                 break;
515         case ' ':
516                 key = BKEY_SPACE;
517                 break;
518         default:
519                 key = BKEY_NONE;
520                 break;
521         }
522
523         return key;
524 }
525
526 enum bootmenu_key bootmenu_loop(struct bootmenu_data *menu,
527                                 struct cli_ch_state *cch)
528 {
529         enum bootmenu_key key;
530         int c;
531
532         c = cli_ch_process(cch, 0);
533         if (!c) {
534                 while (!c && !tstc()) {
535                         schedule();
536                         mdelay(10);
537                         c = cli_ch_process(cch, -ETIMEDOUT);
538                 }
539                 if (!c) {
540                         c = getchar();
541                         c = cli_ch_process(cch, c);
542                 }
543         }
544
545         key = bootmenu_conv_key(c);
546
547         return key;
548 }