Ignore power button if held on startup

Ignore a power button push until after we have seen it released,
to avoid shutting down immediately if the power button is held
down on startup.

BUG=b:116819414,chromium:670492
BRANCH=grunt
TEST=manual:
1) Press and hold esc+refresh+power.
2) Depthcharge shows INSERT screen and does not power off.
3) Release esc+refresh+power.
4) Press and release power.
5) Depthcharge powers off.
TEST=test_that --fast -b grunt $grunt_ip firmware_ECLidShutdown
TEST=FEATURES=test emerge-grunt --nodeps vboot_reference

Change-Id: I7421a4b1a1b8a7894f0e7d1c7927ffc52d9faac0
Signed-off-by: Edward Hill <ecgh@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1256023
Reviewed-by: Raul E Rangel <rrangel@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c
index 217090a..289e000 100644
--- a/firmware/lib/vboot_ui.c
+++ b/firmware/lib/vboot_ui.c
@@ -25,6 +25,14 @@
 #include "vboot_display.h"
 #include "vboot_kernel.h"
 
+/* Global variables */
+static int power_button_released;
+
+static void vb2_init_ui(void)
+{
+	power_button_released = 0;
+}
+
 static void VbAllowUsbBoot(struct vb2_context *ctx)
 {
 	VB2_DEBUG(".");
@@ -42,6 +50,18 @@
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
 	uint32_t shutdown_request = VbExIsShutdownRequested();
 
+	/*
+	 * Ignore power button push until after we have seen it released.
+	 * This avoids shutting down immediately if the power button is still
+	 * being held on startup.
+	 */
+	if (shutdown_request & VB_SHUTDOWN_REQUEST_POWER_BUTTON) {
+		if (!power_button_released)
+			shutdown_request &= ~VB_SHUTDOWN_REQUEST_POWER_BUTTON;
+	} else {
+		power_button_released = 1;
+	}
+
 	if (key == VB_BUTTON_POWER_SHORT_PRESS)
 		shutdown_request |= VB_SHUTDOWN_REQUEST_POWER_BUTTON;
 
@@ -402,6 +422,7 @@
 
 VbError_t VbBootDeveloper(struct vb2_context *ctx)
 {
+	vb2_init_ui();
 	VbError_t retval = vb2_developer_ui(ctx);
 	VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0);
 	return retval;
@@ -552,6 +573,7 @@
 
 VbError_t VbBootRecovery(struct vb2_context *ctx)
 {
+	vb2_init_ui();
 	VbError_t retval = recovery_ui(ctx);
 	VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0);
 	return retval;
diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c
index f9d061f..3bc3a7f 100644
--- a/tests/vboot_api_kernel2_tests.c
+++ b/tests/vboot_api_kernel2_tests.c
@@ -33,6 +33,7 @@
 static struct vb2_shared_data *sd;
 
 static int shutdown_request_calls_left;
+static int shutdown_request_power_held;
 static int audio_looping_calls_left;
 static uint32_t vbtlk_retval;
 static int vbexlegacy_called;
@@ -74,6 +75,7 @@
 	sd->vbsd = shared;
 
 	shutdown_request_calls_left = -1;
+	shutdown_request_power_held = -1;
 	audio_looping_calls_left = 30;
 	vbtlk_retval = 1000;
 	vbexlegacy_called = 0;
@@ -106,6 +108,15 @@
 	else if (shutdown_request_calls_left > 0)
 		shutdown_request_calls_left--;
 
+	if (shutdown_request_power_held >= 0) {
+		/* Hold power button for 10 calls, then release for 10. */
+		if (shutdown_request_calls_left % 10 == 0)
+			shutdown_request_power_held
+				= !shutdown_request_power_held;
+		if (shutdown_request_power_held)
+			return VB_SHUTDOWN_REQUEST_POWER_BUTTON;
+	}
+
 	return 0;
 }
 
@@ -630,6 +641,26 @@
 		VBERROR_SHUTDOWN_REQUESTED,
 		"Shutdown requested by keyboard");
 
+	/* Ignore power button held on boot */
+	ResetMocks();
+	shutdown_request_calls_left = 100;
+	shutdown_request_power_held = 1;
+	shared->flags = VBSD_BOOT_REC_SWITCH_ON;
+	trust_ec = 1;
+	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+	TEST_EQ(VbBootRecovery(&ctx),
+		VBERROR_SHUTDOWN_REQUESTED,
+		"Ignore power button held on boot");
+	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
+		"  insert screen");
+	/*
+	 * shutdown_request_power_held holds power button for 10 calls, then
+	 * releases for 10, then holds again, so expect shutdown after 20:
+	 * 100 - 20 = 80.
+	 */
+	TEST_EQ(shutdown_request_calls_left, 80,
+		"  ignore held button");
+
 	/* Broken screen */
 	ResetMocks();
 	shutdown_request_calls_left = 100;