void fbcon_putc(char c) { uint16_t *pixels; /* ignore anything that happens before fbcon is initialized */ if (!config) return; if((unsigned char)c > 127) return; if((unsigned char)c < 32) { if(c == '\n') goto newline; else if (c == '\r') cur_pos.x = 0; return; } #if DISPLAY_TYPE_TOUCHPAD fbcon_drawglyph_tp(cur_pos.x, cur_pos.y, font5x12 + (c - 32) * 2); cur_pos.x += FONT_WIDTH + 1; if (cur_pos.x <= max_pos.x) return; newline: cur_pos.y += FONT_HEIGHT; cur_pos.x = 0; if(cur_pos.y > max_pos.y) { cur_pos.y -= FONT_HEIGHT; fbcon_scroll_up(); } else fbcon_flush(); #else pixels = config->base; pixels += cur_pos.y * FONT_HEIGHT * config->width; pixels += cur_pos.x * (FONT_WIDTH + 1); fbcon_drawglyph(pixels, FGCOLOR, config->stride, font5x12 + (c - 32) * 2); cur_pos.x++; if (cur_pos.x < max_pos.x) return; newline: cur_pos.y++; cur_pos.x = 0; if(cur_pos.y >= max_pos.y) { cur_pos.y = max_pos.y - 1; fbcon_scroll_up(); } else fbcon_flush(); #endif }
/* TODO: Take stride into account */ static void fbcon_scroll_up(void) { #if DISPLAY_TYPE_TOUCHPAD for (unsigned y = 0; y <= max_pos.y - FONT_HEIGHT; y += FONT_HEIGHT) { memcpy (config->base + y * 1024*4, config->base + (y + FONT_HEIGHT) * 1024*4, 1024*4*FONT_HEIGHT); } for (unsigned y = max_pos.y; y < config->height; y++) { memset(config->base + y*1024*4, 0, 1024*4); } #else unsigned short *dst = config->base; unsigned short *src = dst + (config->width * FONT_HEIGHT); unsigned count = config->width * (config->height - FONT_HEIGHT); while(count--) { *dst++ = *src++; } count = config->width * FONT_HEIGHT; while(count--) { *dst++ = BGCOLOR; } #endif fbcon_flush(); }
void display_image_on_screen(void) { unsigned i = 0; unsigned total_x = config->width; unsigned total_y = config->height; unsigned bytes_per_bpp = ((config->bpp) / 8); unsigned image_base = ((((total_y/2) - (SPLASH_IMAGE_WIDTH / 2) - 1) * (config->width)) + (total_x/2 - (SPLASH_IMAGE_HEIGHT / 2))); fbcon_clear(); #if DISPLAY_TYPE_MIPI if (bytes_per_bpp == 3) { for (i = 0; i < SPLASH_IMAGE_WIDTH; i++) { memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp), imageBuffer_rgb888 + (i * SPLASH_IMAGE_HEIGHT * bytes_per_bpp), SPLASH_IMAGE_HEIGHT * bytes_per_bpp); } } fbcon_flush(); #if DISPLAY_MIPI_PANEL_NOVATEK_BLUE if(is_cmd_mode_enabled()) mipi_dsi_cmd_mode_trigger(); #endif #elif DISPLAY_TYPE_TOUCHPAD /* not supported yet */ return; #else if (bytes_per_bpp == 2) { for (i = 0; i < SPLASH_IMAGE_WIDTH; i++) { memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp), imageBuffer + (i * SPLASH_IMAGE_HEIGHT * bytes_per_bpp), SPLASH_IMAGE_HEIGHT * bytes_per_bpp); } } fbcon_flush(); #endif }
/** * Clear complete section on the screen. * The section is of section_height, and is located from the y * coordinate and down. */ static void fbcon_clear_section(uint32_t y, uint32_t section_height) { unsigned image_base; unsigned bytes_per_bpp; if (fb_config) { image_base = (y *(fb_config->width)); bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE); unsigned count = fb_config->width*section_height; memset(fb_config->base + image_base*bytes_per_bpp, RGB888_BLACK, count*bytes_per_bpp); fbcon_flush(); } else { dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n"); display_error_msg(); /* This will never return */ } }
/** * Put image at a specific (x,y) location on the screen. * Duplicated from fbcon.c, with modifications to allow (x,y) location (instead of a centered image), * and display bmp images properly (order of copying the lines to the screen was reversed) */ static void fbcon_putImage_in_location(struct mdtp_fbimage *fbimg, uint32_t x, uint32_t y) { unsigned i = 0; unsigned bytes_per_bpp; unsigned image_base; unsigned width, pitch, height; unsigned char *logo_base = NULL; if (!fb_config) { dprintf(CRITICAL,"ERROR: NULL configuration, image cannot be displayed\n"); return; } if(fbimg) { width = pitch = fbimg->width; height = fbimg->height; logo_base = (unsigned char *)fbimg->image; } else { dprintf(CRITICAL,"ERROR: invalid image struct\n"); return; } bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE); #if DISPLAY_TYPE_MIPI if (bytes_per_bpp == 3) { if (fbimg->width == fb_config->width && fbimg->height == fb_config->height) { dprintf(CRITICAL,"ERROR: full screen image, cannot be displayed\n"); return; } if (fbimg->width > fb_config->width || fbimg->height > fb_config->height || (x > (fb_config->width - fbimg->width)) || (y > (fb_config->height - fbimg->height))) { dprintf(CRITICAL,"ERROR: invalid image size, larger than the screen or exceeds its margins\n"); return; } image_base = ( (y *(fb_config->width)) + x); for (i = 0; i < height; i++) { memcpy (fb_config->base + ((image_base + (i * (fb_config->width))) * bytes_per_bpp), logo_base + ((height - 1 - i) * pitch * bytes_per_bpp), width * bytes_per_bpp); } } else { dprintf(CRITICAL,"ERROR: invalid bpp value\n"); display_error_msg(); /* This will never return */ } /* Flush the contents to memory before giving the data to dma */ arch_clean_invalidate_cache_range((addr_t) fb_config->base, (fb_config->height * fb_config->width * bytes_per_bpp)); fbcon_flush(); #if DISPLAY_MIPI_PANEL_NOVATEK_BLUE if(is_cmd_mode_enabled()) mipi_dsi_cmd_mode_trigger(); #endif #endif }
static void menu_renderer(int keycode) { int y = 1; unsigned i; int fh = pf2font_get_fontheight(); struct fbcon_config *config = fbcon_display(); // input handling if(!block_user) { // handle keypress if(keycode==KEY_RIGHT && menu_stack->entries[selection].execute) { menu_execute_entry(menu_stack->entries[selection].execute); return; } if(keycode==KEY_DOWN) { int first_visible = -1; int next_visible = -1; for(i=0; menu_stack->entries[i].name; i++) { if(!menu_stack->entries[i].hide || !menu_stack->entries[i].hide()) { if(first_visible==-1) first_visible = i; if(next_visible==-1 && i>selection) next_visible = i; } } if(next_visible!=-1) selection = next_visible; else selection=first_visible; } if(keycode==KEY_UP) { int last_visible = -1; int previous_visible = -1; for(i=0; menu_stack->entries[i].name; i++) { if(!menu_stack->entries[i].hide || !menu_stack->entries[i].hide()) { last_visible = i; if(i<selection) previous_visible = i; } } if(previous_visible!=-1) selection = previous_visible; else selection=last_visible; } } // clear fbcon_clear(); // title menu_set_color(NORMAL_TEXT_COLOR); pf2font_printf(0, fh*y++, "Fastboot Flash Mode (%s)", ABOOT_VERSION); // USB status if(usb_is_connected()) pf2font_printf(0, fh*y++, "Transfer Mode: USB Connected"); else pf2font_printf(0, fh*y++, "Connect USB Data Cable"); // device info char sn_buf[13]; target_serialno((unsigned char*)sn_buf); pf2font_printf(0, fh*y++, "CPU: %s Serial: %s", TARGET, sn_buf); #if WITH_DEV_PMIC_PM8921 // time unsigned long time; struct rtc_time tm; pm8xxx_rtc_read_time(&time); rtc_time_to_tm(time, &tm); pf2font_printf(0, fh*y++, "Time: %d-%02d-%02d %02d:%02d", tm.tm_year+1900, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min); #endif // divider 1 menu_set_color(DIVIDER_COLOR); menu_draw_divider(fh*y++ - pf2font_get_ascent()/2, 3); // draw interactive UI if(!block_user) { // menu header menu_set_color(NORMAL_TEXT_COLOR); pf2font_printf(0, fh*y++, "Boot Mode Selection Menu"); pf2font_printf(0, fh*y++, " Power Selects, Vol Up/Down Scrolls"); // menu entries for(i=0; menu_stack->entries[i].name; i++) { if(menu_stack->entries[i].hide && menu_stack->entries[i].hide()) continue; char* buf = NULL; if(menu_stack->entries[i].format) menu_stack->entries[i].format(&buf); else buf = strdup(menu_stack->entries[i].name); menu_draw_item(fh*y++, buf, selection==i); if(buf) free(buf); } // divider 2 menu_set_color(DIVIDER_COLOR); menu_draw_divider(fh*y++ - pf2font_get_ascent()/2, 3); } // draw log menu_set_color(LOG_COLOR_NORMAL); mutex_acquire(&logbuf_mutex); int log_top = y; int log_bottom = config->height/fh; int log_size = log_bottom-log_top; int start = (logbuf_row-log_size); for(i=(start>=0?start:0); i<=logbuf_row; i++) { pf2font_printf(0, fh*y++, logbuf[i]); } mutex_release(&logbuf_mutex); // flush fbcon_flush(); };