blob: 6b552e81844588f4703e25f59bbf2d94d0356b57 [file] [log] [blame]
lijuangf55ad052018-04-23 18:30:50 +08001/* Copyright (c) 2015-2018, 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>
Kishor PK60a68212017-05-08 16:55:57 +053048#include <string.h>
lijuang7d235f42015-07-16 20:19:45 +080049
50#define KEY_DETECT_FREQUENCY 50
lijuang7d235f42015-07-16 20:19:45 +080051
lijuang9a7d3b92015-11-30 14:41:24 +080052static time_t before_time;
lijuang7d235f42015-07-16 20:19:45 +080053
Parth Dixit54ac3bb2017-03-07 15:52:48 +053054extern bool pwr_key_is_pressed;
lijuang7d235f42015-07-16 20:19:45 +080055extern int target_volume_up();
56extern uint32_t target_volume_down();
57extern void reboot_device(unsigned reboot_reason);
58extern void shutdown_device();
59
60typedef uint32_t (*keys_detect_func)(void);
lijuang9a7d3b92015-11-30 14:41:24 +080061typedef void (*keys_action_func)(struct select_msg_info* msg_info);
lijuang7d235f42015-07-16 20:19:45 +080062
63struct keys_stru {
64 int type;
65 keys_detect_func keys_pressed_func;
66};
67
68struct keys_stru keys[] = {
69 {VOLUME_UP, (uint32_t (*)(void))target_volume_up},
70 {VOLUME_DOWN, target_volume_down},
71 {POWER_KEY, pm8x41_get_pwrkey_is_pressed},
72};
73
74struct pages_action {
75 keys_action_func up_action_func;
76 keys_action_func down_action_func;
77 keys_action_func enter_action_func;
78};
79
lijuang9a7d3b92015-11-30 14:41:24 +080080static uint32_t verify_index_action[] = {
81 [0] = POWEROFF,
82 [1] = RESTART,
83 [2] = RECOVER,
84 [3] = FASTBOOT,
85 [4] = BACK,
86};
87
88static uint32_t fastboot_index_action[] = {
89 [0] = RESTART,
90 [1] = FASTBOOT,
91 [2] = RECOVER,
92 [3] = POWEROFF,
lijuang42aefaa2016-04-14 15:55:17 +080093 [4] = FFBM,
lijuang9a7d3b92015-11-30 14:41:24 +080094};
95
96static uint32_t unlock_index_action[] = {
lijuangf55ad052018-04-23 18:30:50 +080097 [0] = RESTART,
98 [1] = RECOVER,
lijuang9a7d3b92015-11-30 14:41:24 +080099};
100
lijuang7d235f42015-07-16 20:19:45 +0800101static int is_key_pressed(int keys_type)
102{
103 int count = 0;
104
105 if (keys[keys_type].keys_pressed_func()) {
106 /*if key is pressed, wait for 1 second to see if it is released*/
107 while(count++ < 10 && keys[keys_type].keys_pressed_func())
108 thread_sleep(100);
109 return 1;
110 }
111
112 return 0;
113}
114
lijuang9a7d3b92015-11-30 14:41:24 +0800115static void update_device_status(struct select_msg_info* msg_info, int reason)
lijuang7d235f42015-07-16 20:19:45 +0800116{
lijuang42aefaa2016-04-14 15:55:17 +0800117 char ffbm_page_buffer[FFBM_MODE_BUF_SIZE];
lijuang9a7d3b92015-11-30 14:41:24 +0800118 fbcon_clear();
119 switch (reason) {
120 case RECOVER:
lijuangf55ad052018-04-23 18:30:50 +0800121 reset_device_unlock_status(msg_info->info.msg_type);
lijuang9a7d3b92015-11-30 14:41:24 +0800122 reboot_device(RECOVERY_MODE);
123 break;
124 case RESTART:
125 reboot_device(0);
126 break;
127 case POWEROFF:
128 shutdown_device();
129 break;
130 case FASTBOOT:
131 reboot_device(FASTBOOT_MODE);
132 break;
133 case CONTINUE:
lijuang9a7d3b92015-11-30 14:41:24 +0800134 /* Continue boot, no need to detect the keys'status */
lijuangde34d502016-02-26 16:04:50 +0800135 msg_info->info.is_exit = true;
lijuang9a7d3b92015-11-30 14:41:24 +0800136 break;
137 case BACK:
138 display_bootverify_menu_renew(msg_info, msg_info->last_msg_type);
139 before_time = current_time();
140
141 break;
lijuang42aefaa2016-04-14 15:55:17 +0800142 case FFBM:
Kishor PK60a68212017-05-08 16:55:57 +0530143 memset(&ffbm_page_buffer, 0, sizeof(ffbm_page_buffer));
lijuang42aefaa2016-04-14 15:55:17 +0800144 snprintf(ffbm_page_buffer, sizeof(ffbm_page_buffer), "ffbm-00");
145 write_misc(0, ffbm_page_buffer, sizeof(ffbm_page_buffer));
146
147 reboot_device(0);
148 break;
lijuang7d235f42015-07-16 20:19:45 +0800149 }
150}
151
lijuang9a7d3b92015-11-30 14:41:24 +0800152/* msg_lock need to be holded when call this function. */
153static void update_volume_up_bg(struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800154{
lijuang9a7d3b92015-11-30 14:41:24 +0800155 if (msg_info->info.option_index == msg_info->info.option_num - 1) {
156 fbcon_draw_msg_background(msg_info->info.option_start[0],
157 msg_info->info.option_end[0],
158 msg_info->info.option_bg[0], 0);
lijuang7d235f42015-07-16 20:19:45 +0800159
lijuang9a7d3b92015-11-30 14:41:24 +0800160 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_num - 1],
161 msg_info->info.option_end[msg_info->info.option_num - 1],
162 msg_info->info.option_bg[msg_info->info.option_num - 1], 1);
lijuang7d235f42015-07-16 20:19:45 +0800163 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800164 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index],
165 msg_info->info.option_end[msg_info->info.option_index],
166 msg_info->info.option_bg[msg_info->info.option_index], 1);
lijuang7d235f42015-07-16 20:19:45 +0800167
lijuang9a7d3b92015-11-30 14:41:24 +0800168 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index + 1],
169 msg_info->info.option_end[msg_info->info.option_index + 1],
170 msg_info->info.option_bg[msg_info->info.option_index + 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800171 }
172}
173
lijuang9a7d3b92015-11-30 14:41:24 +0800174/* msg_lock need to be holded when call this function. */
175static void update_volume_down_bg(struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800176{
lijuang9a7d3b92015-11-30 14:41:24 +0800177 if (msg_info->info.option_index == 0) {
178 fbcon_draw_msg_background(msg_info->info.option_start[0],
179 msg_info->info.option_end[0],
180 msg_info->info.option_bg[0], 1);
lijuang7d235f42015-07-16 20:19:45 +0800181
lijuang9a7d3b92015-11-30 14:41:24 +0800182 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_num - 1],
183 msg_info->info.option_end[msg_info->info.option_num - 1],
184 msg_info->info.option_bg[msg_info->info.option_num - 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800185 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800186 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index],
187 msg_info->info.option_end[msg_info->info.option_index],
188 msg_info->info.option_bg[msg_info->info.option_index], 1);
lijuang7d235f42015-07-16 20:19:45 +0800189
lijuang9a7d3b92015-11-30 14:41:24 +0800190 fbcon_draw_msg_background(msg_info->info.option_start[msg_info->info.option_index - 1],
191 msg_info->info.option_end[msg_info->info.option_index - 1],
192 msg_info->info.option_bg[msg_info->info.option_index - 1], 0);
lijuang7d235f42015-07-16 20:19:45 +0800193 }
194}
195
196/* update select option's background when volume up key is pressed */
lijuang9a7d3b92015-11-30 14:41:24 +0800197static void menu_volume_up_func (struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800198{
lijuang9a7d3b92015-11-30 14:41:24 +0800199 if (msg_info->info.option_index == 0)
200 msg_info->info.option_index = msg_info->info.option_num - 1;
201 else
202 msg_info->info.option_index--;
203
204 if (msg_info->info.msg_type == DISPLAY_MENU_FASTBOOT) {
205 display_fastboot_menu_renew(msg_info);
206 } else {
207 update_volume_up_bg(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800208 }
lijuang7d235f42015-07-16 20:19:45 +0800209}
210
211/* update select option's background when volume down key is pressed */
lijuang9a7d3b92015-11-30 14:41:24 +0800212static void menu_volume_down_func (struct select_msg_info* msg_info)
lijuang7d235f42015-07-16 20:19:45 +0800213{
lijuang9a7d3b92015-11-30 14:41:24 +0800214 msg_info->info.option_index++;
215 if (msg_info->info.option_index >= msg_info->info.option_num)
216 msg_info->info.option_index = 0;
lijuang7d235f42015-07-16 20:19:45 +0800217
lijuang9a7d3b92015-11-30 14:41:24 +0800218 if (msg_info->info.msg_type == DISPLAY_MENU_FASTBOOT) {
219 display_fastboot_menu_renew(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800220 } else {
lijuang9a7d3b92015-11-30 14:41:24 +0800221 update_volume_down_bg(msg_info);
lijuang7d235f42015-07-16 20:19:45 +0800222 }
lijuang7d235f42015-07-16 20:19:45 +0800223}
224
lijuang9a7d3b92015-11-30 14:41:24 +0800225/* enter to boot verification option page if volume key is pressed */
226static void boot_warning_volume_keys_func (struct select_msg_info* msg_info)
lijuang4ece1e72015-08-14 21:02:36 +0800227{
lijuang9a7d3b92015-11-30 14:41:24 +0800228 msg_info->last_msg_type = msg_info->info.msg_type;
229 display_bootverify_option_menu_renew(msg_info);
lijuang4ece1e72015-08-14 21:02:36 +0800230}
231
232/* update device's status via select option */
lijuang9a7d3b92015-11-30 14:41:24 +0800233static void power_key_func(struct select_msg_info* msg_info)
lijuang4ece1e72015-08-14 21:02:36 +0800234{
lijuang9a7d3b92015-11-30 14:41:24 +0800235 int reason = -1;
lijuang4ece1e72015-08-14 21:02:36 +0800236
lijuang9a7d3b92015-11-30 14:41:24 +0800237 switch (msg_info->info.msg_type) {
238 case DISPLAY_MENU_YELLOW:
239 case DISPLAY_MENU_ORANGE:
240 case DISPLAY_MENU_RED:
lijuangbdd9bb42016-03-01 18:22:17 +0800241 case DISPLAY_MENU_LOGGING:
Parth Dixit54ac3bb2017-03-07 15:52:48 +0530242 reason = CONTINUE;
243 break;
Channagoud Kadabi86b0c112016-03-16 19:23:16 -0700244 case DISPLAY_MENU_EIO:
Parth Dixit54ac3bb2017-03-07 15:52:48 +0530245 pwr_key_is_pressed = true;
lijuang9a7d3b92015-11-30 14:41:24 +0800246 reason = CONTINUE;
247 break;
248 case DISPLAY_MENU_MORE_OPTION:
249 if(msg_info->info.option_index < ARRAY_SIZE(verify_index_action))
250 reason = verify_index_action[msg_info->info.option_index];
251 break;
252 case DISPLAY_MENU_UNLOCK:
253 case DISPLAY_MENU_UNLOCK_CRITICAL:
lijuangf55ad052018-04-23 18:30:50 +0800254 case DISPLAY_MENU_LOCK:
255 case DISPLAY_MENU_LOCK_CRITICAL:
lijuang9a7d3b92015-11-30 14:41:24 +0800256 if(msg_info->info.option_index < ARRAY_SIZE(unlock_index_action))
257 reason = unlock_index_action[msg_info->info.option_index];
258 break;
259 case DISPLAY_MENU_FASTBOOT:
260 if(msg_info->info.option_index < ARRAY_SIZE(fastboot_index_action))
261 reason = fastboot_index_action[msg_info->info.option_index];
262 break;
263 default:
264 dprintf(CRITICAL,"Unsupported menu type\n");
265 break;
lijuang4ece1e72015-08-14 21:02:36 +0800266 }
267
lijuang9a7d3b92015-11-30 14:41:24 +0800268 if (reason != -1) {
269 update_device_status(msg_info, reason);
270 }
lijuang4ece1e72015-08-14 21:02:36 +0800271}
272
lijuang9a7d3b92015-11-30 14:41:24 +0800273/* Initialize different page's function
274 * DISPLAY_MENU_UNLOCK/DISPLAY_MENU_UNLOCK_CRITICAL
275 * DISPLAY_MENU_MORE_OPTION/DISPLAY_MENU_FASTBOOT:
lijuang7d235f42015-07-16 20:19:45 +0800276 * up_action_func: update select option's background when volume up
277 * is pressed
278 * down_action_func: update select option's background when volume up
279 * is pressed
280 * enter_action_func: update device's status via select option
lijuang9a7d3b92015-11-30 14:41:24 +0800281 * DISPLAY_MENU_YELLOW/DISPLAY_MENU_ORANGE/DISPLAY_MENU_RED:
lijuang7d235f42015-07-16 20:19:45 +0800282 * up_action_func/down_action_func: enter BOOT_VERIFY_PAGE2 when volume
283 * key is pressed
284 * enter_action_func: continue booting
285 */
286static struct pages_action menu_pages_action[] = {
lijuang9a7d3b92015-11-30 14:41:24 +0800287 [DISPLAY_MENU_UNLOCK] = {
lijuang7d235f42015-07-16 20:19:45 +0800288 menu_volume_up_func,
289 menu_volume_down_func,
lijuang9a7d3b92015-11-30 14:41:24 +0800290 power_key_func,
lijuang7d235f42015-07-16 20:19:45 +0800291 },
lijuang9a7d3b92015-11-30 14:41:24 +0800292 [DISPLAY_MENU_UNLOCK_CRITICAL] = {
lijuang7d235f42015-07-16 20:19:45 +0800293 menu_volume_up_func,
294 menu_volume_down_func,
lijuang9a7d3b92015-11-30 14:41:24 +0800295 power_key_func,
lijuang7d235f42015-07-16 20:19:45 +0800296 },
lijuangf55ad052018-04-23 18:30:50 +0800297 [DISPLAY_MENU_LOCK] = {
298 menu_volume_up_func,
299 menu_volume_down_func,
300 power_key_func,
301 },
302 [DISPLAY_MENU_LOCK_CRITICAL] = {
303 menu_volume_up_func,
304 menu_volume_down_func,
305 power_key_func,
306 },
lijuang9a7d3b92015-11-30 14:41:24 +0800307 [DISPLAY_MENU_YELLOW] = {
308 boot_warning_volume_keys_func,
309 boot_warning_volume_keys_func,
310 power_key_func,
311 },
312 [DISPLAY_MENU_ORANGE] = {
313 boot_warning_volume_keys_func,
314 boot_warning_volume_keys_func,
315 power_key_func,
316 },
317 [DISPLAY_MENU_RED] = {
318 boot_warning_volume_keys_func,
319 boot_warning_volume_keys_func,
320 power_key_func,
321 },
lijuangbdd9bb42016-03-01 18:22:17 +0800322 [DISPLAY_MENU_LOGGING] = {
323 boot_warning_volume_keys_func,
324 boot_warning_volume_keys_func,
325 power_key_func,
326 },
Channagoud Kadabi86b0c112016-03-16 19:23:16 -0700327 [DISPLAY_MENU_EIO] = {
328 boot_warning_volume_keys_func,
329 boot_warning_volume_keys_func,
330 power_key_func,
331 },
lijuang9a7d3b92015-11-30 14:41:24 +0800332 [DISPLAY_MENU_MORE_OPTION] = {
333 menu_volume_up_func,
334 menu_volume_down_func,
335 power_key_func,
336 },
337 [DISPLAY_MENU_FASTBOOT] = {
338 menu_volume_up_func,
339 menu_volume_down_func,
340 power_key_func,
lijuang4ece1e72015-08-14 21:02:36 +0800341 },
342
lijuang7d235f42015-07-16 20:19:45 +0800343};
344
345void keys_detect_init()
346{
lijuang86f46b42015-12-23 13:39:22 +0800347 /* Waiting for all keys are released */
348 while(1) {
349 if(!keys[VOLUME_UP].keys_pressed_func() &&
350 !keys[VOLUME_DOWN].keys_pressed_func() &&
351 !keys[POWER_KEY].keys_pressed_func()) {
352 break;
353 }
354 thread_sleep(KEY_DETECT_FREQUENCY);
355 }
lijuang9a7d3b92015-11-30 14:41:24 +0800356
357 before_time = current_time();
lijuang7d235f42015-07-16 20:19:45 +0800358}
359
360int select_msg_keys_detect(void *param) {
361 struct select_msg_info *msg_info = (struct select_msg_info*)param;
lijuang7d235f42015-07-16 20:19:45 +0800362
lijuang9a7d3b92015-11-30 14:41:24 +0800363 msg_lock_init();
lijuang7d235f42015-07-16 20:19:45 +0800364 keys_detect_init();
365 while(1) {
lijuang7d235f42015-07-16 20:19:45 +0800366 /* 1: update select option's index, default it is the total option number
367 * volume up: index decrease, the option will scroll up from
368 * the bottom to top if the key is pressed firstly.
369 * eg: 5->4->3->2->1->0
370 * volume down: index increase, the option will scroll down from
371 * the bottom to top if the key is pressed firstly.
372 * eg: 5->0
373 * 2: update device's status via select option's index
374 */
375 if (is_key_pressed(VOLUME_UP)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800376 mutex_acquire(&msg_info->msg_lock);
377 menu_pages_action[msg_info->info.msg_type].up_action_func(msg_info);
378 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800379 } else if (is_key_pressed(VOLUME_DOWN)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800380 mutex_acquire(&msg_info->msg_lock);
381 menu_pages_action[msg_info->info.msg_type].down_action_func(msg_info);
382 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800383 } else if (is_key_pressed(POWER_KEY)) {
lijuang9a7d3b92015-11-30 14:41:24 +0800384 mutex_acquire(&msg_info->msg_lock);
385 menu_pages_action[msg_info->info.msg_type].enter_action_func(msg_info);
386 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800387 }
388
lijuang9a7d3b92015-11-30 14:41:24 +0800389 mutex_acquire(&msg_info->msg_lock);
lijuangde34d502016-02-26 16:04:50 +0800390 /* Never time out if the timeout_time is 0 */
lijuang9a7d3b92015-11-30 14:41:24 +0800391 if(msg_info->info.timeout_time) {
lijuangde34d502016-02-26 16:04:50 +0800392 if ((current_time() - before_time) > msg_info->info.timeout_time)
393 msg_info->info.is_exit = true;
394 }
lijuang9a7d3b92015-11-30 14:41:24 +0800395
lijuangde34d502016-02-26 16:04:50 +0800396 if (msg_info->info.is_exit) {
397 msg_info->info.rel_exit = true;
398 mutex_release(&msg_info->msg_lock);
399 break;
lijuang9a7d3b92015-11-30 14:41:24 +0800400 }
401 mutex_release(&msg_info->msg_lock);
lijuang7d235f42015-07-16 20:19:45 +0800402 thread_sleep(KEY_DETECT_FREQUENCY);
403 }
404
405 return 0;
406}