blob: 472814db0edbe2b9c0a852383939de5075d82958 [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>
44#include <../../../app/aboot/recovery.h>
45
46#define KEY_DETECT_FREQUENCY 50
47#define KEY_PRESS_TIMEOUT 5000
48
49#define RECOVERY_MODE 0x77665502
50#define FASTBOOT_MODE 0x77665500
51
52static uint32_t wait_time = 0;
53static int old_device_type = -1;
54
55extern 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);
61typedef uint32_t (*keys_action_func)(struct select_msg_info* msg_info,
62 uint32_t option_index);
63
64struct keys_stru {
65 int type;
66 keys_detect_func keys_pressed_func;
67};
68
69struct keys_stru keys[] = {
70 {VOLUME_UP, (uint32_t (*)(void))target_volume_up},
71 {VOLUME_DOWN, target_volume_down},
72 {POWER_KEY, pm8x41_get_pwrkey_is_pressed},
73};
74
75struct pages_action {
76 keys_action_func up_action_func;
77 keys_action_func down_action_func;
78 keys_action_func enter_action_func;
79};
80
81static int is_key_pressed(int keys_type)
82{
83 int count = 0;
84
85 if (keys[keys_type].keys_pressed_func()) {
86 /*if key is pressed, wait for 1 second to see if it is released*/
87 while(count++ < 10 && keys[keys_type].keys_pressed_func())
88 thread_sleep(100);
89 return 1;
90 }
91
92 return 0;
93}
94
95static void update_device_status(unsigned reason)
96{
97 if (reason == RECOVER) {
98 /* wipe data */
99 struct recovery_message msg;
100
101 snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
102 write_misc(0, &msg, sizeof(msg));
103
104 reboot_device(RECOVERY_MODE);
105 } else if (reason == RESTART) {
106 reboot_device(0);
107 } else if (reason == POWEROFF) {
108 shutdown_device();
109 } else if (reason == FASTBOOT) {
110 reboot_device(FASTBOOT_MODE);
111 } else if (reason == CONTINUE) {
112 fbcon_clear();
113 display_image_on_screen();
114 }
115}
116
117static void update_volume_up_bg(struct select_msg_info* msg_info, uint32_t option_index)
118{
119 if (option_index == msg_info->option_num - 1) {
120 fbcon_draw_msg_background(msg_info->option_start[0],
121 msg_info->option_end[0],
122 msg_info->option_bg[0], 0);
123
124 fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
125 msg_info->option_end[msg_info->option_num - 1],
126 msg_info->option_bg[msg_info->option_num - 1], 1);
127 } else {
128 fbcon_draw_msg_background(msg_info->option_start[option_index],
129 msg_info->option_end[option_index],
130 msg_info->option_bg[option_index], 1);
131
132 fbcon_draw_msg_background(msg_info->option_start[option_index + 1],
133 msg_info->option_end[option_index + 1],
134 msg_info->option_bg[option_index + 1], 0);
135 }
136}
137
138static void update_volume_down_bg(struct select_msg_info* msg_info, uint32_t option_index)
139{
140 if (option_index == 0) {
141 fbcon_draw_msg_background(msg_info->option_start[0],
142 msg_info->option_end[0],
143 msg_info->option_bg[0], 1);
144
145 fbcon_draw_msg_background(msg_info->option_start[msg_info->option_num - 1],
146 msg_info->option_end[msg_info->option_num - 1],
147 msg_info->option_bg[msg_info->option_num - 1], 0);
148 } else {
149 fbcon_draw_msg_background(msg_info->option_start[option_index],
150 msg_info->option_end[option_index],
151 msg_info->option_bg[option_index], 1);
152
153 fbcon_draw_msg_background(msg_info->option_start[option_index - 1],
154 msg_info->option_end[option_index - 1],
155 msg_info->option_bg[option_index - 1], 0);
156 }
157}
158
159/* update select option's background when volume up key is pressed */
160static uint32_t menu_volume_up_func (struct select_msg_info* msg_info,
161 uint32_t option_index)
162{
163 if (option_index == msg_info->option_num ||
164 option_index == 0) {
165 option_index = msg_info->option_num - 1;
166 } else if (option_index > 0) {
167 option_index--;
168 }
169
170 update_volume_up_bg(msg_info, option_index);
171
172 return option_index;
173}
174
175/* update select option's background when volume down key is pressed */
176static uint32_t menu_volume_down_func (struct select_msg_info* msg_info,
177 uint32_t option_index)
178{
179 option_index++;
180 if (option_index >= msg_info->option_num)
181 option_index = 0;
182
183 update_volume_down_bg(msg_info, option_index);
184
185 return option_index;
186}
187
188/* enter to boot verify page2 if volume key is pressed */
189static uint32_t boot_page1_volume_keys_func (struct select_msg_info* msg_info,
190 uint32_t option_index)
191{
192 keys_detect_init();
193 old_device_type = msg_info->msg_type;
194 display_boot_verified_option(msg_info);
195 msg_info->msg_volume_key_pressed = true;
196 option_index = msg_info->option_num;
197
198 return option_index;
199}
200
201/* update device's status via select option */
202static uint32_t unlock_power_key_func (struct select_msg_info* msg_info,
203 uint32_t option_index)
204{
205 int device_state = -1;
206 if (option_index == 0)
207 device_state = RECOVER;
208 else if (option_index == 1)
209 device_state = RESTART;
210
211 update_device_status(device_state);
212 return 0;
213}
214
215/* continue booting when power key is pressed at boot-verify page1 */
216static uint32_t boot_page1_power_key_func (struct select_msg_info* msg_info,
217 uint32_t option_index){
218 update_device_status(CONTINUE);
219 return option_index;
220}
221
222/* update device's status via select option */
223static uint32_t boot_page2_power_key_func (struct select_msg_info* msg_info,
224 uint32_t option_index)
225{
226 if (option_index == BACK) {
227 wait_time = 0;
228 msg_info->msg_timeout = false;
229 option_index = msg_info->option_num;
230 display_boot_verified_menu(msg_info,
231 old_device_type);
232 } else {
233 msg_info->msg_power_key_pressed = true;
234 update_device_status(option_index);
235 }
236 return option_index;
237}
238
239/* initialize different page's function
240 * UNLOCK_PAGE/BOOT_VERIFY_PAGE2:
241 * up_action_func: update select option's background when volume up
242 * is pressed
243 * down_action_func: update select option's background when volume up
244 * is pressed
245 * enter_action_func: update device's status via select option
246 * BOOT_VERIFY_PAGE1:
247 * up_action_func/down_action_func: enter BOOT_VERIFY_PAGE2 when volume
248 * key is pressed
249 * enter_action_func: continue booting
250 */
251static struct pages_action menu_pages_action[] = {
252 [UNLOCK_PAGE] = {
253 menu_volume_up_func,
254 menu_volume_down_func,
255 unlock_power_key_func,
256 },
257 [BOOT_VERIFY_PAGE1] = {
258 boot_page1_volume_keys_func,
259 boot_page1_volume_keys_func,
260 boot_page1_power_key_func,
261 },
262 [BOOT_VERIFY_PAGE2] = {
263 menu_volume_up_func,
264 menu_volume_down_func,
265 boot_page2_power_key_func,
266 },
267};
268
269void keys_detect_init()
270{
271 wait_time = 0;
272}
273
274int select_msg_keys_detect(void *param) {
275 struct select_msg_info *msg_info = (struct select_msg_info*)param;
276 uint32_t current_page_index;
277 uint32_t option_index = msg_info->option_num;
278
279 keys_detect_init();
280 while(1) {
281 /* get page's index via different message type */
282 switch(msg_info->msg_type) {
283 case DISPLAY_MENU_UNLOCK:
284 current_page_index = UNLOCK_PAGE;
285 break;
286 case DISPLAY_MENU_MORE_OPTION:
287 current_page_index = BOOT_VERIFY_PAGE2;
288 break;
289 default:
290 current_page_index = BOOT_VERIFY_PAGE1;
291 break;
292 }
293
294 /* device will continue booting when user has no action
295 * on BOOT_VERIFY_PAGE1
296 */
297 if (wait_time > KEY_PRESS_TIMEOUT)
298 msg_info->msg_timeout = true;
299
300 /* 1: update select option's index, default it is the total option number
301 * volume up: index decrease, the option will scroll up from
302 * the bottom to top if the key is pressed firstly.
303 * eg: 5->4->3->2->1->0
304 * volume down: index increase, the option will scroll down from
305 * the bottom to top if the key is pressed firstly.
306 * eg: 5->0
307 * 2: update device's status via select option's index
308 */
309 if (is_key_pressed(VOLUME_UP)) {
310 option_index =
311 menu_pages_action[current_page_index].up_action_func(msg_info, option_index);
312 } else if (is_key_pressed(VOLUME_DOWN)) {
313 option_index =
314 menu_pages_action[current_page_index].down_action_func(msg_info, option_index);
315 } else if (is_key_pressed(POWER_KEY)) {
316 option_index =
317 menu_pages_action[current_page_index].enter_action_func(msg_info, option_index);
318 }
319
320 wait_time += KEY_DETECT_FREQUENCY;
321 thread_sleep(KEY_DETECT_FREQUENCY);
322 }
323
324 return 0;
325}