blob: 28766a79b00b606143c1b92a4e08a995e2bea99d [file] [log] [blame]
lijuang7d235f42015-07-16 20:19:45 +08001/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2*
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>
lijuang7d235f42015-07-16 20:19:45 +080045#include <../../../app/aboot/recovery.h>
lijuang4ece1e72015-08-14 21:02:36 +080046#include <../../../app/aboot/devinfo.h>
lijuang7d235f42015-07-16 20:19:45 +080047
48#define KEY_DETECT_FREQUENCY 50
49#define KEY_PRESS_TIMEOUT 5000
50
lijuang7d235f42015-07-16 20:19:45 +080051static uint32_t wait_time = 0;
52static int old_device_type = -1;
53
54extern int target_volume_up();
55extern uint32_t target_volume_down();
56extern void reboot_device(unsigned reboot_reason);
57extern void shutdown_device();
58
59typedef uint32_t (*keys_detect_func)(void);
60typedef uint32_t (*keys_action_func)(struct select_msg_info* msg_info,
61 uint32_t option_index);
62
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
80static int is_key_pressed(int keys_type)
81{
82 int count = 0;
83
84 if (keys[keys_type].keys_pressed_func()) {
85 /*if key is pressed, wait for 1 second to see if it is released*/
86 while(count++ < 10 && keys[keys_type].keys_pressed_func())
87 thread_sleep(100);
88 return 1;
89 }
90
91 return 0;
92}
93
lijuangf5045b52015-09-07 17:19:20 +080094static void update_device_status(unsigned reason, int type)
lijuang7d235f42015-07-16 20:19:45 +080095{
96 if (reason == RECOVER) {
lijuangf5045b52015-09-07 17:19:20 +080097 if (type == DISPLAY_MENU_UNLOCK) {
lijuang4ece1e72015-08-14 21:02:36 +080098 set_device_unlock_value(UNLOCK, TRUE);
99 } else if (type == DISPLAY_MENU_UNLOCK_CRITICAL) {
100 set_device_unlock_value(UNLOCK_CRITICAL, TRUE);
101 }
lijuang7d235f42015-07-16 20:19:45 +0800102
lijuang4ece1e72015-08-14 21:02:36 +0800103 if (type == DISPLAY_MENU_UNLOCK ||
104 type == DISPLAY_MENU_UNLOCK_CRITICAL) {
lijuangf5045b52015-09-07 17:19:20 +0800105 /* wipe data */
106 struct recovery_message msg;
107
108 snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
109 write_misc(0, &msg, sizeof(msg));
110 }
lijuang7d235f42015-07-16 20:19:45 +0800111
112 reboot_device(RECOVERY_MODE);
113 } else if (reason == RESTART) {
114 reboot_device(0);
115 } else if (reason == POWEROFF) {
116 shutdown_device();
117 } else if (reason == FASTBOOT) {
118 reboot_device(FASTBOOT_MODE);
119 } else if (reason == CONTINUE) {
120 fbcon_clear();
121 display_image_on_screen();
122 }
123}
124
125static void update_volume_up_bg(struct select_msg_info* msg_info, uint32_t option_index)
126{
127 if (option_index == msg_info->option_num - 1) {
128 fbcon_draw_msg_background(msg_info->option_start[0],
129 msg_info->option_end[0],
130 msg_info->option_bg[0], 0);
131
132 fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
133 msg_info->option_end[msg_info->option_num - 1],
134 msg_info->option_bg[msg_info->option_num - 1], 1);
135 } else {
136 fbcon_draw_msg_background(msg_info->option_start[option_index],
137 msg_info->option_end[option_index],
138 msg_info->option_bg[option_index], 1);
139
140 fbcon_draw_msg_background(msg_info->option_start[option_index + 1],
141 msg_info->option_end[option_index + 1],
142 msg_info->option_bg[option_index + 1], 0);
143 }
144}
145
146static void update_volume_down_bg(struct select_msg_info* msg_info, uint32_t option_index)
147{
148 if (option_index == 0) {
149 fbcon_draw_msg_background(msg_info->option_start[0],
150 msg_info->option_end[0],
151 msg_info->option_bg[0], 1);
152
153 fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
154 msg_info->option_end[msg_info->option_num - 1],
155 msg_info->option_bg[msg_info->option_num - 1], 0);
156 } else {
157 fbcon_draw_msg_background(msg_info->option_start[option_index],
158 msg_info->option_end[option_index],
159 msg_info->option_bg[option_index], 1);
160
161 fbcon_draw_msg_background(msg_info->option_start[option_index - 1],
162 msg_info->option_end[option_index - 1],
163 msg_info->option_bg[option_index - 1], 0);
164 }
165}
166
167/* update select option's background when volume up key is pressed */
168static uint32_t menu_volume_up_func (struct select_msg_info* msg_info,
169 uint32_t option_index)
170{
171 if (option_index == msg_info->option_num ||
172 option_index == 0) {
173 option_index = msg_info->option_num - 1;
174 } else if (option_index > 0) {
175 option_index--;
176 }
177
178 update_volume_up_bg(msg_info, option_index);
179
180 return option_index;
181}
182
183/* update select option's background when volume down key is pressed */
184static uint32_t menu_volume_down_func (struct select_msg_info* msg_info,
185 uint32_t option_index)
186{
187 option_index++;
188 if (option_index >= msg_info->option_num)
189 option_index = 0;
190
191 update_volume_down_bg(msg_info, option_index);
192
193 return option_index;
194}
195
196/* enter to boot verify page2 if volume key is pressed */
197static uint32_t boot_page1_volume_keys_func (struct select_msg_info* msg_info,
198 uint32_t option_index)
199{
200 keys_detect_init();
201 old_device_type = msg_info->msg_type;
202 display_boot_verified_option(msg_info);
203 msg_info->msg_volume_key_pressed = true;
204 option_index = msg_info->option_num;
205
206 return option_index;
207}
208
209/* update device's status via select option */
210static uint32_t unlock_power_key_func (struct select_msg_info* msg_info,
211 uint32_t option_index)
212{
213 int device_state = -1;
214 if (option_index == 0)
215 device_state = RECOVER;
216 else if (option_index == 1)
217 device_state = RESTART;
218
lijuangf5045b52015-09-07 17:19:20 +0800219 update_device_status(device_state, msg_info->msg_type);
lijuang7d235f42015-07-16 20:19:45 +0800220 return 0;
221}
222
223/* continue booting when power key is pressed at boot-verify page1 */
224static uint32_t boot_page1_power_key_func (struct select_msg_info* msg_info,
225 uint32_t option_index){
lijuang4ece1e72015-08-14 21:02:36 +0800226 msg_info->msg_power_key_pressed = true;
lijuangf5045b52015-09-07 17:19:20 +0800227 update_device_status(CONTINUE, msg_info->msg_type);
lijuang7d235f42015-07-16 20:19:45 +0800228 return option_index;
229}
230
231/* update device's status via select option */
232static uint32_t boot_page2_power_key_func (struct select_msg_info* msg_info,
233 uint32_t option_index)
234{
235 if (option_index == BACK) {
236 wait_time = 0;
237 msg_info->msg_timeout = false;
238 option_index = msg_info->option_num;
239 display_boot_verified_menu(msg_info,
240 old_device_type);
241 } else {
242 msg_info->msg_power_key_pressed = true;
lijuangf5045b52015-09-07 17:19:20 +0800243 update_device_status(option_index, msg_info->msg_type);
lijuang7d235f42015-07-16 20:19:45 +0800244 }
245 return option_index;
246}
247
lijuang4ece1e72015-08-14 21:02:36 +0800248static uint32_t fastboot_volume_up_func (struct select_msg_info* msg_info,
249 uint32_t option_index)
250{
251 if (option_index == msg_info->option_num ||
252 option_index == 0) {
253 option_index = msg_info->option_num - 1;
254 } else if (option_index > 0) {
255 option_index--;
256 }
257
258 display_fastboot_menu(msg_info, option_index);
259
260 return option_index;
261}
262
263static uint32_t fastboot_volume_down_func (struct select_msg_info* msg_info,
264 uint32_t option_index)
265{
266 option_index++;
267 if (option_index > msg_info->option_num)
268 option_index = 1;
269 if (option_index == msg_info->option_num)
270 option_index = 0;
271
272 display_fastboot_menu(msg_info, option_index);
273
274 return option_index;
275}
276
277/* update device's status via select option */
278static uint32_t fastboot_power_key_func (struct select_msg_info* msg_info,
279 uint32_t option_index)
280{
281 int device_state[] = {RESTART, FASTBOOT, RECOVER, POWEROFF};
282
283 if(option_index < sizeof(device_state)) {
284 update_device_status(device_state[option_index], msg_info->msg_type);
285 } else {
286 dprintf(CRITICAL, "ERRPR: option index is overflow!!!\n");
287 return 1;
288 }
289
290 return 0;
291}
292
lijuang7d235f42015-07-16 20:19:45 +0800293/* initialize different page's function
294 * UNLOCK_PAGE/BOOT_VERIFY_PAGE2:
295 * up_action_func: update select option's background when volume up
296 * is pressed
297 * down_action_func: update select option's background when volume up
298 * is pressed
299 * enter_action_func: update device's status via select option
300 * BOOT_VERIFY_PAGE1:
301 * up_action_func/down_action_func: enter BOOT_VERIFY_PAGE2 when volume
302 * key is pressed
303 * enter_action_func: continue booting
304 */
305static struct pages_action menu_pages_action[] = {
306 [UNLOCK_PAGE] = {
307 menu_volume_up_func,
308 menu_volume_down_func,
309 unlock_power_key_func,
310 },
311 [BOOT_VERIFY_PAGE1] = {
312 boot_page1_volume_keys_func,
313 boot_page1_volume_keys_func,
314 boot_page1_power_key_func,
315 },
316 [BOOT_VERIFY_PAGE2] = {
317 menu_volume_up_func,
318 menu_volume_down_func,
319 boot_page2_power_key_func,
320 },
lijuang4ece1e72015-08-14 21:02:36 +0800321 [FASTBOOT_PAGE] = {
322 fastboot_volume_up_func,
323 fastboot_volume_down_func,
324 fastboot_power_key_func,
325 },
326
lijuang7d235f42015-07-16 20:19:45 +0800327};
328
329void keys_detect_init()
330{
331 wait_time = 0;
332}
333
334int select_msg_keys_detect(void *param) {
335 struct select_msg_info *msg_info = (struct select_msg_info*)param;
336 uint32_t current_page_index;
337 uint32_t option_index = msg_info->option_num;
338
339 keys_detect_init();
340 while(1) {
341 /* get page's index via different message type */
342 switch(msg_info->msg_type) {
343 case DISPLAY_MENU_UNLOCK:
lijuang4ece1e72015-08-14 21:02:36 +0800344 case DISPLAY_MENU_UNLOCK_CRITICAL:
lijuang7d235f42015-07-16 20:19:45 +0800345 current_page_index = UNLOCK_PAGE;
346 break;
347 case DISPLAY_MENU_MORE_OPTION:
348 current_page_index = BOOT_VERIFY_PAGE2;
349 break;
lijuang4ece1e72015-08-14 21:02:36 +0800350 case DISPLAY_MENU_FASTBOOT:
351 current_page_index = FASTBOOT_PAGE;
352 break;
lijuang7d235f42015-07-16 20:19:45 +0800353 default:
354 current_page_index = BOOT_VERIFY_PAGE1;
355 break;
356 }
357
358 /* device will continue booting when user has no action
359 * on BOOT_VERIFY_PAGE1
360 */
361 if (wait_time > KEY_PRESS_TIMEOUT)
362 msg_info->msg_timeout = true;
363
364 /* 1: update select option's index, default it is the total option number
365 * volume up: index decrease, the option will scroll up from
366 * the bottom to top if the key is pressed firstly.
367 * eg: 5->4->3->2->1->0
368 * volume down: index increase, the option will scroll down from
369 * the bottom to top if the key is pressed firstly.
370 * eg: 5->0
371 * 2: update device's status via select option's index
372 */
373 if (is_key_pressed(VOLUME_UP)) {
374 option_index =
375 menu_pages_action[current_page_index].up_action_func(msg_info, option_index);
376 } else if (is_key_pressed(VOLUME_DOWN)) {
377 option_index =
378 menu_pages_action[current_page_index].down_action_func(msg_info, option_index);
379 } else if (is_key_pressed(POWER_KEY)) {
380 option_index =
381 menu_pages_action[current_page_index].enter_action_func(msg_info, option_index);
382 }
383
384 wait_time += KEY_DETECT_FREQUENCY;
385 thread_sleep(KEY_DETECT_FREQUENCY);
386 }
387
388 return 0;
389}