609 lines
17 KiB
C
609 lines
17 KiB
C
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* * Neither the name of The Linux Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <debug.h>
|
|
#include <dev/fbcon.h>
|
|
#include <target.h>
|
|
#include <mmc.h>
|
|
#include <partition_parser.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "mdtp.h"
|
|
#include "mdtp_defs.h"
|
|
|
|
// Image releative locations
|
|
#define ERROR_MESSAGE_RELATIVE_Y_LOCATION (0.18)
|
|
#define MAIN_TEXT_RELATIVE_Y_LOCATION (0.33)
|
|
#define PIN_RELATIVE_Y_LOCATION (0.47)
|
|
#define PIN_TEXT_RELATIVE_Y_LOCATION (0.57)
|
|
#define OK_BUTTON_RELATIVE_Y_LOCATION (0.75)
|
|
#define OK_TEXT_RELATIVE_Y_LOCATION (0.82)
|
|
|
|
#define MDTP_PRESSING_DELAY_MSEC (400)
|
|
#define MDTP_MAX_IMAGE_SIZE (1183000) //size in bytes, includes some extra bytes since we round up to block size in read
|
|
#define RGB888_BLACK (0x000000)
|
|
#define BITS_PER_BYTE (8)
|
|
|
|
|
|
#define CENTER_IMAGE_ON_X_AXIS(image_width,screen_width) (((screen_width)-(image_width))/2)
|
|
|
|
extern void mdelay(unsigned msecs);
|
|
extern uint32_t target_volume_up();
|
|
extern uint32_t target_volume_down();
|
|
|
|
struct mdtp_fbimage {
|
|
uint32_t width;
|
|
uint32_t height;
|
|
uint8_t image[MDTP_MAX_IMAGE_SIZE];
|
|
};
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Global Variables
|
|
* -------------------------------------------------------------------------*/
|
|
|
|
static uint32_t g_pin_frames_x_location[MDTP_MAX_PIN_LEN] = {0};
|
|
static uint32_t g_pin_frames_y_location = 0;
|
|
|
|
static bool g_initial_screen_displayed = false;
|
|
|
|
static struct mdtp_fbimage *g_mdtp_header = NULL;
|
|
static struct fbcon_config *fb_config = NULL;
|
|
|
|
struct mdtp_ui_defs mdtp_ui_defs_data;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Local Functions
|
|
* -------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Allocate mdtp image
|
|
*/
|
|
static void alloc_mdtp_image() {
|
|
if (!g_mdtp_header) {
|
|
g_mdtp_header = (struct mdtp_fbimage *)malloc(sizeof(struct mdtp_fbimage));
|
|
ASSERT(g_mdtp_header);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free mdtp image
|
|
*/
|
|
void free_mdtp_image() {
|
|
if (g_mdtp_header) {
|
|
free(g_mdtp_header);
|
|
g_mdtp_header = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load images from EMMC
|
|
*/
|
|
static struct mdtp_fbimage* mdtp_read_mmc_image(uint32_t offset, uint32_t width, uint32_t height)
|
|
{
|
|
int index = INVALID_PTN;
|
|
unsigned long long ptn = 0;
|
|
struct mdtp_fbimage *logo = g_mdtp_header;
|
|
uint32_t block_size = mmc_get_device_blocksize();
|
|
|
|
index = partition_get_index("mdtp");
|
|
if (index == 0) {
|
|
dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
|
|
return NULL;
|
|
}
|
|
|
|
ptn = partition_get_offset(index);
|
|
if (ptn == 0) {
|
|
dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (fb_config)
|
|
{
|
|
uint8_t *base = logo->image;
|
|
unsigned bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE);
|
|
|
|
if (mmc_read(ptn+offset, (void*)base, ROUNDUP(width*height*bytes_per_bpp, block_size))) {
|
|
fbcon_clear();
|
|
dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
logo->width = width;
|
|
logo->height = height;
|
|
}
|
|
|
|
return logo;
|
|
}
|
|
|
|
/**
|
|
* flush fbcon display
|
|
*
|
|
* The function is duplicated from fbcon.c
|
|
*/
|
|
static void fbcon_flush(void)
|
|
{
|
|
if (fb_config->update_start)
|
|
fb_config->update_start();
|
|
if (fb_config->update_done)
|
|
while (!fb_config->update_done());
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
}
|
|
|
|
/**
|
|
* Display main error message
|
|
*/
|
|
static int display_error_message()
|
|
{
|
|
struct mdtp_fbimage *fbimg;
|
|
|
|
if (fb_config)
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.error_msg_width,fb_config->width);
|
|
uint32_t y = ((fb_config->height)*ERROR_MESSAGE_RELATIVE_Y_LOCATION);
|
|
|
|
fbimg = mdtp_read_mmc_image(mdtp_ui_defs_data.error_msg_offset, mdtp_ui_defs_data.error_msg_width, mdtp_ui_defs_data.error_msg_height);
|
|
if (NULL == fbimg)
|
|
{
|
|
dprintf(CRITICAL,"ERROR: failed to read error image from mmc\n");
|
|
return -1;
|
|
}
|
|
|
|
fbcon_putImage_in_location(fbimg, x, y);
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read from mmc the image in the given offset, of the given width and height.
|
|
* Then, display the image on the screen in the given (x,y) location.
|
|
*/
|
|
static void display_image(uint32_t offset, uint32_t width, uint32_t height, uint32_t x, uint32_t y)
|
|
{
|
|
struct mdtp_fbimage *fbimg;
|
|
|
|
if (fb_config)
|
|
{
|
|
fbimg = mdtp_read_mmc_image(offset, width, height);
|
|
if (NULL == fbimg)
|
|
{
|
|
dprintf(CRITICAL,"ERROR: failed to read image from mmc\n");
|
|
display_error_msg(); /* This will never return */
|
|
}
|
|
|
|
fbcon_putImage_in_location(fbimg, x, y);
|
|
}
|
|
else
|
|
{
|
|
dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
|
|
display_error_msg(); /* This will never return */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display initial delay message
|
|
*/
|
|
static void display_initial_delay()
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.main_text_width,fb_config->width);
|
|
uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.initial_delay_offset, mdtp_ui_defs_data.main_text_width, mdtp_ui_defs_data.main_text_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Display "enter PIN" message
|
|
*/
|
|
static void display_enter_pin()
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.main_text_width,fb_config->width);
|
|
uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.enter_pin_offset, mdtp_ui_defs_data.main_text_width, mdtp_ui_defs_data.main_text_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Display invalid PIN message
|
|
*/
|
|
static void display_invalid_pin()
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.main_text_width,fb_config->width);
|
|
uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.invalid_pin_offset, mdtp_ui_defs_data.main_text_width, mdtp_ui_defs_data.main_text_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Clear digits instructions
|
|
*/
|
|
static void display_digits_instructions()
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.digits_instructions_width,fb_config->width);
|
|
uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.digits_instructions_offset, mdtp_ui_defs_data.digits_instructions_width, mdtp_ui_defs_data.digits_instructions_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Clear digits instructions
|
|
*/
|
|
static void clear_digits_instructions()
|
|
{
|
|
uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
fbcon_clear_section(y, mdtp_ui_defs_data.digits_instructions_height);
|
|
}
|
|
|
|
/**
|
|
* Display a digit as un-selected.
|
|
*/
|
|
static void display_digit(uint32_t x, uint32_t y, uint32_t digit)
|
|
{
|
|
display_image(mdtp_ui_defs_data.pin_digit_0_offset + digit*mdtp_ui_defs_data.pin_digits_offset,
|
|
mdtp_ui_defs_data.pin_digit_width, mdtp_ui_defs_data.pin_digit_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Display a digit as selected.
|
|
*/
|
|
static void display_selected_digit(uint32_t x, uint32_t y, uint32_t digit)
|
|
{
|
|
display_image(mdtp_ui_defs_data.pin_selected_digit_0_offset + digit*mdtp_ui_defs_data.pin_digits_offset,
|
|
mdtp_ui_defs_data.pin_digit_width, mdtp_ui_defs_data.pin_digit_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Display OK button as un-selected.
|
|
*/
|
|
static void display_ok_button()
|
|
{
|
|
uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.ok_button_width,fb_config->width);
|
|
uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.ok_button_offset, mdtp_ui_defs_data.ok_button_width, mdtp_ui_defs_data.ok_button_height, ok_x, ok_y);
|
|
}
|
|
|
|
/**
|
|
* Display OK button as selected.
|
|
*/
|
|
static void display_selected_ok_button()
|
|
{
|
|
uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.ok_button_width,fb_config->width);
|
|
uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.selected_ok_button_offset, mdtp_ui_defs_data.ok_button_width, mdtp_ui_defs_data.ok_button_height, ok_x, ok_y);
|
|
}
|
|
|
|
/**
|
|
* Display the instructions for the OK button.
|
|
*/
|
|
static void display_pin_instructions()
|
|
{
|
|
uint32_t x = CENTER_IMAGE_ON_X_AXIS(mdtp_ui_defs_data.pin_instructions_width,fb_config->width);
|
|
uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
display_image(mdtp_ui_defs_data.pin_instructions_offset, mdtp_ui_defs_data.pin_instructions_width, mdtp_ui_defs_data.pin_instructions_height, x, y);
|
|
}
|
|
|
|
/**
|
|
* Clear the instructions for the OK button.
|
|
*/
|
|
static void clear_pin_message()
|
|
{
|
|
uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
|
|
|
|
fbcon_clear_section(y, mdtp_ui_defs_data.pin_instructions_height);
|
|
}
|
|
|
|
/**
|
|
* Initialize data structures required for MDTP UI.
|
|
*/
|
|
static void init_mdtp_ui_data()
|
|
{
|
|
fb_config = fbcon_display();
|
|
alloc_mdtp_image();
|
|
mdtp_ui_defs_data = mdtp_get_target_ui_defs();
|
|
}
|
|
|
|
/**
|
|
* Display the basic layout of the screen (done only once).
|
|
*/
|
|
static void display_initial_screen(uint32_t pin_length)
|
|
{
|
|
if (g_initial_screen_displayed == true)
|
|
return;
|
|
|
|
init_mdtp_ui_data();
|
|
|
|
if (fb_config)
|
|
{
|
|
fbcon_clear();
|
|
|
|
if (display_error_message())
|
|
display_error_msg(); /* This will never return */
|
|
display_initial_delay();
|
|
|
|
mdelay(INITIAL_DELAY_MSECONDS);
|
|
|
|
g_pin_frames_y_location = ((fb_config->height)*PIN_RELATIVE_Y_LOCATION);
|
|
|
|
uint32_t total_pin_length = pin_length*mdtp_ui_defs_data.pin_digit_width + mdtp_ui_defs_data.digit_space*(pin_length - 1);
|
|
uint32_t complete_pin_centered = (fb_config->width - total_pin_length)/2;
|
|
|
|
for (uint32_t i=0; i<pin_length; i++)
|
|
{
|
|
g_pin_frames_x_location[i] = complete_pin_centered + i*(mdtp_ui_defs_data.digit_space+mdtp_ui_defs_data.pin_digit_width);
|
|
}
|
|
|
|
for (uint32_t i=0; i<pin_length; i++)
|
|
{
|
|
display_digit(g_pin_frames_x_location[i], g_pin_frames_y_location, 0);
|
|
}
|
|
|
|
display_ok_button();
|
|
|
|
g_initial_screen_displayed = true;
|
|
}
|
|
else
|
|
{
|
|
dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
|
|
display_error_msg(); /* This will never return */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the recovery PIN screen and set received buffer
|
|
* with the PIN the user has entered.
|
|
* The entered PIN will be validated by the calling function.
|
|
*/
|
|
static void display_get_pin_interface(char *entered_pin, uint32_t pin_length)
|
|
{
|
|
uint32_t previous_position = 0, current_position = 0;
|
|
|
|
display_initial_screen(pin_length);
|
|
display_enter_pin();
|
|
|
|
// Convert ascii to digits
|
|
for (uint32_t i=0; i<pin_length; i++)
|
|
{
|
|
entered_pin[i] -= '0';
|
|
}
|
|
display_selected_digit(g_pin_frames_x_location[0], g_pin_frames_y_location, entered_pin[0]);
|
|
display_digits_instructions();
|
|
|
|
while (1)
|
|
{
|
|
if (target_volume_up())
|
|
{
|
|
// current position is the OK button
|
|
if (current_position == pin_length)
|
|
{
|
|
// Convert digits to ascii and
|
|
// validate entered PIN in the calling function
|
|
for (uint32_t i=0; i<pin_length; i++)
|
|
{
|
|
entered_pin[i] += '0';
|
|
}
|
|
return;
|
|
}
|
|
|
|
// current position is a PIN slot
|
|
entered_pin[current_position] = (entered_pin[current_position]+1) % 10;
|
|
display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
|
|
mdelay(MDTP_PRESSING_DELAY_MSEC);
|
|
}
|
|
if (target_volume_down())
|
|
{
|
|
previous_position = current_position;
|
|
current_position = (current_position+1) % (pin_length+1);
|
|
|
|
// previous position was the OK button
|
|
if (previous_position == pin_length)
|
|
{
|
|
clear_pin_message();
|
|
display_ok_button();
|
|
|
|
display_digits_instructions();
|
|
display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
|
|
|
|
}
|
|
|
|
// current position is the OK button
|
|
else if (current_position == pin_length)
|
|
{
|
|
display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
|
|
clear_digits_instructions();
|
|
|
|
display_selected_ok_button();
|
|
display_pin_instructions();
|
|
}
|
|
|
|
// both the previous and the current positions are PIN slots
|
|
else
|
|
{
|
|
display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
|
|
|
|
display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
|
|
}
|
|
|
|
mdelay(MDTP_PRESSING_DELAY_MSEC);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* External Functions
|
|
* -------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Display the recovery PIN screen and set received buffer
|
|
* with the PIN the user has entered.
|
|
*/
|
|
void get_pin_from_user(char *entered_pin, uint32_t pin_length)
|
|
{
|
|
display_get_pin_interface(entered_pin, pin_length);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* User has entered invalid PIN, display error message and
|
|
* allow the user to try again.
|
|
*/
|
|
void display_invalid_pin_msg()
|
|
{
|
|
clear_pin_message();
|
|
display_ok_button();
|
|
|
|
display_invalid_pin();
|
|
|
|
mdelay(INVALID_PIN_DELAY_MSECONDS);
|
|
}
|
|
|
|
/**
|
|
* Display error message and stop boot process.
|
|
*/
|
|
void display_error_msg()
|
|
{
|
|
init_mdtp_ui_data();
|
|
|
|
if (fb_config)
|
|
{
|
|
fbcon_clear();
|
|
display_error_message(); // No point in checking the return value here
|
|
}
|
|
|
|
// Invalid state. Nothing to be done but contacting the OEM.
|
|
// Stop boot process.
|
|
dprintf(CRITICAL,"ERROR: blocking boot process\n");
|
|
for(;;);
|
|
}
|
|
|