detachables: New code path for displaying detachable menus

BUG=b:35585623
BRANCH=None
TEST=None
CQ-DEPEND=CL:457863

Change-Id: Ib2f8d93334cecfd80169842994ea7561baf41378
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/457839
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index a8e79ce..d1c91c3 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -754,6 +754,18 @@
 	VB_SCREEN_OS_BROKEN         = 0x208,
 	/* Display base screen (no icons, no text) */
 	VB_SCREEN_BASE              = 0x209,
+	/* Detachable Menu - Developer Warning */
+	VB_SCREEN_DEVELOPER_WARNING_MENU = 0x20a,
+	/* Detachable Menu - Developer Boot */
+	VB_SCREEN_DEVELOPER_MENU = 0x20b,
+	/* Detachable Menu - Recovery */
+	VB_SCREEN_RECOVERY_MENU = 0x20c,
+	/* Detachable Menu - Confirm Dev Mode */
+	VB_SCREEN_RECOVERY_TO_DEV_MENU = 0x20d,
+	/* Detachable Menu - Confirm Normal Mode */
+	VB_SCREEN_DEVELOPER_TO_NORM_MENU = 0x20e,
+	/* Detachable Menu - Languages */
+	VB_SCREEN_LANGUAGES_MENU = 0x20f,
 };
 
 /**
diff --git a/firmware/lib/include/vboot_display.h b/firmware/lib/include/vboot_display.h
index 3ec4eae..664bc19 100644
--- a/firmware/lib/include/vboot_display.h
+++ b/firmware/lib/include/vboot_display.h
@@ -19,6 +19,8 @@
                                  uint32_t locale);
 VbError_t VbDisplayScreen(struct vb2_context *ctx, VbCommonParams *cparams,
 			  uint32_t screen, int force);
+VbError_t VbDisplayMenu(struct vb2_context *ctx, VbCommonParams *cparams,
+			uint32_t screen, int force, uint32_t selected_index);
 VbError_t VbDisplayDebugInfo(struct vb2_context *ctx, VbCommonParams *cparams);
 VbError_t VbCheckDisplayKey(struct vb2_context *ctx, VbCommonParams *cparams,
 			    uint32_t key);
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 18aaf78..abf2d69 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -22,6 +22,7 @@
 #include "vboot_nvstorage.h"
 
 static uint32_t disp_current_screen = VB_SCREEN_BLANK;
+static uint32_t disp_current_index = 0;
 static uint32_t disp_width = 0, disp_height = 0;
 
 __attribute__((weak))
@@ -372,6 +373,47 @@
 	return rv;
 }
 
+VbError_t VbDisplayMenu(struct vb2_context *ctx,
+			VbCommonParams *cparams, uint32_t screen, int force,
+			uint32_t selected_index)
+{
+	uint32_t locale;
+	VbError_t rv;
+	uint32_t redraw_base_screen = 0;
+
+	/*
+	 * If requested screen/selected_index is the same as the current one,
+	 * we're done.
+	 */
+	if (disp_current_screen == screen &&
+	    disp_current_index == selected_index &&
+	    !force)
+		return VBERROR_SUCCESS;
+
+	/*
+	 * If current screen is not the same, make sure we redraw the base
+	 * screen as well to avoid having artifacts from the menu.
+	 */
+	if (disp_current_screen != screen)
+		redraw_base_screen = 1;
+
+	/* Read the locale last saved */
+	locale = vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX);
+
+	rv = VbExDisplayMenu(screen, locale, selected_index, redraw_base_screen);
+
+	if (rv == VBERROR_SUCCESS) {
+		/*
+		 * Keep track of the currently displayed screen and
+		 * selected_index
+		 */
+		disp_current_screen = screen;
+		disp_current_index = selected_index;
+	}
+
+	return rv;
+}
+
 static void Uint8ToString(char *buf, uint8_t val)
 {
 	const char *trans = "0123456789abcdef";
diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c
index b4b5b25..453ef57 100644
--- a/firmware/lib/vboot_ui_menu.c
+++ b/firmware/lib/vboot_ui_menu.c
@@ -354,6 +354,30 @@
 	return VBERROR_SUCCESS;
 }
 
+/*
+ * Static array for mapping current_menu to matching screen item in depthcharge.
+ * Note that order here is important and needs to match that of items in
+ * VB_MENU.
+ */
+static const uint32_t VB_MENU_TO_SCREEN_MAP[] = {
+	VB_SCREEN_DEVELOPER_WARNING_MENU,
+	VB_SCREEN_DEVELOPER_MENU,
+	VB_SCREEN_DEVELOPER_TO_NORM_MENU,
+	VB_SCREEN_RECOVERY_MENU,
+	VB_SCREEN_RECOVERY_TO_DEV_MENU,
+	VB_SCREEN_LANGUAGES_MENU,
+};
+
+VbError_t vb2_draw_current_screen(struct vb2_context *ctx,
+				  VbCommonParams *cparams) {
+	uint32_t screen;
+	if (current_menu < VB_MENU_COUNT)
+		screen = VB_MENU_TO_SCREEN_MAP[current_menu];
+	else
+		return VBERROR_UNKNOWN;
+	return VbDisplayMenu(ctx, cparams, screen, 0, current_menu_idx);
+}
+
 /**
  * Set current_menu to new_current_menu
  *
@@ -720,6 +744,7 @@
 			/* Do not wrap selection index */
 			if (current_menu_idx > 0)
 				current_menu_idx--;
+			vb2_draw_current_screen(ctx, cparams);
 			vb2_print_current_menu();
 			break;
 		case VB_BUTTON_VOL_DOWN:
@@ -729,6 +754,7 @@
 			/* Do no wrap selection index */
 			if (current_menu_idx < menu_size-1)
 				current_menu_idx++;
+			vb2_draw_current_screen(ctx, cparams);
 			vb2_print_current_menu();
 			break;
 		case VB_BUTTON_POWER:
@@ -982,6 +1008,7 @@
 				vb2_get_current_menu_size(current_menu, NULL, &menu_size);
 				if (current_menu_idx > 0)
 					current_menu_idx--;
+				vb2_draw_current_screen(ctx, cparams);
 				vb2_print_current_menu();
 				break;
 			case VB_BUTTON_VOL_DOWN:
@@ -989,6 +1016,7 @@
 				vb2_get_current_menu_size(current_menu, NULL, &menu_size);
 				if (current_menu_idx < menu_size-1)
 					current_menu_idx++;
+				vb2_draw_current_screen(ctx, cparams);
 				vb2_print_current_menu();
 				break;
 			case VB_BUTTON_POWER: