• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <fcntl.h>
18 #include <linux/fb.h>
19 #include <linux/input.h>
20 #include <pthread.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/ioctl.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <linux/ioctl.h>
30 
31 #include "common.h"
32 #include "device.h"
33 #include "ui.h"
34 #include "screen_ui.h"
35 
36 /* CEA-861 specifies a maximum of 65 modes in an EDID */
37 #define CEA_MODEDB_SIZE 65
38 static const char* HEADERS[] = { "Use hardware button to move cursor; long-press to select item.",
39                                  "",
40                                  NULL };
41 
42 // these strings are never actually displayed
43 static const char* ITEMS[] =  {"reboot system now",
44                                "apply update from ADB",
45                                "wipe data/factory reset",
46                                "wipe cache partition",
47                                NULL };
48 
49 #define kFBDevice "/dev/graphics/fb0"
50 #define FBIO_PSB_SET_RGBX       _IOWR('F', 0x42, struct fb_var_screeninfo)
51 #define FBIO_PSB_SET_RMODE      _IOWR('F', 0x43, struct fb_var_screeninfo)
52 
53 struct led_rgb_vals {
54         uint8_t rgb[3];
55 };
56 
57 // Return the current time as a double (including fractions of a second).
now()58 static double now() {
59     struct timeval tv;
60     gettimeofday(&tv, NULL);
61     return tv.tv_sec + tv.tv_usec / 1000000.0;
62 }
63 
64 class FuguUI : public ScreenRecoveryUI {
65 public:
FuguUI()66     FuguUI() :
67         text_visible(false),
68         text_ever_visible(false),
69         background_mode(NONE),
70         up_keys(0),
71         next_key_pos(0),
72         pending_select(false),
73         long_press(false) {
74         pthread_mutex_init(&long_mu, NULL);
75         memset(last_keys, 0, kKeyBufferSize * sizeof(int));
76     }
77 
Init()78     void Init() {
79         SetupDisplayMode();
80         ScreenRecoveryUI::Init();
81     }
82 
SetupDisplayMode()83     void SetupDisplayMode() {
84         int fb_dev = open(kFBDevice, O_RDWR);
85         int res;
86         uint32_t i;
87         printf("opening fb %s\n", kFBDevice);
88         if (fb_dev < 0) {
89             fprintf(stderr, "FAIL: failed to open \"%s\" (errno = %d)\n", kFBDevice, errno);
90             return;
91         }
92 
93         struct fb_var_screeninfo current_mode;
94 
95         res = ioctl(fb_dev, FBIO_PSB_SET_RMODE, &current_mode);
96         if (res) {
97             fprintf(stderr,
98                 "FAIL: unable to set RGBX mode on display controller (errno = %d)\n",
99                 errno);
100             return;
101         }
102 
103         res = ioctl(fb_dev, FBIOGET_VSCREENINFO, &current_mode);
104         if (res) {
105             fprintf(stderr, "FAIL: unable to get mode, err %d\n", res);
106             return;
107         }
108 
109         res = ioctl(fb_dev, FBIOBLANK, FB_BLANK_POWERDOWN);
110         if (res) {
111             fprintf(stderr, "FAIL: unable to blank display, err %d\n", res);
112             return;
113         }
114 
115         current_mode.bits_per_pixel = 32;
116         current_mode.red.offset = 0;
117         current_mode.red.length = 8;
118         current_mode.green.offset = 8;
119         current_mode.green.length = 8;
120         current_mode.blue.offset = 16;
121         current_mode.blue.length = 8;
122 
123         res = ioctl(fb_dev, FBIOPUT_VSCREENINFO, &current_mode);
124         if (res) {
125             fprintf(stderr, "FAIL: unable to set mode, err %d\n", res);
126             return;
127         }
128 
129         /* set our display controller for RGBX */
130         res = ioctl(fb_dev, FBIO_PSB_SET_RGBX, &current_mode);
131         if (res) {
132             fprintf(stderr,
133                 "FAIL: unable to set RGBX mode on display controller (errno = %d)\n",
134                 errno);
135             return;
136         }
137 
138         res = ioctl(fb_dev, FBIOBLANK, FB_BLANK_UNBLANK);
139         if (res) {
140             fprintf(stderr, "FAIL: unable to unblank display, err %d\n", res);
141             return;
142         }
143     }
144 
SetBackground(Icon icon)145     void SetBackground(Icon icon) {
146         ScreenRecoveryUI::SetBackground(icon);
147 
148         background_mode = icon;
149     }
150 
SetColor(UIElement e)151     void SetColor(UIElement e) {
152         switch (e) {
153             case HEADER:
154                 gr_color(247, 0, 6, 255);
155                 break;
156             case MENU:
157                 gr_color(0, 106, 157, 255);
158                 break;
159             case MENU_SEL_BG:
160                 pthread_mutex_lock(&long_mu);
161                 if (pending_select) {
162                     gr_color(0, 156, 100, 255);
163                 } else {
164                     gr_color(0, 106, 157, 255);
165                 }
166                 pthread_mutex_unlock(&long_mu);
167                 break;
168             case MENU_SEL_FG:
169                 gr_color(255, 255, 255, 255);
170                 break;
171             case LOG:
172                 gr_color(249, 194, 0, 255);
173                 break;
174             case TEXT_FILL:
175                 gr_color(0, 0, 0, 160);
176                 break;
177             default:
178                 gr_color(255, 255, 255, 255);
179                 break;
180         }
181     }
182 
ShowText(bool visible)183     void ShowText(bool visible) {
184         ScreenRecoveryUI::ShowText(visible);
185 
186         text_ever_visible = text_ever_visible || visible;
187         text_visible = visible;
188     }
189 
IsTextVisible()190     bool IsTextVisible() {
191         return text_visible;
192     }
193 
WasTextEverVisible()194     bool WasTextEverVisible() {
195         return text_ever_visible;
196     }
197 
Print(const char * fmt,...)198     void Print(const char* fmt, ...) {
199         char buf[256];
200         va_list ap;
201         va_start(ap, fmt);
202         vsnprintf(buf, 256, fmt, ap);
203         va_end(ap);
204         ScreenRecoveryUI::Print("%s", buf);
205     }
206 
StartMenu(const char * const * headers,const char * const * items,int initial_selection)207     void StartMenu(const char* const * headers, const char* const * items,
208                    int initial_selection) {
209         ScreenRecoveryUI::StartMenu(headers, items, initial_selection);
210 
211         menu_items = 0;
212         for (const char* const * p = items; *p; ++p) {
213             ++menu_items;
214         }
215     }
216 
SelectMenu(int sel)217     int SelectMenu(int sel) {
218         if (sel < 0) {
219             sel += menu_items;
220         }
221         sel %= menu_items;
222         ScreenRecoveryUI::SelectMenu(sel);
223         return sel;
224     }
225 
NextCheckKeyIsLong(bool is_long_press)226     void NextCheckKeyIsLong(bool is_long_press) {
227         long_press = is_long_press;
228     }
229 
KeyLongPress(int key)230     void KeyLongPress(int key) {
231         pthread_mutex_lock(&long_mu);
232         pending_select = true;
233         pthread_mutex_unlock(&long_mu);
234 
235         Redraw();
236     }
237 
CheckKey(int key)238     KeyAction CheckKey(int key) {
239         pthread_mutex_lock(&long_mu);
240         pending_select = false;
241         pthread_mutex_unlock(&long_mu);
242 
243         if (key == KEY_F1) {
244             return MOUNT_SYSTEM;
245         }
246 
247         if (long_press) {
248             if (text_visible) {
249                 EnqueueKey(KEY_ENTER);
250                 return IGNORE;
251             } else {
252                 return TOGGLE;
253             }
254         } else {
255             return text_visible ? ENQUEUE : IGNORE;
256         }
257     }
258 
259 private:
260     static const int kKeyBufferSize = 100;
261 
262     int text_visible;
263     int text_ever_visible;
264 
265     Icon background_mode;
266 
267     int up_keys;
268     int next_key_pos;
269     int last_keys[kKeyBufferSize];
270 
271     int menu_items;
272 
273     pthread_mutex_t long_mu;
274     bool pending_select;
275 
276     bool long_press;
277 };
278 
279 class FuguDevice : public Device {
280   public:
FuguDevice()281     FuguDevice() :
282         ui(new FuguUI) {
283     }
284 
GetUI()285     RecoveryUI* GetUI() { return ui; }
286 
HandleMenuKey(int key,int visible)287     int HandleMenuKey(int key, int visible) {
288         static int running = 0;
289 
290         if (visible) {
291             switch (key) {
292                 case KEY_ENTER:
293                     return kInvokeItem;
294                     break;
295 
296                 case KEY_UP:
297                     return kHighlightUp;
298                     break;
299 
300                 case KEY_DOWN:
301                 case KEY_CONNECT:   // the Fugu hardware button
302                     return kHighlightDown;
303                     break;
304             }
305         }
306 
307         return kNoAction;
308     }
309 
InvokeMenuItem(int menu_position)310     BuiltinAction InvokeMenuItem(int menu_position) {
311         switch (menu_position) {
312           case 0: return REBOOT;
313           case 1: return APPLY_ADB_SIDELOAD;
314           case 2: return WIPE_DATA;
315           case 3: return WIPE_CACHE;
316           default: return NO_ACTION;
317         }
318     }
319 
GetMenuHeaders()320     const char* const* GetMenuHeaders() { return HEADERS; }
GetMenuItems()321     const char* const* GetMenuItems() { return ITEMS; }
322 
323   private:
324     RecoveryUI* ui;
325 };
326 
make_device()327 Device* make_device() {
328     return new FuguDevice();
329 }
330