blob: efea07e8ddcfb5fe921bd5276dc4bff31a3108bc [file] [log] [blame]
lijuang86f46b42015-12-23 13:39:22 +08001/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
lijuang7d235f42015-07-16 20:19:45 +08002*
3* Redistribution and use in source and binary forms, with or without
4* modification, are permitted provided that the following conditions are
5* met:
6* * Redistributions of source code must retain the above copyright
7* notice, this list of conditions and the following disclaimer.
8* * Redistributions in binary form must reproduce the above
9* copyright notice, this list of conditions and the following
10* disclaimer in the documentation and/or other materials provided
11* with the distribution.
12* * Neither the name of The Linux Foundation nor the names of its
13* contributors may be used to endorse or promote products derived
14* from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <debug.h>
30#include <reg.h>
31#include <stdlib.h>
32#include <pm8x41.h>
33#include <pm8x41_hw.h>
34#include <kernel/timer.h>
35#include <platform/timer.h>
36#include <kernel/thread.h>
37#include <dev/keys.h>
38#include <dev/fbcon.h>
39#include <menu_keys_detect.h>
40#include <display_menu.h>
41#include <platform/gpio.h>
42#include <platform/iomap.h>
43#include <platform.h>
lijuangf5045b52015-09-07 17:19:20 +080044#include <reboot.h>
lijuang9a7d3b92015-11-30 14:41:24 +080045#include <sys/types.h>
lijuang7d235f42015-07-16 20:19:45 +080046#include <../../../app/aboot/recovery.h>
lijuang4ece1e72015-08-14 21:02:36 +080047#include <../../../app/aboot/devinfo.h>
lijuang7d235f42015-07-16 20:19:45 +080048
49#define KEY_DETECT_FREQUENCY 50
lijuang7d235f42015-07-16 20:19:45 +080050
lijuang9a7d3b92015-11-30 14:41:24 +080051static time_t before_time;
lijuang7d235f42015-07-16 20:19:45 +080052
53extern int target_volume_up();
54extern uint32_t target_volume_down();
55extern void reboot_device(unsigned reboot_reason);
56extern void shutdown_device();
57
58typedef uint32_t (*keys_detect_func)(void);
lijuang9a7d3b92015-11-30 14:41:24 +080059typedef void (*keys_action_func)(struct select_msg_info* msg_info);
lijuang7d235f42015-07-16 20:19:45 +080060
61struct keys_stru {
62 int type;
63 keys_detect_func keys_pressed_func;
64};
65
66struct keys_stru keys[] = {
67 {VOLUME_UP, (uint32_t (*)(void))target_volume_up},
68 {VOLUME_DOWN, target_volume_down},
69 {POWER_KEY, pm8x41_get_pwrkey_is_pressed},
70};
71
72struct pages_action {
73 keys_action_func up_action_func;
74 keys_action_func down_action_func;
75 keys_action_func enter_action_func;
76};
77
lijuang9a7d3b92015-11-30 14:41:24 +080078static uint32_t verify_index_action[] = {
79 [0] = POWEROFF,
80 [1] = RESTART,
81 [2] = RECOVER,
82 [3] = FASTBOOT,
83 [4] = BACK,
84};
85
86static uint32_t fastboot_index_action[] = {
87 [0] = RESTART,
88 [1] = FASTBOOT,
89 [2] = RECOVER,
90 [3] = POWEROFF,
lijuang42aefaa2016-04-14 15:55:17 +080091 [4] = FFBM,
lijuang9a7d3b92015-11-30 14:41:24 +080092};
93
94static uint32_t unlock_index_action[] = {
95 [0] = RECOVER,
96 [1] = RESTART,
97};
98
lijuang7d235f42015-07-16 20:19:45 +080099static int is_key_pressed(int keys_type)
100{
101 int count = 0;
102
103 if (keys[keys_type].keys_pressed_func()) {
104 /*if key is pressed, wait for 1 second to see if it is released*/
105 while(count++ < 10 && keys[keys_type].keys_pressed_func())
106 thread_sleep(100);
107 return 1;
108 }
109
110 return 0;
111}
112
lijuang9a7d3b92015-11-30 14:41:24 +0800113static void update_device_status(struct select_msg_info* msg_info, int reason)
lijuang7d235f42015-07-16 20:19:45 +0800114{
lijuang42aefaa2016-04-14 15:55:17 +0800115 char ffbm_page_buffer[FFBM_MODE_BUF_SIZE];
lijuang9a7d3b92015-11-30 14:41:24 +0800116 fbcon_clear();
117 switch (reason) {
118 case RECOVER:
119 if (msg_info->info.msg_type == DISPLAY_MENU_UNLOCK) {
120 set_device_unlock_value(UNLOCK, TRUE);
121 } else if (msg_info->info.msg_type == DISPLAY_MENU_UNLOCK_CRITICAL) {
122 set_device_unlock_value(UNLOCK_CRITICAL, TRUE);
123 }
lijuang7d235f42015-07-16 20:19:45 +0800124
lijuang9a7d3b92015-11-30 14:41:24 +0800125 if (msg_info->info.msg_type == DISPLAY_MENU_UNLOCK ||
126 msg_info->info.msg_type == DISPLAY_MENU_UNLOCK_CRITICAL) {
127 /* wipe data */
128 struct recovery_message msg;
lijuangf5045b52015-09-07 17:19:20 +0800129
lijuang9a7d3b92015-11-30 14:41:24 +0800130 snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
131 write_misc(0, &msg, sizeof(msg));
132 }
133 reboot_device(RECOVERY_MODE);
134 break;
135 case RESTART:
136 reboot_device(0);
137 break;
138 case POWEROFF:
139 shutdown_device();
140 break;
141 case FASTBOOT:
142 reboot_device(FASTBOOT_MODE);
143 break;
144 case CONTINUE:
145 display_image_on_screen();
lijuang7d235f42015-07-16 20:19:45 +0800146
lijuang9a7d3b92015-11-30 14:41:24 +0800147 /* Continue boot, no need to detect the keys'status */
lijuangde34d502016-02-26 16:04:50 +0800148 msg_info->info.is_exit = true;
lijuang9a7d3b92015-11-30 14:41:24 +0800149 break;
150 case BACK:
151 display_bootverify_menu_renew(msg_info, msg_info->last_msg_type);
152 before_time = current_time();
153
154 break;
lijuang42aefaa2016-04-14 15:55:17 +0800155 case FFBM:
156 snprintf(ffbm_page_buffer, sizeof(ffbm_page_buffer), "ffbm-00");
157 write_misc(0, ffbm_page_buffer, sizeof(ffbm_page_buffer));
158
159 reboot_device(0);
160 break;
lijuang7d235f42015-07-16 20:19:45 +0800161 }
162}
163
lijuang9a7d3b92015-11-30 14:41:24 +0800164/* msg_lock need to be holded when call this function. */
165static void update_volume_up_bg(struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800166{
lijuang9a7d3b92015-11-30 14:41:24 +0800167 if (msg_info->info.option_index == msg_info->info.option_num - 1) {
168 fbcon_draw_msg_background(msg_info->info.option_start[0],
169 msg_info->info.option_end[0],
170 msg_info->info.option_bg[0], 0);
lijuang7d235f42015-07-16 20:19:45 +0800171
lijuang9a7d3b92015-11-30 14:41:24 +0800172 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_num - 1],
173 msg_info->info.option_end[msg_info->info.option_num - 1],
174 msg_info->info.option_bg[msg_info->info.option_num - 1], 1);
lijuang7d235f42015-07-16 20:19:45 +0800175 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800176 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index],
177 msg_info->info.option_end[msg_info->info.option_index],
178 msg_info->info.option_bg[msg_info->info.option_index], 1);
lijuang7d235f42015-07-16 20:19:45 +0800179
lijuang9a7d3b92015-11-30 14:41:24 +0800180 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index + 1],
181 msg_info->info.option_end[msg_info->info.option_index + 1],
182 msg_info->info.option_bg[msg_info->info.option_index + 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800183 }
184}
185
lijuang9a7d3b92015-11-30 14:41:24 +0800186/* msg_lock need to be holded when call this function. */
187static void update_volume_down_bg(struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800188{
lijuang9a7d3b92015-11-30 14:41:24 +0800189 if (msg_info->info.option_index == 0) {
190 fbcon_draw_msg_background(msg_info->info.option_start[0],
191 msg_info->info.option_end[0],
192 msg_info->info.option_bg[0], 1);
lijuang7d235f42015-07-16 20:19:45 +0800193
lijuang9a7d3b92015-11-30 14:41:24 +0800194 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_num - 1],
195 msg_info->info.option_end[msg_info->info.option_num - 1],
196 msg_info->info.option_bg[msg_info->info.option_num - 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800197 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800198 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index],
199 msg_info->info.option_end[msg_info->info.option_index],
200 msg_info->info.option_bg[msg_info->info.option_index], 1);
lijuang7d235f42015-07-16 20:19:45 +0800201
lijuang9a7d3b92015-11-30 14:41:24 +0800202 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index - 1],
203 msg_info->info.option_end[msg_info->info.option_index - 1],
204 msg_info->info.option_bg[msg_info->info.option_index - 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800205 }
206}
207
208/* update select option's background when volume up key is pressed */
lijuang9a7d3b92015-11-30 14:41:24 +0800209static void menu_volume_up_func (struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800210{
lijuang9a7d3b92015-11-30 14:41:24 +0800211 if (msg_info->info.option_index == 0)
212 msg_info->info.option_index = msg_info->info.option_num - 1;
213 else
214 msg_info->info.option_index--;
215
216 if (msg_info->info.msg_type == DISPLAY_MENU_FASTBOOT) {
217 display_fastboot_menu_renew(msg_info);
218 } else {
219 update_volume_up_bg(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800220 }
lijuang7d235f42015-07-16 20:19:45 +0800221}
222
223/* update select option's background when volume down key is pressed */
lijuang9a7d3b92015-11-30 14:41:24 +0800224static void menu_volume_down_func (struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800225{
lijuang9a7d3b92015-11-30 14:41:24 +0800226 msg_info->info.option_index++;
227 if (msg_info->info.option_index >= msg_info->info.option_num)
228 msg_info->info.option_index = 0;
lijuang7d235f42015-07-16 20:19:45 +0800229
lijuang9a7d3b92015-11-30 14:41:24 +0800230 if (msg_info->info.msg_type == DISPLAY_MENU_FASTBOOT) {
231 display_fastboot_menu_renew(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800232 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800233 update_volume_down_bg(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800234 }
lijuang7d235f42015-07-16 20:19:45 +0800235}
236
lijuang9a7d3b92015-11-30 14:41:24 +0800237/* enter to boot verification option page if volume key is pressed */
238static void boot_warning_volume_keys_func (struct select_msg_info* msg_info)
lijuang4ece1e72015-08-14 21:02:36 +0800239{
lijuang9a7d3b92015-11-30 14:41:24 +0800240 msg_info->last_msg_type = msg_info->info.msg_type;
241 display_bootverify_option_menu_renew(msg_info);
lijuang4ece1e72015-08-14 21:02:36 +0800242}
243
244/* update device's status via select option */
lijuang9a7d3b92015-11-30 14:41:24 +0800245static void power_key_func(struct select_msg_info* msg_info)
lijuang4ece1e72015-08-14 21:02:36 +0800246{
lijuang9a7d3b92015-11-30 14:41:24 +0800247 int reason = -1;
lijuang4ece1e72015-08-14 21:02:36 +0800248
lijuang9a7d3b92015-11-30 14:41:24 +0800249 switch (msg_info->info.msg_type) {
250 case DISPLAY_MENU_YELLOW:
251 case DISPLAY_MENU_ORANGE:
252 case DISPLAY_MENU_RED:
lijuangbdd9bb42016-03-01 18:22:17 +0800253 case DISPLAY_MENU_LOGGING:
Channagoud Kadabi86b0c112016-03-16 19:23:16 -0700254 case DISPLAY_MENU_EIO:
lijuang9a7d3b92015-11-30 14:41:24 +0800255 reason = CONTINUE;
256 break;
257 case DISPLAY_MENU_MORE_OPTION:
258 if(msg_info->info.option_index < ARRAY_SIZE(verify_index_action))
259 reason = verify_index_action[msg_info->info.option_index];
260 break;
261 case DISPLAY_MENU_UNLOCK:
262 case DISPLAY_MENU_UNLOCK_CRITICAL:
263 if(msg_info->info.option_index < ARRAY_SIZE(unlock_index_action))
264 reason = unlock_index_action[msg_info->info.option_index];
265 break;
266 case DISPLAY_MENU_FASTBOOT:
267 if(msg_info->info.option_index < ARRAY_SIZE(fastboot_index_action))
268 reason = fastboot_index_action[msg_info->info.option_index];
269 break;
270 default:
271 dprintf(CRITICAL,"Unsupported menu type\n");
272 break;
lijuang4ece1e72015-08-14 21:02:36 +0800273 }
274
lijuang9a7d3b92015-11-30 14:41:24 +0800275 if (reason != -1) {
276 update_device_status(msg_info, reason);
277 }
lijuang4ece1e72015-08-14 21:02:36 +0800278}
279
lijuang9a7d3b92015-11-30 14:41:24 +0800280/* Initialize different page's function
281 * DISPLAY_MENU_UNLOCK/DISPLAY_MENU_UNLOCK_CRITICAL
282 * DISPLAY_MENU_MORE_OPTION/DISPLAY_MENU_FASTBOOT:
lijuang7d235f42015-07-16 20:19:45 +0800283 * up_action_func: update select option's background when volume up
284 * is pressed
285 * down_action_func: update select option's background when volume up
286 * is pressed
287 * enter_action_func: update device's status via select option
lijuang9a7d3b92015-11-30 14:41:24 +0800288 * DISPLAY_MENU_YELLOW/DISPLAY_MENU_ORANGE/DISPLAY_MENU_RED:
lijuang7d235f42015-07-16 20:19:45 +0800289 * up_action_func/down_action_func: enter BOOT_VERIFY_PAGE2 when volume
290 * key is pressed
291 * enter_action_func: continue booting
292 */
293static struct pages_action menu_pages_action[] = {
lijuang9a7d3b92015-11-30 14:41:24 +0800294 [DISPLAY_MENU_UNLOCK] = {
lijuang7d235f42015-07-16 20:19:45 +0800295 menu_volume_up_func,
296 menu_volume_down_func,
lijuang9a7d3b92015-11-30 14:41:24 +0800297 power_key_func,
lijuang7d235f42015-07-16 20:19:45 +0800298 },
lijuang9a7d3b92015-11-30 14:41:24 +0800299 [DISPLAY_MENU_UNLOCK_CRITICAL] = {
lijuang7d235f42015-07-16 20:19:45 +0800300 menu_volume_up_func,
301 menu_volume_down_func,
lijuang9a7d3b92015-11-30 14:41:24 +0800302 power_key_func,
lijuang7d235f42015-07-16 20:19:45 +0800303 },
lijuang9a7d3b92015-11-30 14:41:24 +0800304 [DISPLAY_MENU_YELLOW] = {
305 boot_warning_volume_keys_func,
306 boot_warning_volume_keys_func,
307 power_key_func,
308 },
309 [DISPLAY_MENU_ORANGE] = {
310 boot_warning_volume_keys_func,
311 boot_warning_volume_keys_func,
312 power_key_func,
313 },
314 [DISPLAY_MENU_RED] = {
315 boot_warning_volume_keys_func,
316 boot_warning_volume_keys_func,
317 power_key_func,
318 },
lijuangbdd9bb42016-03-01 18:22:17 +0800319 [DISPLAY_MENU_LOGGING] = {
320 boot_warning_volume_keys_func,
321 boot_warning_volume_keys_func,
322 power_key_func,
323 },
Channagoud Kadabi86b0c112016-03-16 19:23:16 -0700324 [DISPLAY_MENU_EIO] = {
325 boot_warning_volume_keys_func,
326 boot_warning_volume_keys_func,
327 power_key_func,
328 },
lijuang9a7d3b92015-11-30 14:41:24 +0800329 [DISPLAY_MENU_MORE_OPTION] = {
330 menu_volume_up_func,
331 menu_volume_down_func,
332 power_key_func,
333 },
334 [DISPLAY_MENU_FASTBOOT] = {
335 menu_volume_up_func,
336 menu_volume_down_func,
337 power_key_func,
lijuang4ece1e72015-08-14 21:02:36 +0800338 },
339
lijuang7d235f42015-07-16 20:19:45 +0800340};
341
342void keys_detect_init()
343{
lijuang86f46b42015-12-23 13:39:22 +0800344 /* Waiting for all keys are released */
345 while(1) {
346 if(!keys[VOLUME_UP].keys_pressed_func() &&
347 !keys[VOLUME_DOWN].keys_pressed_func() &&
348 !keys[POWER_KEY].keys_pressed_func()) {
349 break;
350 }
351 thread_sleep(KEY_DETECT_FREQUENCY);
352 }
lijuang9a7d3b92015-11-30 14:41:24 +0800353
354 before_time = current_time();
lijuang7d235f42015-07-16 20:19:45 +0800355}
356
357int select_msg_keys_detect(void *param) {
358 struct select_msg_info *msg_info = (struct select_msg_info*)param;
lijuang7d235f42015-07-16 20:19:45 +0800359
lijuang9a7d3b92015-11-30 14:41:24 +0800360 msg_lock_init();
lijuang7d235f42015-07-16 20:19:45 +0800361 keys_detect_init();
362 while(1) {
lijuang7d235f42015-07-16 20:19:45 +0800363 /* 1: update select option's index, default it is the total option number
364 * volume up: index decrease, the option will scroll up from
365 * the bottom to top if the key is pressed firstly.
366 * eg: 5->4->3->2->1->0
367 * volume down: index increase, the option will scroll down from
368 * the bottom to top if the key is pressed firstly.
369 * eg: 5->0
370 * 2: update device's status via select option's index
371 */
372 if (is_key_pressed(VOLUME_UP)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800373 mutex_acquire(&msg_info->msg_lock);
374 menu_pages_action[msg_info->info.msg_type].up_action_func(msg_info);
375 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800376 } else if (is_key_pressed(VOLUME_DOWN)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800377 mutex_acquire(&msg_info->msg_lock);
378 menu_pages_action[msg_info->info.msg_type].down_action_func(msg_info);
379 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800380 } else if (is_key_pressed(POWER_KEY)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800381 mutex_acquire(&msg_info->msg_lock);
382 menu_pages_action[msg_info->info.msg_type].enter_action_func(msg_info);
383 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800384 }
385
lijuang9a7d3b92015-11-30 14:41:24 +0800386 mutex_acquire(&msg_info->msg_lock);
lijuangde34d502016-02-26 16:04:50 +0800387 /* Never time out if the timeout_time is 0 */
lijuang9a7d3b92015-11-30 14:41:24 +0800388 if(msg_info->info.timeout_time) {
lijuangde34d502016-02-26 16:04:50 +0800389 if ((current_time() - before_time) > msg_info->info.timeout_time)
390 msg_info->info.is_exit = true;
391 }
lijuang9a7d3b92015-11-30 14:41:24 +0800392
lijuangde34d502016-02-26 16:04:50 +0800393 if (msg_info->info.is_exit) {
394 msg_info->info.rel_exit = true;
395 mutex_release(&msg_info->msg_lock);
396 break;
lijuang9a7d3b92015-11-30 14:41:24 +0800397 }
398 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800399 thread_sleep(KEY_DETECT_FREQUENCY);
400 }
401
402 return 0;
403}