Merge commit 'remotes/korg/cupcake' into cupcake_to_master
This commit is contained in:
		
							
								
								
									
										12
									
								
								common.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								common.h
									
									
									
									
									
								
							| @@ -26,12 +26,24 @@ void ui_init(); | ||||
| int ui_wait_key();            // waits for a key/button press, returns the code | ||||
| int ui_key_pressed(int key);  // returns >0 if the code is currently pressed | ||||
| int ui_text_visible();        // returns >0 if text log is currently visible | ||||
| void ui_clear_key_queue(); | ||||
|  | ||||
| // Write a message to the on-screen log shown with Alt-L (also to stderr). | ||||
| // The screen is small, and users may need to report these messages to support, | ||||
| // so keep the output short and not too cryptic. | ||||
| void ui_print(const char *fmt, ...); | ||||
|  | ||||
| // Display some header text followed by a menu of items, which appears | ||||
| // at the top of the screen (in place of any scrolling ui_print() | ||||
| // output, if necessary). | ||||
| void ui_start_menu(char** headers, char** items); | ||||
| // Set the menu highlight to the given index, and return it (capped to | ||||
| // the range [0..numitems). | ||||
| int ui_menu_select(int sel); | ||||
| // End menu mode, resetting the text overlay so that ui_print() | ||||
| // statements will be displayed. | ||||
| void ui_end_menu(); | ||||
|  | ||||
| // Set the icon (normally the only thing visible besides the progress bar). | ||||
| enum { | ||||
|   BACKGROUND_ICON_NONE, | ||||
|   | ||||
| @@ -43,6 +43,7 @@ static GRFont *gr_font = 0; | ||||
| static GGLContext *gr_context = 0; | ||||
| static GGLSurface gr_font_texture; | ||||
| static GGLSurface gr_framebuffer[2]; | ||||
| static GGLSurface gr_mem_surface; | ||||
| static unsigned gr_active_fb = 0; | ||||
|  | ||||
| static int gr_fb_fd = -1; | ||||
| @@ -55,7 +56,7 @@ static int get_framebuffer(GGLSurface *fb) | ||||
|     int fd; | ||||
|     struct fb_fix_screeninfo fi; | ||||
|     void *bits; | ||||
|      | ||||
|  | ||||
|     fd = open("/dev/graphics/fb0", O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         perror("cannot open fb0"); | ||||
| @@ -87,9 +88,9 @@ static int get_framebuffer(GGLSurface *fb) | ||||
|     fb->stride = vi.xres; | ||||
|     fb->data = bits; | ||||
|     fb->format = GGL_PIXEL_FORMAT_RGB_565; | ||||
|      | ||||
|  | ||||
|     fb++; | ||||
|      | ||||
|  | ||||
|     fb->version = sizeof(*fb); | ||||
|     fb->width = vi.xres; | ||||
|     fb->height = vi.yres; | ||||
| @@ -100,6 +101,15 @@ static int get_framebuffer(GGLSurface *fb) | ||||
|     return fd; | ||||
| } | ||||
|  | ||||
| static void get_memory_surface(GGLSurface* ms) { | ||||
|   ms->version = sizeof(*ms); | ||||
|   ms->width = vi.xres; | ||||
|   ms->height = vi.yres; | ||||
|   ms->stride = vi.xres; | ||||
|   ms->data = malloc(vi.xres * vi.yres * 2); | ||||
|   ms->format = GGL_PIXEL_FORMAT_RGB_565; | ||||
| } | ||||
|  | ||||
| static void set_active_framebuffer(unsigned n) | ||||
| { | ||||
|     if (n > 1) return; | ||||
| @@ -113,14 +123,16 @@ static void set_active_framebuffer(unsigned n) | ||||
| void gr_flip(void) | ||||
| { | ||||
|     GGLContext *gl = gr_context; | ||||
|      | ||||
|         /* currently active buffer becomes the backbuffer */ | ||||
|     gl->colorBuffer(gl, gr_framebuffer + gr_active_fb); | ||||
|  | ||||
|         /* swap front and back buffers */ | ||||
|     /* swap front and back buffers */ | ||||
|     gr_active_fb = (gr_active_fb + 1) & 1; | ||||
|  | ||||
|         /* inform the display driver */ | ||||
|     /* copy data from the in-memory surface to the buffer we're about | ||||
|      * to make active. */ | ||||
|     memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data, | ||||
|            vi.xres * vi.yres * 2); | ||||
|  | ||||
|     /* inform the display driver */ | ||||
|     set_active_framebuffer(gr_active_fb); | ||||
| } | ||||
|  | ||||
| @@ -147,13 +159,13 @@ int gr_text(int x, int y, const char *s) | ||||
|     unsigned off; | ||||
|  | ||||
|     y -= font->ascent; | ||||
|    | ||||
|  | ||||
|     gl->bindTexture(gl, &font->texture); | ||||
|     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE); | ||||
|     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); | ||||
|     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); | ||||
|     gl->enable(gl, GGL_TEXTURE_2D); | ||||
|      | ||||
|  | ||||
|     while((off = *s++)) { | ||||
|         off -= 32; | ||||
|         if (off < 96) { | ||||
| @@ -209,10 +221,10 @@ static void gr_init_font(void) | ||||
|     unsigned char *in, data; | ||||
|  | ||||
|     gr_font = calloc(sizeof(*gr_font), 1); | ||||
|     ftex = &gr_font->texture;  | ||||
|     ftex = &gr_font->texture; | ||||
|  | ||||
|     bits = malloc(font.width * font.height); | ||||
|      | ||||
|  | ||||
|     ftex->version = sizeof(*ftex); | ||||
|     ftex->width = font.width; | ||||
|     ftex->height = font.height; | ||||
| @@ -225,7 +237,7 @@ static void gr_init_font(void) | ||||
|         memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); | ||||
|         bits += (data & 0x7f); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     gr_font->cwidth = font.cwidth; | ||||
|     gr_font->cheight = font.cheight; | ||||
|     gr_font->ascent = font.cheight - 2; | ||||
| @@ -254,13 +266,16 @@ int gr_init(void) | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     get_memory_surface(&gr_mem_surface); | ||||
|  | ||||
|     fprintf(stderr, "framebuffer: fd %d (%d x %d)\n", | ||||
|             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); | ||||
|  | ||||
|         /* start with 0 as front (displayed) and 1 as back (drawing) */ | ||||
|     gr_active_fb = 0; | ||||
|     set_active_framebuffer(0); | ||||
|     gl->colorBuffer(gl, gr_framebuffer + 1); | ||||
|     gl->colorBuffer(gl, &gr_mem_surface); | ||||
|  | ||||
|  | ||||
|     gl->activeTexture(gl, 0); | ||||
|     gl->enable(gl, GGL_BLEND); | ||||
| @@ -273,7 +288,9 @@ void gr_exit(void) | ||||
| { | ||||
|     close(gr_fb_fd); | ||||
|     gr_fb_fd = -1; | ||||
|      | ||||
|  | ||||
|     free(gr_mem_surface.data); | ||||
|  | ||||
|     ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); | ||||
|     close(gr_vt_fd); | ||||
|     gr_vt_fd = -1; | ||||
| @@ -291,5 +308,5 @@ int gr_fb_height(void) | ||||
|  | ||||
| gr_pixel *gr_fb_data(void) | ||||
| { | ||||
|     return (unsigned short *) gr_framebuffer[1 - gr_active_fb].data; | ||||
|     return (unsigned short *) gr_mem_surface.data; | ||||
| } | ||||
|   | ||||
							
								
								
									
										99
									
								
								recovery.c
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								recovery.c
									
									
									
									
									
								
							| @@ -291,17 +291,32 @@ erase_root(const char *root) | ||||
| static void | ||||
| prompt_and_wait() | ||||
| { | ||||
|     ui_print("\n" | ||||
|         "Home+Back - reboot system now\n" | ||||
|         "Alt+L - toggle log text display\n" | ||||
|         "Alt+S - apply sdcard:update.zip\n" | ||||
|         "Alt+W - wipe data/factory reset\n"); | ||||
|     char* headers[] = { "Android system recovery utility", | ||||
|                         "", | ||||
|                         "Use trackball to highlight;", | ||||
|                         "click to select.", | ||||
|                         "", | ||||
|                         NULL }; | ||||
|  | ||||
|     // these constants correspond to elements of the items[] list. | ||||
| #define ITEM_REBOOT        0 | ||||
| #define ITEM_APPLY_SDCARD  1 | ||||
| #define ITEM_WIPE_DATA     2 | ||||
|     char* items[] = { "reboot system now [Home+Back]", | ||||
|                       "apply sdcard:update.zip [Alt+S]", | ||||
|                       "wipe data/factory reset [Alt+W]", | ||||
|                       NULL }; | ||||
|  | ||||
|     ui_start_menu(headers, items); | ||||
|     int selected = 0; | ||||
|     int chosen_item = -1; | ||||
|  | ||||
|     finish_recovery(NULL); | ||||
|     ui_reset_progress(); | ||||
|     for (;;) { | ||||
|         finish_recovery(NULL); | ||||
|         ui_reset_progress(); | ||||
|         int key = ui_wait_key(); | ||||
|         int alt = ui_key_pressed(KEY_LEFTALT) || ui_key_pressed(KEY_RIGHTALT); | ||||
|         int visible = ui_text_visible(); | ||||
|  | ||||
|         if (key == KEY_DREAM_BACK && ui_key_pressed(KEY_DREAM_HOME)) { | ||||
|             // Wait for the keys to be released, to avoid triggering | ||||
| @@ -310,23 +325,64 @@ prompt_and_wait() | ||||
|                    ui_key_pressed(KEY_DREAM_HOME)) { | ||||
|                 usleep(1000); | ||||
|             } | ||||
|             break; | ||||
|             chosen_item = ITEM_REBOOT; | ||||
|         } else if (alt && key == KEY_W) { | ||||
|             ui_print("\n"); | ||||
|             erase_root("DATA:"); | ||||
|             erase_root("CACHE:"); | ||||
|             ui_print("Data wipe complete.\n"); | ||||
|             if (!ui_text_visible()) break; | ||||
|             chosen_item = ITEM_WIPE_DATA; | ||||
|         } else if (alt && key == KEY_S) { | ||||
|             ui_print("\nInstalling from sdcard...\n"); | ||||
|             int status = install_package(SDCARD_PACKAGE_FILE); | ||||
|             if (status != INSTALL_SUCCESS) { | ||||
|                 ui_set_background(BACKGROUND_ICON_ERROR); | ||||
|                 ui_print("Installation aborted.\n"); | ||||
|             } else if (!ui_text_visible()) { | ||||
|                 break;  // reboot if logs aren't visible | ||||
|             chosen_item = ITEM_APPLY_SDCARD; | ||||
|         } else if ((key == KEY_DOWN || key == KEY_VOLUMEDOWN) && visible) { | ||||
|             ++selected; | ||||
|             selected = ui_menu_select(selected); | ||||
|         } else if ((key == KEY_UP || key == KEY_VOLUMEUP) && visible) { | ||||
|             --selected; | ||||
|             selected = ui_menu_select(selected); | ||||
|         } else if (key == BTN_MOUSE && visible) { | ||||
|             chosen_item = selected; | ||||
|         } | ||||
|  | ||||
|         if (chosen_item >= 0) { | ||||
|             // turn off the menu, letting ui_print() to scroll output | ||||
|             // on the screen. | ||||
|             ui_end_menu(); | ||||
|  | ||||
|             switch (chosen_item) { | ||||
|                 case ITEM_REBOOT: | ||||
|                     return; | ||||
|  | ||||
|                 case ITEM_WIPE_DATA: | ||||
|                     ui_print("\n-- Wiping data...\n"); | ||||
|                     erase_root("DATA:"); | ||||
|                     erase_root("CACHE:"); | ||||
|                     ui_print("Data wipe complete.\n"); | ||||
|                     if (!ui_text_visible()) return; | ||||
|                     break; | ||||
|  | ||||
|                 case ITEM_APPLY_SDCARD: | ||||
|                     ui_print("\n-- Install from sdcard...\n"); | ||||
|                     int status = install_package(SDCARD_PACKAGE_FILE); | ||||
|                     if (status != INSTALL_SUCCESS) { | ||||
|                         ui_set_background(BACKGROUND_ICON_ERROR); | ||||
|                         ui_print("Installation aborted.\n"); | ||||
|                     } else if (!ui_text_visible()) { | ||||
|                         return;  // reboot if logs aren't visible | ||||
|                     } else { | ||||
|                       ui_print("Install from sdcard complete.\n"); | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|             ui_print("\nPress Home+Back to reboot\n"); | ||||
|  | ||||
|             // if we didn't return from this function to reboot, show | ||||
|             // the menu again. | ||||
|             ui_start_menu(headers, items); | ||||
|             selected = 0; | ||||
|             chosen_item = -1; | ||||
|  | ||||
|             finish_recovery(NULL); | ||||
|             ui_reset_progress(); | ||||
|  | ||||
|             // throw away keys pressed while the command was running, | ||||
|             // so user doesn't accidentally trigger menu items. | ||||
|             ui_clear_key_queue(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -348,7 +404,6 @@ main(int argc, char **argv) | ||||
|     fprintf(stderr, "Starting recovery on %s", ctime(&start)); | ||||
|  | ||||
|     ui_init(); | ||||
|     ui_print("Android system recovery utility\n"); | ||||
|     get_args(&argc, &argv); | ||||
|  | ||||
|     int previous_runs = 0; | ||||
|   | ||||
							
								
								
									
										140
									
								
								ui.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								ui.c
									
									
									
									
									
								
							| @@ -89,6 +89,10 @@ static int text_cols = 0, text_rows = 0; | ||||
| static int text_col = 0, text_row = 0, text_top = 0; | ||||
| static int show_text = 0; | ||||
|  | ||||
| static char menu[MAX_ROWS][MAX_COLS]; | ||||
| static int show_menu = 0; | ||||
| static int menu_top = 0, menu_items = 0, menu_sel = 0; | ||||
|  | ||||
| // Key event input queue | ||||
| static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
| static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER; | ||||
| @@ -154,6 +158,12 @@ static void draw_progress_locked() | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void draw_text_line(int row, const char* t) { | ||||
|   if (t[0] != '\0') { | ||||
|     gr_text(0, (row+1)*CHAR_HEIGHT-1, t); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Redraw everything on the screen.  Does not flip pages. | ||||
| // Should only be called with gUpdateMutex locked. | ||||
| static void draw_screen_locked(void) | ||||
| @@ -163,13 +173,32 @@ static void draw_screen_locked(void) | ||||
|  | ||||
|     if (show_text) { | ||||
|         gr_color(0, 0, 0, 160); | ||||
|         gr_fill(0, 0, gr_fb_width(), text_rows * CHAR_HEIGHT); | ||||
|         gr_fill(0, 0, gr_fb_width(), gr_fb_height()); | ||||
|  | ||||
|         int i = 0; | ||||
|         if (show_menu) { | ||||
|             gr_color(64, 96, 255, 255); | ||||
|             gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT, | ||||
|                     gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1); | ||||
|  | ||||
|             for (; i < menu_top + menu_items; ++i) { | ||||
|                 if (i == menu_top + menu_sel) { | ||||
|                     gr_color(255, 255, 255, 255); | ||||
|                     draw_text_line(i, menu[i]); | ||||
|                     gr_color(64, 96, 255, 255); | ||||
|                 } else { | ||||
|                     draw_text_line(i, menu[i]); | ||||
|                 } | ||||
|             } | ||||
|             gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1, | ||||
|                     gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1); | ||||
|             ++i; | ||||
|         } | ||||
|  | ||||
|         gr_color(255, 255, 0, 255); | ||||
|         int i; | ||||
|         for (i = 0; i < text_rows; ++i) { | ||||
|             const char* line = text[(i + text_top) % text_rows]; | ||||
|             if (line[0] != '\0') gr_text(0, (i + 1) * CHAR_HEIGHT - 1, line); | ||||
|  | ||||
|         for (; i < text_rows; ++i) { | ||||
|             draw_text_line(i, text[(i+text_top) % text_rows]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -228,13 +257,50 @@ static void *progress_thread(void *cookie) | ||||
| // Reads input events, handles special hot keys, and adds to the key queue. | ||||
| static void *input_thread(void *cookie) | ||||
| { | ||||
|     int rel_sum = 0; | ||||
|     int fake_key = 0; | ||||
|     for (;;) { | ||||
|         // wait for the next key event | ||||
|         struct input_event ev; | ||||
|         do { ev_get(&ev, 0); } while (ev.type != EV_KEY || ev.code > KEY_MAX); | ||||
|         do { | ||||
|             ev_get(&ev, 0); | ||||
|  | ||||
|             if (ev.type == EV_SYN) { | ||||
|                 continue; | ||||
|             } else if (ev.type == EV_REL) { | ||||
|                 if (ev.code == REL_Y) { | ||||
|                     // accumulate the up or down motion reported by | ||||
|                     // the trackball.  When it exceeds a threshold | ||||
|                     // (positive or negative), fake an up/down | ||||
|                     // key event. | ||||
|                     rel_sum += ev.value; | ||||
|                     if (rel_sum > 3) { | ||||
|                         fake_key = 1; | ||||
|                         ev.type = EV_KEY; | ||||
|                         ev.code = KEY_DOWN; | ||||
|                         ev.value = 1; | ||||
|                         rel_sum = 0; | ||||
|                     } else if (rel_sum < -3) { | ||||
|                         fake_key = 1; | ||||
|                         ev.type = EV_KEY; | ||||
|                         ev.code = KEY_UP; | ||||
|                         ev.value = 1; | ||||
|                         rel_sum = 0; | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 rel_sum = 0; | ||||
|             } | ||||
|         } while (ev.type != EV_KEY || ev.code > KEY_MAX); | ||||
|  | ||||
|         pthread_mutex_lock(&key_queue_mutex); | ||||
|         key_pressed[ev.code] = ev.value; | ||||
|         if (!fake_key) { | ||||
|             // our "fake" keys only report a key-down event (no | ||||
|             // key-up), so don't record them in the key_pressed | ||||
|             // table. | ||||
|             key_pressed[ev.code] = ev.value; | ||||
|         } | ||||
|         fake_key = 0; | ||||
|         const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]); | ||||
|         if (ev.value > 0 && key_queue_len < queue_max) { | ||||
|             key_queue[key_queue_len++] = ev.code; | ||||
| @@ -242,9 +308,10 @@ static void *input_thread(void *cookie) | ||||
|         } | ||||
|         pthread_mutex_unlock(&key_queue_mutex); | ||||
|  | ||||
|         // Alt+L: toggle log display | ||||
|         // Alt+L or Home+End: toggle log display | ||||
|         int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT]; | ||||
|         if (alt && ev.code == KEY_L && ev.value > 0) { | ||||
|         if ((alt && ev.code == KEY_L && ev.value > 0) || | ||||
|             (key_pressed[KEY_HOME] && ev.code == KEY_END && ev.value > 0)) { | ||||
|             pthread_mutex_lock(&gUpdateMutex); | ||||
|             show_text = !show_text; | ||||
|             update_screen_locked(); | ||||
| @@ -269,6 +336,7 @@ void ui_init(void) | ||||
|     text_col = text_row = 0; | ||||
|     text_rows = gr_fb_height() / CHAR_HEIGHT; | ||||
|     if (text_rows > MAX_ROWS) text_rows = MAX_ROWS; | ||||
|     text_top = 1; | ||||
|  | ||||
|     text_cols = gr_fb_width() / CHAR_WIDTH; | ||||
|     if (text_cols > MAX_COLS - 1) text_cols = MAX_COLS - 1; | ||||
| @@ -392,6 +460,54 @@ void ui_print(const char *fmt, ...) | ||||
|     pthread_mutex_unlock(&gUpdateMutex); | ||||
| } | ||||
|  | ||||
| void ui_start_menu(char** headers, char** items) { | ||||
|     int i; | ||||
|     pthread_mutex_lock(&gUpdateMutex); | ||||
|     if (text_rows > 0 && text_cols > 0) { | ||||
|         for (i = 0; i < text_rows; ++i) { | ||||
|             if (headers[i] == NULL) break; | ||||
|             strncpy(menu[i], headers[i], text_cols-1); | ||||
|             menu[i][text_cols-1] = '\0'; | ||||
|         } | ||||
|         menu_top = i; | ||||
|         for (; i < text_rows; ++i) { | ||||
|             if (items[i-menu_top] == NULL) break; | ||||
|             strncpy(menu[i], items[i-menu_top], text_cols-1); | ||||
|             menu[i][text_cols-1] = '\0'; | ||||
|         } | ||||
|         menu_items = i - menu_top; | ||||
|         show_menu = 1; | ||||
|         menu_sel = 0; | ||||
|         update_screen_locked(); | ||||
|     } | ||||
|     pthread_mutex_unlock(&gUpdateMutex); | ||||
| } | ||||
|  | ||||
| int ui_menu_select(int sel) { | ||||
|     int old_sel; | ||||
|     pthread_mutex_lock(&gUpdateMutex); | ||||
|     if (show_menu > 0) { | ||||
|         old_sel = menu_sel; | ||||
|         menu_sel = sel; | ||||
|         if (menu_sel < 0) menu_sel = 0; | ||||
|         if (menu_sel >= menu_items) menu_sel = menu_items-1; | ||||
|         sel = menu_sel; | ||||
|         if (menu_sel != old_sel) update_screen_locked(); | ||||
|     } | ||||
|     pthread_mutex_unlock(&gUpdateMutex); | ||||
|     return sel; | ||||
| } | ||||
|  | ||||
| void ui_end_menu() { | ||||
|     int i; | ||||
|     pthread_mutex_lock(&gUpdateMutex); | ||||
|     if (show_menu > 0 && text_rows > 0 && text_cols > 0) { | ||||
|         show_menu = 0; | ||||
|         update_screen_locked(); | ||||
|     } | ||||
|     pthread_mutex_unlock(&gUpdateMutex); | ||||
| } | ||||
|  | ||||
| int ui_text_visible() | ||||
| { | ||||
|     pthread_mutex_lock(&gUpdateMutex); | ||||
| @@ -418,3 +534,9 @@ int ui_key_pressed(int key) | ||||
|     // This is a volatile static array, don't bother locking | ||||
|     return key_pressed[key]; | ||||
| } | ||||
|  | ||||
| void ui_clear_key_queue() { | ||||
|     pthread_mutex_lock(&key_queue_mutex); | ||||
|     key_queue_len = 0; | ||||
|     pthread_mutex_unlock(&key_queue_mutex); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user