platform: msm_shared: add API to show menu on screen in lk
This change add API to show menu on screen and add keys detection
to switch diffrent menu.
Change-Id: I2cd1416302a65e855a68f45d08ad9ec3f7532b2e
diff --git a/platform/msm_shared/display_menu.c b/platform/msm_shared/display_menu.c
new file mode 100644
index 0000000..2a792b2
--- /dev/null
+++ b/platform/msm_shared/display_menu.c
@@ -0,0 +1,339 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <debug.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <openssl/evp.h>
+#include <dev/fbcon.h>
+#include <kernel/thread.h>
+#include <display_menu.h>
+#include <menu_keys_detect.h>
+#include <boot_verifier.h>
+#include <string.h>
+#include <platform.h>
+
+#define UNLOCK_OPTION_NUM 2
+#define BOOT_VERIFY_OPTION_NUM 5
+
+static char *unlock_menu_common_msg = "If you unlock the bootloader, "\
+ "you will be able to install "\
+ "custom operating system on this phone.\n\n"\
+ "A custom OS is not subject to the same testing "\
+ "as the original OS, "\
+ "and can cause your phone and installed "\
+ "applications to stop working properly.\n\n"\
+ "To prevent unauthorized access to your personal data, "\
+ "unlocking the bootloader will also delete all personal "\
+ "data from your phone(a \"fatory data reset\").\n\n"\
+ "Press the Volume Up/Down buttons to select Yes "\
+ "or No. Then press the Power button to continue.\n";
+
+static char *yellow_warning_msg = "Your device has loaded a diffrent operating "\
+ "system\n\nTo learn more, visit:\n";
+
+static char *orange_warning_msg = "Your device has been unlocker and cann't "\
+ "be trusted\n\nTo learn more, visit:\n";
+
+static char *red_warning_msg = "Your device has failed verification and may "\
+ "not work properly\n\nTo learn more, visit:\n";
+
+static bool is_thread_start = false;
+struct select_msg_info msg_info;
+
+static char *option_menu[] = {
+ [POWEROFF] = "Power off\n",
+ [RESTART] = "Restart\n",
+ [RECOVER] = "Recovery\n",
+ [FASTBOOT] = "Fastboot\n",
+ [BACK] = "Back to previous page\n"};
+
+static int big_factor = 2;
+static int common_factor = 1;
+
+void wait_for_users_action()
+{
+ struct select_msg_info *select_msg;
+ select_msg = &msg_info;
+
+ while(1) {
+ if (select_msg->msg_timeout == true &&
+ select_msg->msg_volume_key_pressed == false)
+ break;
+ if (select_msg->msg_power_key_pressed == true)
+ break;
+
+ thread_sleep(10);
+ }
+ fbcon_clear();
+ display_image_on_screen();
+}
+
+static void set_message_factor()
+{
+ uint32_t tmp_factor = 0;
+ uint32_t max_x_count = 40;
+ uint32_t max_x = fbcon_get_max_x();
+
+ max_x = fbcon_get_max_x();
+ tmp_factor = max_x/max_x_count;
+
+ if(tmp_factor <= 1) {
+ big_factor = 2;
+ common_factor = 1;
+ } else {
+ big_factor = tmp_factor*2;
+ common_factor = tmp_factor;
+ }
+}
+
+static void display_fbcon_menu_message(char *str, unsigned type,
+ unsigned scale_factor)
+{
+ while(*str != 0) {
+ fbcon_putc_factor(*str++, type, scale_factor);
+ }
+}
+
+static char *str_align_right(char *str, int factor)
+{
+ uint32_t max_x = 0;
+ int diff = 0;
+ int i = 0;
+ char *str_target = NULL;
+
+ max_x = fbcon_get_max_x();
+ if (!str_target && max_x) {
+ str_target = malloc(max_x);
+ }
+
+ if (str_target) {
+ memset(str_target, 0, max_x);
+ if ( max_x/factor > strlen(str)) {
+ if (factor == 1)
+ diff = max_x/factor - strlen(str) - 1;
+ else
+ diff = max_x/factor - strlen(str);
+ for (i = 0; i < diff; i++) {
+ strcat(str_target, " ");
+ }
+ strcat(str_target, str);
+ return str_target;
+ } else {
+ free(str_target);
+ return str;
+ }
+ }
+ return str;
+}
+
+void display_unlock_menu(struct select_msg_info *unlock_msg_info)
+{
+ fbcon_clear();
+ memset(unlock_msg_info, 0, sizeof(struct select_msg_info));
+ display_fbcon_menu_message("Unlock bootloader?\n",
+ FBCON_UNLOCK_TITLE_MSG, big_factor);
+ fbcon_draw_line();
+
+ display_fbcon_menu_message(unlock_menu_common_msg,
+ FBCON_COMMON_MSG, common_factor);
+ fbcon_draw_line();
+ unlock_msg_info->option_start[0] = fbcon_get_current_line();
+ display_fbcon_menu_message("Yes\n",
+ FBCON_COMMON_MSG, big_factor);
+ unlock_msg_info->option_bg[0] = fbcon_get_current_bg();
+ display_fbcon_menu_message("Unlock bootloader(may void warranty)\n",
+ FBCON_COMMON_MSG, common_factor);
+ unlock_msg_info->option_end[0] = fbcon_get_current_line();
+ fbcon_draw_line();
+ unlock_msg_info->option_start[1] = fbcon_get_current_line();
+ display_fbcon_menu_message("No\n",
+ FBCON_COMMON_MSG, big_factor);
+ unlock_msg_info->option_bg[1] = fbcon_get_current_bg();
+ display_fbcon_menu_message("Do not unlock bootloader and restart phone\n",
+ FBCON_COMMON_MSG, common_factor);
+ unlock_msg_info->option_end[1] = fbcon_get_current_line();
+ fbcon_draw_line();
+
+ unlock_msg_info->msg_type = DISPLAY_MENU_UNLOCK;
+ unlock_msg_info->option_num = UNLOCK_OPTION_NUM;
+}
+
+void display_boot_verified_menu(struct select_msg_info *msg_info, int type)
+{
+ int msg_type = FBCON_COMMON_MSG;
+ char *warning_msg = NULL;
+ unsigned char* fp_buf = NULL;
+ char fp_str_temp[EVP_MAX_MD_SIZE] = {'\0'};
+ char fp_str[EVP_MAX_MD_SIZE*2] = {'\0'};
+ char str_temp[8];
+
+ char str1[]= "Start >";
+ char str2[] = "Continue boot";
+ char *str_target = NULL;
+ uint32 fp_size = 0;
+ unsigned int i = 0;
+
+ fbcon_clear();
+ memset(msg_info, 0, sizeof(struct select_msg_info));
+
+ switch (type) {
+ case DISPLAY_MENU_RED:
+ msg_type = FBCON_RED_MSG;
+ warning_msg = red_warning_msg;
+ break;
+ case DISPLAY_MENU_YELLOW:
+ msg_type = FBCON_YELLOW_MSG;
+ warning_msg = yellow_warning_msg;
+ break;
+ case DISPLAY_MENU_ORANGE:
+ msg_type = FBCON_ORANGE_MSG;
+ warning_msg = orange_warning_msg;
+ break;
+ }
+
+ /* Align Right */
+ str_target = str_align_right(str1, big_factor);
+ display_fbcon_menu_message(str_target, FBCON_TITLE_MSG, big_factor);
+
+ str_target = str_align_right(str2, common_factor);
+ display_fbcon_menu_message(str_target, FBCON_TITLE_MSG, common_factor);
+
+ display_fbcon_menu_message("\n< More options\n",
+ FBCON_COMMON_MSG, common_factor);
+ display_fbcon_menu_message("press VOLUME keys\n\n",
+ FBCON_SUBTITLE_MSG, common_factor);
+
+ display_fbcon_menu_message(warning_msg, FBCON_COMMON_MSG, common_factor);
+
+ display_fbcon_menu_message("g.co/placeholder\n",
+ msg_type, common_factor);
+
+#if VERIFIED_BOOT
+ if (type == DISPLAY_MENU_YELLOW) {
+ fp_buf = get_boot_fingerprint(&fp_size);
+ if (fp_buf != NULL) {
+ strncpy(fp_str_temp, (char const *)fp_buf, fp_size);
+ for (i = 0; i < fp_size; i++) {
+ if(i == fp_size - 1)
+ sprintf(str_temp, "%02x", fp_str_temp[i]);
+ else
+ sprintf(str_temp, "%02x-", fp_str_temp[i]);
+
+ strcat(fp_str, str_temp);
+ }
+ }
+ display_fbcon_menu_message("ID:", FBCON_COMMON_MSG, common_factor);
+ display_fbcon_menu_message(fp_str, FBCON_COMMON_MSG, common_factor);
+ }
+#endif
+
+ display_fbcon_menu_message("\n\nIf no key pressed:\n"\
+ "Your device will boot in 5 seconds\n\n", FBCON_COMMON_MSG, common_factor);
+
+ msg_info->msg_type = type;
+ if(str_target) {
+ free(str_target);
+ }
+}
+
+void display_boot_verified_option(struct select_msg_info *msg_info)
+{
+ int i = 0;
+ fbcon_clear();
+ memset(msg_info, 0, sizeof(struct select_msg_info));
+
+ display_fbcon_menu_message("Options menu:\n\n",
+ FBCON_COMMON_MSG, big_factor);
+ display_fbcon_menu_message("Press volume key to select, and "\
+ "press power key to select\n\n", FBCON_COMMON_MSG, common_factor);
+
+ for (i = 0; i < BOOT_VERIFY_OPTION_NUM; i++) {
+ fbcon_draw_line();
+ msg_info->option_start[i] = fbcon_get_current_line();
+ display_fbcon_menu_message(option_menu[i],
+ FBCON_COMMON_MSG, common_factor);
+ msg_info->option_bg[i]= fbcon_get_current_bg();
+ msg_info->option_end[i]= fbcon_get_current_line();
+ }
+
+ fbcon_draw_line();
+ msg_info->msg_type = DISPLAY_MENU_MORE_OPTION;
+ msg_info->option_num = BOOT_VERIFY_OPTION_NUM;
+}
+
+static void display_menu_thread_start(struct select_msg_info *msg_info)
+{
+ thread_t *thr;
+
+ if (!is_thread_start) {
+ thr = thread_create("selectkeydetect", &select_msg_keys_detect,
+ (void*)msg_info, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+ if (!thr) {
+ dprintf(CRITICAL, "ERROR: creat device status detect thread failed!!\n");
+ return;
+ }
+ thread_resume(thr);
+ }
+
+ is_thread_start = true;
+}
+
+void display_menu_thread(int type)
+{
+ struct select_msg_info *display_menu_msg_info;
+ display_menu_msg_info = &msg_info;
+ int menu_type = 0;
+
+ set_message_factor();
+ if (type == DISPLAY_THREAD_UNLOCK) {
+ display_unlock_menu(display_menu_msg_info);
+
+ dprintf(INFO, "creating oem unlock keys detect thread\n");
+ display_menu_thread_start(display_menu_msg_info);
+ } else {
+ #if VERIFIED_BOOT
+ if (boot_verify_get_state() == ORANGE) {
+ menu_type = DISPLAY_MENU_ORANGE;
+ } else if (boot_verify_get_state() == YELLOW) {
+ menu_type = DISPLAY_MENU_YELLOW;
+ } else if (boot_verify_get_state() == RED) {
+ menu_type = DISPLAY_MENU_RED;
+ }
+ display_boot_verified_menu(display_menu_msg_info, menu_type);
+
+ dprintf(INFO, "creating device state keys detect thread\n");
+ display_menu_thread_start(display_menu_msg_info);
+
+ #else
+ dprintf(CRITICAL, "VERIFIED_BOOT is not enable!!\n");
+ return;
+ #endif
+ }
+}
+
diff --git a/platform/msm_shared/include/display_menu.h b/platform/msm_shared/include/display_menu.h
new file mode 100644
index 0000000..2350fe9
--- /dev/null
+++ b/platform/msm_shared/include/display_menu.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __PLATFORM_MSM_SHARED_DISPLAY_MENU_H
+#define __PLATFORM_MSM_SHARED_DISPLAY_MENU_H
+
+#include <openssl/evp.h>
+
+#define SELECT_OPTION_MAX 5
+
+enum display_menu_type {
+ DISPLAY_MENU_YELLOW = 0,
+ DISPLAY_MENU_ORANGE,
+ DISPLAY_MENU_RED,
+ DISPLAY_MENU_MORE_OPTION,
+ DISPLAY_MENU_UNLOCK,
+};
+
+struct select_msg_info {
+ uint32_t option_start[SELECT_OPTION_MAX];
+ uint32_t option_end[SELECT_OPTION_MAX];
+ uint32_t option_bg[SELECT_OPTION_MAX];
+ uint32_t option_num;
+ uint32_t msg_type;
+ bool msg_timeout;
+ bool msg_power_key_pressed;
+ bool msg_volume_key_pressed;
+};
+
+enum display_thread_type {
+ DISPLAY_THREAD_UNLOCK = 0,
+ DISPLAY_THREAD_BOOT_STATE,
+};
+
+void wait_for_users_action(void);
+void display_unlock_menu(struct select_msg_info *msg_info);
+void display_boot_verified_menu(struct select_msg_info *msg_info, int type);
+void display_boot_verified_option(struct select_msg_info *msg_info);
+void display_menu_thread(int type);
+#endif /* __PLATFORM_MSM_SHARED_DISPLAY_MENU_H */
diff --git a/platform/msm_shared/include/menu_keys_detect.h b/platform/msm_shared/include/menu_keys_detect.h
new file mode 100644
index 0000000..31a5661
--- /dev/null
+++ b/platform/msm_shared/include/menu_keys_detect.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __PLATFORM_MSM_SHARED_KEYS_DETECT_H
+#define __PLATFORM_MSM_SHARED_KEYS_DETECT_H
+
+enum device_select_option {
+ POWEROFF = 0,
+ RESTART,
+ RECOVER,
+ FASTBOOT,
+ BACK,
+
+ CONTINUE,
+};
+
+enum keys_option {
+ VOLUME_UP = 0,
+ VOLUME_DOWN,
+ POWER_KEY,
+};
+
+enum pages_type {
+ UNLOCK_PAGE = 0,
+ BOOT_VERIFY_PAGE1,
+ BOOT_VERIFY_PAGE2,
+};
+
+int select_msg_keys_detect(void *param);
+void keys_detect_init();
+#endif /* __PLATFORM_MSM_SHARED_KEYS_DETECT_H */
diff --git a/platform/msm_shared/menu_keys_detect.c b/platform/msm_shared/menu_keys_detect.c
new file mode 100644
index 0000000..472814d
--- /dev/null
+++ b/platform/msm_shared/menu_keys_detect.c
@@ -0,0 +1,325 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <debug.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <pm8x41.h>
+#include <pm8x41_hw.h>
+#include <kernel/timer.h>
+#include <platform/timer.h>
+#include <kernel/thread.h>
+#include <dev/keys.h>
+#include <dev/fbcon.h>
+#include <menu_keys_detect.h>
+#include <display_menu.h>
+#include <platform/gpio.h>
+#include <platform/iomap.h>
+#include <platform.h>
+#include <../../../app/aboot/recovery.h>
+
+#define KEY_DETECT_FREQUENCY 50
+#define KEY_PRESS_TIMEOUT 5000
+
+#define RECOVERY_MODE 0x77665502
+#define FASTBOOT_MODE 0x77665500
+
+static uint32_t wait_time = 0;
+static int old_device_type = -1;
+
+extern int target_volume_up();
+extern uint32_t target_volume_down();
+extern void reboot_device(unsigned reboot_reason);
+extern void shutdown_device();
+
+typedef uint32_t (*keys_detect_func)(void);
+typedef uint32_t (*keys_action_func)(struct select_msg_info* msg_info,
+ uint32_t option_index);
+
+struct keys_stru {
+ int type;
+ keys_detect_func keys_pressed_func;
+};
+
+struct keys_stru keys[] = {
+ {VOLUME_UP, (uint32_t (*)(void))target_volume_up},
+ {VOLUME_DOWN, target_volume_down},
+ {POWER_KEY, pm8x41_get_pwrkey_is_pressed},
+};
+
+struct pages_action {
+ keys_action_func up_action_func;
+ keys_action_func down_action_func;
+ keys_action_func enter_action_func;
+};
+
+static int is_key_pressed(int keys_type)
+{
+ int count = 0;
+
+ if (keys[keys_type].keys_pressed_func()) {
+ /*if key is pressed, wait for 1 second to see if it is released*/
+ while(count++ < 10 && keys[keys_type].keys_pressed_func())
+ thread_sleep(100);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void update_device_status(unsigned reason)
+{
+ if (reason == RECOVER) {
+ /* wipe data */
+ struct recovery_message msg;
+
+ snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
+ write_misc(0, &msg, sizeof(msg));
+
+ reboot_device(RECOVERY_MODE);
+ } else if (reason == RESTART) {
+ reboot_device(0);
+ } else if (reason == POWEROFF) {
+ shutdown_device();
+ } else if (reason == FASTBOOT) {
+ reboot_device(FASTBOOT_MODE);
+ } else if (reason == CONTINUE) {
+ fbcon_clear();
+ display_image_on_screen();
+ }
+}
+
+static void update_volume_up_bg(struct select_msg_info* msg_info, uint32_t option_index)
+{
+ if (option_index == msg_info->option_num - 1) {
+ fbcon_draw_msg_background(msg_info->option_start[0],
+ msg_info->option_end[0],
+ msg_info->option_bg[0], 0);
+
+ fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
+ msg_info->option_end[msg_info->option_num - 1],
+ msg_info->option_bg[msg_info->option_num - 1], 1);
+ } else {
+ fbcon_draw_msg_background(msg_info->option_start[option_index],
+ msg_info->option_end[option_index],
+ msg_info->option_bg[option_index], 1);
+
+ fbcon_draw_msg_background(msg_info->option_start[option_index + 1],
+ msg_info->option_end[option_index + 1],
+ msg_info->option_bg[option_index + 1], 0);
+ }
+}
+
+static void update_volume_down_bg(struct select_msg_info* msg_info, uint32_t option_index)
+{
+ if (option_index == 0) {
+ fbcon_draw_msg_background(msg_info->option_start[0],
+ msg_info->option_end[0],
+ msg_info->option_bg[0], 1);
+
+ fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
+ msg_info->option_end[msg_info->option_num - 1],
+ msg_info->option_bg[msg_info->option_num - 1], 0);
+ } else {
+ fbcon_draw_msg_background(msg_info->option_start[option_index],
+ msg_info->option_end[option_index],
+ msg_info->option_bg[option_index], 1);
+
+ fbcon_draw_msg_background(msg_info->option_start[option_index - 1],
+ msg_info->option_end[option_index - 1],
+ msg_info->option_bg[option_index - 1], 0);
+ }
+}
+
+/* update select option's background when volume up key is pressed */
+static uint32_t menu_volume_up_func (struct select_msg_info* msg_info,
+ uint32_t option_index)
+{
+ if (option_index == msg_info->option_num ||
+ option_index == 0) {
+ option_index = msg_info->option_num - 1;
+ } else if (option_index > 0) {
+ option_index--;
+ }
+
+ update_volume_up_bg(msg_info, option_index);
+
+ return option_index;
+}
+
+/* update select option's background when volume down key is pressed */
+static uint32_t menu_volume_down_func (struct select_msg_info* msg_info,
+ uint32_t option_index)
+{
+ option_index++;
+ if (option_index >= msg_info->option_num)
+ option_index = 0;
+
+ update_volume_down_bg(msg_info, option_index);
+
+ return option_index;
+}
+
+/* enter to boot verify page2 if volume key is pressed */
+static uint32_t boot_page1_volume_keys_func (struct select_msg_info* msg_info,
+ uint32_t option_index)
+{
+ keys_detect_init();
+ old_device_type = msg_info->msg_type;
+ display_boot_verified_option(msg_info);
+ msg_info->msg_volume_key_pressed = true;
+ option_index = msg_info->option_num;
+
+ return option_index;
+}
+
+/* update device's status via select option */
+static uint32_t unlock_power_key_func (struct select_msg_info* msg_info,
+ uint32_t option_index)
+{
+ int device_state = -1;
+ if (option_index == 0)
+ device_state = RECOVER;
+ else if (option_index == 1)
+ device_state = RESTART;
+
+ update_device_status(device_state);
+ return 0;
+}
+
+/* continue booting when power key is pressed at boot-verify page1 */
+static uint32_t boot_page1_power_key_func (struct select_msg_info* msg_info,
+ uint32_t option_index){
+ update_device_status(CONTINUE);
+ return option_index;
+}
+
+/* update device's status via select option */
+static uint32_t boot_page2_power_key_func (struct select_msg_info* msg_info,
+ uint32_t option_index)
+{
+ if (option_index == BACK) {
+ wait_time = 0;
+ msg_info->msg_timeout = false;
+ option_index = msg_info->option_num;
+ display_boot_verified_menu(msg_info,
+ old_device_type);
+ } else {
+ msg_info->msg_power_key_pressed = true;
+ update_device_status(option_index);
+ }
+ return option_index;
+}
+
+/* initialize different page's function
+ * UNLOCK_PAGE/BOOT_VERIFY_PAGE2:
+ * up_action_func: update select option's background when volume up
+ * is pressed
+ * down_action_func: update select option's background when volume up
+ * is pressed
+ * enter_action_func: update device's status via select option
+ * BOOT_VERIFY_PAGE1:
+ * up_action_func/down_action_func: enter BOOT_VERIFY_PAGE2 when volume
+ * key is pressed
+ * enter_action_func: continue booting
+ */
+static struct pages_action menu_pages_action[] = {
+ [UNLOCK_PAGE] = {
+ menu_volume_up_func,
+ menu_volume_down_func,
+ unlock_power_key_func,
+ },
+ [BOOT_VERIFY_PAGE1] = {
+ boot_page1_volume_keys_func,
+ boot_page1_volume_keys_func,
+ boot_page1_power_key_func,
+ },
+ [BOOT_VERIFY_PAGE2] = {
+ menu_volume_up_func,
+ menu_volume_down_func,
+ boot_page2_power_key_func,
+ },
+};
+
+void keys_detect_init()
+{
+ wait_time = 0;
+}
+
+int select_msg_keys_detect(void *param) {
+ struct select_msg_info *msg_info = (struct select_msg_info*)param;
+ uint32_t current_page_index;
+ uint32_t option_index = msg_info->option_num;
+
+ keys_detect_init();
+ while(1) {
+ /* get page's index via different message type */
+ switch(msg_info->msg_type) {
+ case DISPLAY_MENU_UNLOCK:
+ current_page_index = UNLOCK_PAGE;
+ break;
+ case DISPLAY_MENU_MORE_OPTION:
+ current_page_index = BOOT_VERIFY_PAGE2;
+ break;
+ default:
+ current_page_index = BOOT_VERIFY_PAGE1;
+ break;
+ }
+
+ /* device will continue booting when user has no action
+ * on BOOT_VERIFY_PAGE1
+ */
+ if (wait_time > KEY_PRESS_TIMEOUT)
+ msg_info->msg_timeout = true;
+
+ /* 1: update select option's index, default it is the total option number
+ * volume up: index decrease, the option will scroll up from
+ * the bottom to top if the key is pressed firstly.
+ * eg: 5->4->3->2->1->0
+ * volume down: index increase, the option will scroll down from
+ * the bottom to top if the key is pressed firstly.
+ * eg: 5->0
+ * 2: update device's status via select option's index
+ */
+ if (is_key_pressed(VOLUME_UP)) {
+ option_index =
+ menu_pages_action[current_page_index].up_action_func(msg_info, option_index);
+ } else if (is_key_pressed(VOLUME_DOWN)) {
+ option_index =
+ menu_pages_action[current_page_index].down_action_func(msg_info, option_index);
+ } else if (is_key_pressed(POWER_KEY)) {
+ option_index =
+ menu_pages_action[current_page_index].enter_action_func(msg_info, option_index);
+ }
+
+ wait_time += KEY_DETECT_FREQUENCY;
+ thread_sleep(KEY_DETECT_FREQUENCY);
+ }
+
+ return 0;
+}
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index b20e32f..cd597c1 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -54,6 +54,12 @@
$(LOCAL_DIR)/boot_verifier.o
endif
+ifeq ($(ENABLE_FBCON_DISPLAY_MSG),1)
+OBJS += \
+ $(LOCAL_DIR)/menu_keys_detect.o \
+ $(LOCAL_DIR)/display_menu.o
+endif
+
ifeq ($(ENABLE_GLINK_SUPPORT),1)
OBJS += \
$(LOCAL_DIR)/rpm-ipc.o \