1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-02-04 07:13:00 +08:00

feat(drivers): add UEFI driver (#7069)

This commit is contained in:
Michael Simon 2025-01-09 19:31:30 +01:00 committed by GitHub
parent f47879b67e
commit 20bfb4855b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 3127 additions and 0 deletions

21
Kconfig
View File

@ -1299,6 +1299,13 @@ menu "LVGL configuration"
string "Set the working directory" string "Set the working directory"
depends on LV_USE_FS_ARDUINO_SD depends on LV_USE_FS_ARDUINO_SD
config LV_USE_FS_UEFI
bool "File system on top of the UEFI EFI_SIMPLE_FILE_SYSTEM_PROTOCOL"
config LV_USE_FS_UEFI_LETTER
int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')"
default 0
depends on LV_USE_FS_UEFI
config LV_USE_LODEPNG config LV_USE_LODEPNG
bool "PNG decoder library" bool "PNG decoder library"
@ -1938,6 +1945,20 @@ menu "LVGL configuration"
depends on LV_OS_WINDOWS depends on LV_OS_WINDOWS
default n default n
config LV_USE_UEFI
bool "Use LVGL UEFI backend"
default n
config LV_USE_UEFI_INCLUDE
string "Header that hides the actual framework (EDK2, gnu-efi, ...)"
depends on LV_USE_UEFI
default "myefi.h"
config LV_UEFI_USE_MEMORY_SERVICES
bool "Use the memory services from the boot services table"
depends on LV_USE_UEFI
default n
config LV_USE_OPENGLES config LV_USE_OPENGLES
bool "Use GLFW and OpenGL to open window on PC and handle mouse and keyboard" bool "Use GLFW and OpenGL to open window on PC and handle mouse and keyboard"
default n default n

View File

@ -14,3 +14,4 @@ Drivers
wayland wayland
windows windows
X11 X11
uefi

View File

@ -0,0 +1,121 @@
=============================
UEFI Display/Inputs driver
=============================
Overview
--------
The **UEFI** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/uefi>`__ offers support for using LVGL with UEFI.
Prerequisites
-------------
You need the following protocols available:
* *EFI_LOADED_IMAGE_PROTOCOL_GUID*, for file system support (used to determine the file system that was used to load the application)
* *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID*, for file system support
* *EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID*, for keyboard support
* *EFI_SIMPLE_POINTER_PROTOCOL_GUID*, for mouse support
* *EFI_ABSOLUTE_POINTER_PROTOCOL_GUID*, for touch support
* *EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID*, for drawing
* *EFI_EDID_ACTIVE_PROTOCOL_GUID*, for drawing (optional)
Configure UEFI driver
------------------------
- Enable the UEFI driver support in lv_conf.h
.. code-block:: c
#define LV_USE_UEFI 1
- Enable the the memory core functions, which are wrappers around AllocatePool and FreePool (using memory of type *EfiBootServicesData*) if you do not wan't to use your own implementations
.. code-block:: c
#define LV_UEFI_USE_MEMORY_SERVICES 1
- You can enable file system support for the file system from which the appliation got loaded (default letter 'E')
.. code-block:: c
#define LV_USE_FS_UEFI 1
- You need to define an include file which contains the basic UEFI definitions (protocols and types), there are 2 predefined files which can be used for EDK2 and gnu-efi
.. code-block:: c
#define LV_USE_UEFI_INCLUDE <lvgl/src/drivers/uefi/lv_uefi_edk2.h>
// or
#define LV_USE_UEFI_INCLUDE <lvgl/src/drivers/uefi/lv_uefi_gnu_efi.h>
Usage
-----
.. code-block:: c
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
EFI_STATUS EFIAPI EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE * SystemTable)
{
lv_uefi_init(ImageHandle, SystemTable);
lv_init();
if(!lv_is_initialized()) return EFI_NOT_READY;
EFI_HANDLE handle = NULL;
lv_display_t* display = NULL;
lv_indev_t* indev = NULL;
lv_group_t* group = NULL;
lv_obj_t* cursor = NULL;
// used to get out of the main loop
size_t counter;
// Init the display
handle = lv_uefi_display_get_active();
if(handle == NULL) {
handle = lv_uefi_display_get_any();
}
if(handle == NULL) {
lv_deinit();
return EFI_UNSUPPORTED;
}
display = lv_uefi_display_create(handle);
lv_display_set_default(display);
// Create the group
group = lv_group_create();
lv_group_set_default(group);
// Create an image that can be used as cursor
cursor = lv_image_create(lv_layer_top());
lv_image_set_src(cursor, "E:cursor.png");
// Create the input devices
indev = lv_uefi_simple_text_input_indev_create();
lv_indev_set_group(indev, lv_group_get_default());
lv_uefi_simple_text_input_indev_add_all(indev);
indev = lv_uefi_simple_pointer_indev_create(NULL);
lv_uefi_simple_pointer_indev_add_all(indev);
lv_indev_set_cursor(indev, cursor);
indev = lv_uefi_absolute_pointer_indev_create(NULL);
lv_uefi_absolute_pointer_indev_add_all(indev);
lv_demo_widgets();
// Run main loop for ~ 10 seconds
counter = 0;
while(counter < 10000) {
counter ++;
gBS->Stall(1000);
lv_tick_inc(1);
lv_timer_handler();
}
return EFI_SUCCESS;
}

View File

@ -852,6 +852,12 @@
#define LV_FS_ARDUINO_SD_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ #define LV_FS_ARDUINO_SD_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
#endif #endif
/** API for UEFI */
#define LV_USE_FS_UEFI 0
#if LV_USE_FS_UEFI
#define LV_FS_UEFI_LETTER '\0' /**< Set an upper cased letter on which the drive will accessible (e.g. 'A') */
#endif
/** LODEPNG decoder library */ /** LODEPNG decoder library */
#define LV_USE_LODEPNG 0 #define LV_USE_LODEPNG 0
@ -1206,6 +1212,13 @@
/** LVGL Windows backend */ /** LVGL Windows backend */
#define LV_USE_WINDOWS 0 #define LV_USE_WINDOWS 0
/** LVGL UEFI backend */
#define LV_USE_UEFI 0
#if LV_USE_UEFI
#define LV_USE_UEFI_INCLUDE "myefi.h" /**< Header that hides the actual framework (EDK2, gnu-efi, ...) */
#define LV_UEFI_USE_MEMORY_SERVICES 0 /**< Use the memory functions from the boot services table */
#endif
/** Use OpenGL to open window on PC and handle mouse and keyboard */ /** Use OpenGL to open window on PC and handle mouse and keyboard */
#define LV_USE_OPENGLES 0 #define LV_USE_OPENGLES 0
#if LV_USE_OPENGLES #if LV_USE_OPENGLES

View File

@ -169,6 +169,10 @@ typedef struct _lv_global_t {
lv_fs_drv_t win32_fs_drv; lv_fs_drv_t win32_fs_drv;
#endif #endif
#if LV_USE_FS_UEFI
lv_fs_drv_t uefi_fs_drv;
#endif
#if LV_USE_FS_LITTLEFS #if LV_USE_FS_LITTLEFS
lv_fs_drv_t littlefs_fs_drv; lv_fs_drv_t littlefs_fs_drv;
#endif #endif

View File

@ -54,6 +54,10 @@ extern "C" {
#include "wayland/lv_wayland.h" #include "wayland/lv_wayland.h"
#include "uefi/lv_uefi_context.h"
#include "uefi/lv_uefi_indev.h"
#include "uefi/lv_uefi_display.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/

106
src/drivers/uefi/lv_uefi.h Normal file
View File

@ -0,0 +1,106 @@
/**
* @file lv_uefi.h
*
*/
#ifndef LV_UEFI_H
#define LV_UEFI_H
#if LV_USE_UEFI
#include LV_USE_UEFI_INCLUDE
#if defined(__clang__) || defined(__GNUC__)
#if defined(__x86_64__)
#define __LV_UEFI_ARCH_X64__
#define __LV_UEFI_64BIT__
#elif defined(__i386__)
#define __LV_UEFI_ARCH_X86__
#define __LV_UEFI_32BIT__
#elif defined(__aarch64__)
#define __LV_UEFI_ARCH_AARCH64__
#define __LV_UEFI_64BIT__
#else
#error Architecture is not supported
#endif
#define LV_UEFI_STATIC_ASSERT _Static_assert
#elif defined(_MSC_VER)
#if defined(_M_AMD64) && !defined(_M_ARM64)
#define __LV_UEFI_ARCH_X64__
#define __LV_UEFI_64BIT__
#elif defined(_M_IX86)
#define __LV_UEFI_ARCH_X86__
#define __LV_UEFI_32BIT__
#elif defined(_M_ARM64)
#define __LV_UEFI_ARCH_AARCH64__
#define __LV_UEFI_64BIT__
#else
#error Architecture is not supported
#endif
#define LV_UEFI_STATIC_ASSERT static_assert
#else
#error Your compiler is not supported
#endif
#ifdef LV_USE_UEFI_INCLUDE
#include LV_USE_UEFI_INCLUDE
#else
#error No UEFI headers available
#endif
// Verify that all required protocols are known
#if !defined(EFI_LOADED_IMAGE_PROTOCOL_GUID)
#error Missing support for EFI_LOADED_IMAGE_PROTOCOL
#endif
#if !defined(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID)
#error Missing support for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
#endif
#if !defined(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID)
#error Missing support for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
#endif
#if !defined(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID)
#error Missing support for EFI_SIMPLE_TEXT_INPUT_PROTOCOL
#endif
#if !defined(EFI_SIMPLE_POINTER_PROTOCOL_GUID)
#error Missing support for EFI_SIMPLE_POINTER_PROTOCOL
#endif
#if !defined(EFI_ABSOLUTE_POINTER_PROTOCOL_GUID)
#error Missing support for EFI_ABSOLUTE_POINTER_PROTOCOL
#endif
#if !defined(EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID)
#error Missing support for EFI_GRAPHICS_OUTPUT_PROTOCOL
#endif
#if !defined(EFI_EDID_ACTIVE_PROTOCOL_GUID)
#error Missing support for EFI_EDID_ACTIVE_PROTOCOL
#endif
#if !defined(EFI_FILE_INFO_ID)
#error Missing support for EFI_FILE_INFO
#endif
#if !defined(EFI_TIMESTAMP_PROTOCOL_GUID)
#error Missing support for EFI_TIMESTAMP_PROTOCOL_GUID
#endif
// Verify that all types have the correct size
LV_UEFI_STATIC_ASSERT(sizeof(BOOLEAN) == 1, "Size check for 'BOOLEAN' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(INT8) == 1, "Size check for 'INT8' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINT8) == 1, "Size check for 'UINT8' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(INT16) == 2, "Size check for 'INT16' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINT16) == 2, "Size check for 'UINT16' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(INT32) == 4, "Size check for 'INT32' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINT32) == 4, "Size check for 'UINT32' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(INT64) == 8, "Size check for 'INT64' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINT64) == 8, "Size check for 'UINT64' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(CHAR8) == 1, "Size check for 'CHAR8' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(CHAR16) == 2, "Size check for 'CHAR16' failed.");
#ifdef __LV_UEFI_32BIT__
LV_UEFI_STATIC_ASSERT(sizeof(INTN) == 4, "Size check for 'INTN' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINTN) == 4, "Size check for 'UINTN' failed.");
#else
LV_UEFI_STATIC_ASSERT(sizeof(INTN) == 8, "Size check for 'INTN' failed.");
LV_UEFI_STATIC_ASSERT(sizeof(UINTN) == 8, "Size check for 'UINTN' failed.");
#endif
#endif
#endif

View File

@ -0,0 +1,91 @@
/**
* @file lv_uefi_context.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_UEFI
#include "lv_uefi_context.h"
#include "lv_uefi_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* GOLBAL VARIABLES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Initialize the UEFI chache variables.
* @param image_handle The handle of the current image
* @param system_table Pointer to the system table
* @remark This has to be called before lv_init().
*/
void lv_uefi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * system_table)
{
LV_ASSERT_NULL(image_handle);
LV_ASSERT_NULL(system_table);
gLvEfiImageHandle = image_handle;
gLvEfiST = system_table;
gLvEfiBS = gLvEfiST->BootServices;
gLvEfiRT = gLvEfiST->RuntimeServices;
}
/**
* @brief Initialize the LVGL UEFI backend.
* @remark This is a private API which is used for LVGL UEFI backend
* implementation. LVGL users shouldn't use that because the
* LVGL has already used it in lv_init.
*/
void lv_uefi_platform_init(void)
{
LV_ASSERT_NULL(gLvEfiImageHandle);
LV_ASSERT_NULL(gLvEfiST);
LV_ASSERT_NULL(gLvEfiBS);
LV_ASSERT_NULL(gLvEfiRT);
}
/**
* @brief Cleanup the LVGL UEFI backend.
* @remark This is a private API which is used for LVGL UEFI backend
* implementation. LVGL users shouldn't use that because the
* LVGL has already used it in lv_deinit.
*/
void lv_uefi_platform_deinit(void)
{
;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -0,0 +1,71 @@
/**
* @file lv_uefi_context.h
*
*/
#ifndef __LV_UEFI_CONTEXT_H__
#define __LV_UEFI_CONTEXT_H__
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_UEFI
#include "lv_uefi.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Initialize the UEFI chache variables.
* @param image_handle The handle of the current image
* @param system_table Pointer to the system table
* @remark This has to be called before lv_init().
*/
void lv_uefi_init(
EFI_HANDLE image_handle,
EFI_SYSTEM_TABLE * system_table);
/**
* @brief Initialize the LVGL UEFI backend.
* @remark This is a private API which is used for LVGL UEFI backend
* implementation. LVGL users shouldn't use that because the
* LVGL has already used it in lv_init.
*/
void lv_uefi_platform_init(void);
/**
* @brief Cleanup the LVGL UEFI backend.
* @remark This is a private API which is used for LVGL UEFI backend
* implementation. LVGL users shouldn't use that because the
* LVGL has already used it in lv_deinit.
*/
void lv_uefi_platform_deinit(void);
/**********************
* MACROS
**********************/
#endif
#ifdef __cplusplus
}
#endif
#endif //__LV_UEFI_CONTEXT_H__

View File

@ -0,0 +1,284 @@
/**
* @file lv_uefi_display.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_UEFI
#include "lv_uefi_display.h"
#include "lv_uefi_private.h"
#if LV_COLOR_DEPTH != 32
#error [lv_uefi] Unsupported LV_COLOR_DEPTH.
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_uefi_display_context_t {
EFI_HANDLE handle;
EFI_GRAPHICS_OUTPUT_PROTOCOL * gop_protocol;
void * buffer;
size_t buffer_size;
} lv_uefi_display_context_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void _display_event_cb(lv_event_t * e);
static void _display_flush_cb(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
static void _display_ctx_free(lv_uefi_display_context_t * display_ctx);
static bool _display_interface_is_valid(const EFI_GRAPHICS_OUTPUT_PROTOCOL * interface);
/**********************
* GOLBAL VARIABLES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static EFI_GUID _uefi_guid_graphics_output = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID _uefi_guid_edid_active = EFI_EDID_ACTIVE_PROTOCOL_GUID;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Create a LVGL display object.
* @param handle The handle on which an instance of the EFI_GRAPHICS_OUTPUT_PROTOCOL protocol is installed.
* @return The created LVGL display object.
*/
lv_display_t * lv_uefi_display_create(void * handle)
{
lv_display_t * display = NULL;
lv_uefi_display_context_t * display_ctx;
if(!lv_uefi_protocol_test(handle, &_uefi_guid_graphics_output)) return NULL;
display_ctx = lv_calloc(1, sizeof(lv_uefi_display_context_t));
LV_ASSERT_MALLOC(display_ctx);
display_ctx->handle = handle;
display_ctx->gop_protocol = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)lv_uefi_protocol_open(handle, &_uefi_guid_graphics_output);
if(!_display_interface_is_valid(display_ctx->gop_protocol)) {
LV_LOG_WARN("[lv_uefi] The GOP interface is not valid.");
goto error;
}
// 4 bytes per pixel
display_ctx->buffer_size = 4 * display_ctx->gop_protocol->Mode->Info->HorizontalResolution *
display_ctx->gop_protocol->Mode->Info->VerticalResolution;
display_ctx->buffer = lv_malloc(display_ctx->buffer_size);
LV_ASSERT_MALLOC(display_ctx->buffer);
display = lv_display_create(display_ctx->gop_protocol->Mode->Info->HorizontalResolution,
display_ctx->gop_protocol->Mode->Info->VerticalResolution);
lv_display_add_event_cb(display, _display_event_cb, LV_EVENT_DELETE, display);
lv_display_set_flush_cb(display, _display_flush_cb);
lv_display_set_buffers(display, display_ctx->buffer, NULL, (uint32_t)display_ctx->buffer_size,
LV_DISPLAY_RENDER_MODE_DIRECT);
lv_display_set_user_data(display, display_ctx);
goto finish;
error:
if(display != NULL) {
lv_display_set_user_data(display, NULL);
lv_display_delete(display);
display = NULL;
}
if(display_ctx != NULL) _display_ctx_free(display_ctx);
finish:
return display;
}
/**
* @brief Try to find the active display handle.
* @return The handle or NULL if not found.
* @remark The active display need interfaces for EFI_GRAPHICS_OUTPUT_PROTOCOL and EFI_EDID_ACTIVE_PROTOCOL
*/
void * lv_uefi_display_get_active(void)
{
EFI_STATUS status;
EFI_HANDLE active_handle = NULL;
EFI_HANDLE * handles = NULL;
UINTN no_handles;
UINTN index;
status = gLvEfiBS->LocateHandleBuffer(
ByProtocol,
&_uefi_guid_graphics_output,
NULL,
&no_handles,
&handles);
if(status != EFI_SUCCESS) goto error;
for(index = 0; index < no_handles; index++) {
if(!lv_uefi_protocol_test(handles[index], &_uefi_guid_edid_active)) continue;
if(!lv_uefi_protocol_test(handles[index], &_uefi_guid_graphics_output)) continue;
active_handle = handles[index];
break;
}
goto finish;
error:
finish:
if(handles != NULL) gLvEfiBS->FreePool(handles);
return active_handle;
}
/**
* @brief Try to find any display handle.
* @return The handle or NULL if not found.
*/
void * lv_uefi_display_get_any(void)
{
EFI_STATUS status;
EFI_HANDLE active_handle = NULL;
EFI_HANDLE * handles = NULL;
UINTN no_handles;
UINTN index;
status = gLvEfiBS->LocateHandleBuffer(
ByProtocol,
&_uefi_guid_graphics_output,
NULL,
&no_handles,
&handles);
if(status != EFI_SUCCESS) goto error;
for(index = 0; index < no_handles; index++) {
if(!lv_uefi_protocol_test(handles[index], &_uefi_guid_graphics_output)) continue;
active_handle = handles[index];
break;
}
goto finish;
error:
finish:
if(handles != NULL) gLvEfiBS->FreePool(handles);
return active_handle;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _display_event_cb(lv_event_t * e)
{
lv_display_t * display;
lv_uefi_display_context_t * display_ctx;
if(lv_event_get_code(e) != LV_EVENT_DELETE) return;
display = (lv_display_t *)lv_event_get_user_data(e);
if(display == NULL) return;
display_ctx = (lv_uefi_display_context_t *)lv_display_get_user_data(display);
lv_display_set_user_data(display, NULL);
if(display_ctx != NULL) _display_ctx_free(display_ctx);
}
static void _display_flush_cb(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
{
EFI_STATUS status;
int32_t w;
int32_t h;
lv_uefi_display_context_t * display_ctx = (lv_uefi_display_context_t *)lv_display_get_user_data(display);
LV_ASSERT_NULL(display_ctx);
w = (int32_t)area->x2 - (int32_t)area->x1 + 1;
h = (int32_t)area->y2 - (int32_t)area->y1 + 1;
if(w < 0 || h < 0) {
LV_LOG_ERROR("[lv_uefi] Invalid lv_display_flush_cb call (invalid rect).");
goto error;
}
if((uint32_t)(area->x1 + w) > display_ctx->gop_protocol->Mode->Info->HorizontalResolution) {
LV_LOG_ERROR("[lv_uefi] Invalid lv_display_flush_cb call (invalid width).");
goto error;
}
if((uint32_t)(area->y1 + h) > display_ctx->gop_protocol->Mode->Info->HorizontalResolution) {
LV_LOG_ERROR("[lv_uefi] Invalid lv_display_flush_cb call (invalid height).");
goto error;
}
status = display_ctx->gop_protocol->Blt(
display_ctx->gop_protocol,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)px_map,
EfiBltBufferToVideo,
area->x1,
area->y1,
area->x1,
area->y1,
w,
h,
display_ctx->gop_protocol->Mode->Info->HorizontalResolution * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] Blt failed with error code: %llx.", status);
goto error;
}
goto finish;
error:
finish:
lv_display_flush_ready(display);
}
static void _display_ctx_free(lv_uefi_display_context_t * display_ctx)
{
if(display_ctx == NULL) {
return;
}
if(display_ctx->gop_protocol != NULL) lv_uefi_protocol_close(display_ctx->handle, &_uefi_guid_graphics_output);
if(display_ctx->buffer != NULL) lv_free(display_ctx->buffer);
lv_free(display_ctx);
}
static bool _display_interface_is_valid(const EFI_GRAPHICS_OUTPUT_PROTOCOL * interface)
{
if(interface == NULL) return FALSE;
if(interface->Mode == NULL) return FALSE;
if(interface->Mode->Info == NULL) return FALSE;
if(interface->Mode->Info->HorizontalResolution == 0) return FALSE;
if(interface->Mode->Info->HorizontalResolution >= 32767) return FALSE;
if(interface->Mode->Info->VerticalResolution == 0) return FALSE;
if(interface->Mode->Info->VerticalResolution >= 32767) return FALSE;
return TRUE;
}
#endif

View File

@ -0,0 +1,65 @@
/**
* @file lv_uefi_display.h
*
*/
#ifndef __LV_UEFI_DISPLAY_H__
#define __LV_UEFI_DISPLAY_H__
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#if LV_USE_UEFI
#include "lv_uefi.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Create a LVGL display object.
* @param handle The handle on which an instance of the EFI_GRAPHICS_OUTPUT_PROTOCOL protocol is installed.
* @return The created LVGL display object.
*/
lv_display_t * lv_uefi_display_create(void * handle);
/**
* @brief Try to find the active display handle.
* @return The handle or NULL if not found.
* @remark The active display need interfaces for EFI_GRAPHICS_OUTPUT_PROTOCOL and EFI_EDID_ACTIVE_PROTOCOL
*/
void * lv_uefi_display_get_active(void);
/**
* @brief Try to find any display handle.
* @return The handle or NULL if not found.
*/
void * lv_uefi_display_get_any(void);
/**********************
* MACROS
**********************/
#endif
#ifdef __cplusplus
}
#endif
#endif //__LV_UEFI_DISPLAY_H__

View File

@ -0,0 +1,28 @@
/**
* @file lv_uefi_edk2.h
*
*/
#ifndef LV_UEFI_EDK2_H
#define LV_UEFI_EDK2_H
#if LV_USE_UEFI
#define LV_UEFI_EDK2_HEADERS 1
#include <Uefi.h>
#include <Base.h>
#include <Protocol/SimplePointer.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/AbsolutePointer.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/SimpleTextIn.h>
#include <Protocol/SimpleTextOut.h>
#include <Protocol/Timestamp.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/EdidActive.h>
#include <Guid/FileInfo.h>
#endif
#endif

View File

@ -0,0 +1,17 @@
/**
* @file lv_uefi_gnu_efi.h
*
*/
#ifndef LV_UEFI_GNU_EFI_H
#define LV_UEFI_GNU_EFI_H
#if LV_USE_UEFI
#define LV_UEFI_GNU_EFI_HEADERS 1
#include <efi.h>
#endif
#endif

View File

@ -0,0 +1,108 @@
/**
* @file lv_uefi_indev.h
*
*/
#ifndef __LV_UEFI_INDEV_H__
#define __LV_UEFI_INDEV_H__
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../indev/lv_indev.h"
#if LV_USE_UEFI
#include "lv_uefi.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Create an indev object.
* @param display_res The resolution of the display in pixels, needed to scale the input.
* If NULL the resolution of the current default display will be used.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_simple_pointer_indev_create(lv_point_t * display_res);
/**
* @brief Add an EFI_SIMPLE_POINTER_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_simple_pointer_indev_create.
* @param handle The handle on which an instance of the EFI_SIMPLE_POINTER_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_simple_pointer_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle);
/**
* @brief Add all available EFI_SIMPLE_POINTER_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_simple_pointer_indev_create.
*/
void lv_uefi_simple_pointer_indev_add_all(lv_indev_t * indev);
/**
* @brief Create a LVGL indev object.
* @param display_res The resolution of the display in pixels, needed to scale the input.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_absolute_pointer_indev_create(lv_point_t * display_res);
/**
* @brief Add an EFI_ABSOLUTE_POINTER_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_absolute_pointer_indev_create.
* @param handle The handle on which an instance of the EFI_ABSOLUTE_POINTER_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_absolute_pointer_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle);
/**
* @brief Add all available EFI_ABSOLUTE_POINTER_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_absolute_pointer_indev_create.
*/
void lv_uefi_absolute_pointer_indev_add_all(lv_indev_t * indev);
/**
* @brief Create an indev object.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_simple_text_input_indev_create(void);
/**
* @brief Add an EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_simple_text_input_indev_create.
* @param handle The handle on which an instance of the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_simple_text_input_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle);
/**
* @brief Add all available EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_simple_text_input_indev_create.
*/
void lv_uefi_simple_text_input_indev_add_all(lv_indev_t * indev);
/**********************
* MACROS
**********************/
#endif
#ifdef __cplusplus
}
#endif
#endif //__LV_UEFI_INDEV_H__

View File

@ -0,0 +1,346 @@
/**
* @file lv_uefi_indev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#include "../../stdlib/lv_mem.h"
#include "../../misc/lv_types.h"
#include "../../misc/lv_text.h"
#if LV_USE_UEFI
#include "lv_uefi_indev.h"
#include "lv_uefi_private.h"
/*********************
* DEFINES
*********************/
#define SIMPLE_TEXT_INPUT_INDEV_SIGNATURE 0x53495449
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_uefi_simple_text_input_key_cache_t {
uint32_t key; /**< Key code*/
bool pressed; /**< If true this is a pressed entry if false this is a release entry*/
} lv_uefi_simple_text_input_key_cache_t;
typedef struct _lv_uefi_simple_text_input_handle_context_t {
EFI_HANDLE handle;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * interface;
} lv_uefi_simple_text_input_handle_context_t;
typedef struct _lv_uefi_simple_text_input_context_t {
uint32_t signature; /**< Has to be checked to avoid access to a different indev*/
lv_ll_t handles;
lv_ll_t key_cache;
} lv_uefi_simple_text_input_context_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void _simple_text_input_event_cb(lv_event_t * e);
static void _simple_text_input_read_cb(lv_indev_t * indev, lv_indev_data_t * data);
static void _simple_text_input_handle_context_free(void * ptr);
static void _simple_text_input_context_free(lv_uefi_simple_text_input_context_t * indev_ctx);
static bool _simple_text_input_interface_is_valid(const EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * interface);
static void _simple_text_input_read(lv_uefi_simple_text_input_context_t * indev_ctx,
lv_uefi_simple_text_input_handle_context_t * handle_ctx);
static uint32_t _utf8_from_unicode(UINT32 unicode);
static uint32_t _key_from_uefi_key(const EFI_KEY_DATA * key);
/**********************
* STATIC VARIABLES
**********************/
static EFI_GUID _uefi_guid_simple_text_input = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Create an indev object.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_simple_text_input_indev_create(void)
{
lv_indev_t * indev = NULL;
lv_uefi_simple_text_input_context_t * indev_ctx = NULL;
indev_ctx = lv_calloc(1, sizeof(lv_uefi_simple_text_input_context_t));
LV_ASSERT_MALLOC(indev_ctx);
indev_ctx->signature = SIMPLE_TEXT_INPUT_INDEV_SIGNATURE;
lv_ll_init(&indev_ctx->handles, sizeof(lv_uefi_simple_text_input_handle_context_t));
lv_ll_init(&indev_ctx->key_cache, sizeof(lv_uefi_simple_text_input_key_cache_t));
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_user_data(indev, indev_ctx);
lv_indev_add_event_cb(indev, _simple_text_input_event_cb, LV_EVENT_DELETE, indev);
lv_indev_set_read_cb(indev, _simple_text_input_read_cb);
return indev;
}
/**
* @brief Add an EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_simple_text_input_indev_create.
* @param handle The handle on which an instance of the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_simple_text_input_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle)
{
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * interface = NULL;
lv_uefi_simple_text_input_handle_context_t * handle_ctx = NULL;
lv_uefi_simple_text_input_context_t * indev_ctx = (lv_uefi_simple_text_input_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != SIMPLE_TEXT_INPUT_INDEV_SIGNATURE) return false;
interface = (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *)lv_uefi_protocol_open(handle, &_uefi_guid_simple_text_input);
if(!_simple_text_input_interface_is_valid(interface)) {
lv_uefi_protocol_close(handle, &_uefi_guid_simple_text_input);
LV_LOG_WARN("[lv_uefi] The SIMPLE_TEXT_INPUT interface is not valid.");
return false;
}
handle_ctx = (lv_uefi_simple_text_input_handle_context_t *) lv_ll_ins_head(&indev_ctx->handles);
LV_ASSERT_MALLOC(handle_ctx);
handle_ctx->handle = handle;
handle_ctx->interface = interface;
return true;
}
/**
* @brief Add all available EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_simple_text_input_indev_create.
*/
void lv_uefi_simple_text_input_indev_add_all(lv_indev_t * indev)
{
EFI_STATUS status;
EFI_HANDLE * handles = NULL;
UINTN no_handles;
UINTN index;
lv_uefi_simple_text_input_context_t * indev_ctx = (lv_uefi_simple_text_input_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != SIMPLE_TEXT_INPUT_INDEV_SIGNATURE) return;
status = gLvEfiBS->LocateHandleBuffer(ByProtocol, &_uefi_guid_simple_text_input, NULL, &no_handles, &handles);
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] LocateHandleBuffer(SIMPLE_TEXT_INPUT_EX) failed with error code %llx.", status);
return;
}
for(index = 0; index < no_handles; index++) {
lv_uefi_simple_text_input_indev_add_handle(indev, handles[index]);
}
if(handles != NULL) gLvEfiBS->FreePool(handles);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _simple_text_input_event_cb(lv_event_t * e)
{
lv_indev_t * indev;
lv_uefi_simple_text_input_context_t * indev_ctx;
if(lv_event_get_code(e) != LV_EVENT_DELETE) return;
indev = (lv_indev_t *)lv_event_get_user_data(e);
if(indev == NULL) return;
indev_ctx = (lv_uefi_simple_text_input_context_t *)lv_indev_get_user_data(indev);
lv_indev_set_user_data(indev, NULL);
if(indev_ctx != NULL) _simple_text_input_context_free(indev_ctx);
}
static void _simple_text_input_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_uefi_simple_text_input_handle_context_t * handle_ctx = NULL;
lv_uefi_simple_text_input_key_cache_t * key_cache = NULL;
void * node = NULL;
lv_uefi_simple_text_input_context_t * indev_ctx = (lv_uefi_simple_text_input_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
/* Empty the buffer before reading new values */
if(lv_ll_is_empty(&indev_ctx->key_cache)) {
// Read from all registered devices
for(node = lv_ll_get_head(&indev_ctx->handles); node != NULL; node = lv_ll_get_next(&indev_ctx->handles, node)) {
handle_ctx = (lv_uefi_simple_text_input_handle_context_t *) node;
_simple_text_input_read(indev_ctx, handle_ctx);
}
}
/* Return the first value */
node = lv_ll_get_head(&indev_ctx->key_cache);
if(node != NULL) {
key_cache = (lv_uefi_simple_text_input_key_cache_t *)node;
data->state = key_cache->pressed ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
data->key = key_cache->key;
lv_ll_remove(&indev_ctx->key_cache, node);
lv_free(key_cache);
}
/* Continue reading if there are more values in the buffer */
data->continue_reading = !lv_ll_is_empty(&indev_ctx->key_cache);
}
static void _simple_text_input_context_free(lv_uefi_simple_text_input_context_t * indev_ctx)
{
if(indev_ctx == NULL) return;
lv_ll_clear_custom(&indev_ctx->handles, _simple_text_input_handle_context_free);
lv_ll_clear(&indev_ctx->key_cache);
lv_free(indev_ctx);
}
static bool _simple_text_input_interface_is_valid(const EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * interface)
{
if(interface == NULL) return FALSE;
return TRUE;
}
static void _simple_text_input_handle_context_free(void * ptr)
{
lv_uefi_simple_text_input_handle_context_t * handle_ctx = (lv_uefi_simple_text_input_handle_context_t *)ptr;
if(handle_ctx == NULL) return;
if(handle_ctx->interface) lv_uefi_protocol_close(handle_ctx->handle, &_uefi_guid_simple_text_input);
lv_free(handle_ctx);
}
static void _simple_text_input_read(lv_uefi_simple_text_input_context_t * indev_ctx,
lv_uefi_simple_text_input_handle_context_t * handle_ctx)
{
EFI_STATUS status;
EFI_KEY_DATA state;
uint32_t key;
lv_uefi_simple_text_input_key_cache_t * cache = NULL;
LV_ASSERT_NULL(indev_ctx);
LV_ASSERT_NULL(handle_ctx);
status = handle_ctx->interface->ReadKeyStrokeEx(
handle_ctx->interface,
&state);
if(status == EFI_NOT_READY) return;
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] ReadKeyStrokeEx failed.");
return;
}
key = _key_from_uefi_key(&state);
/* insert the press */
cache = (lv_uefi_simple_text_input_key_cache_t *) lv_ll_ins_tail(&indev_ctx->key_cache);
LV_ASSERT_MALLOC(cache);
cache->key = key;
cache->pressed = true;
/* insert the release */
cache = (lv_uefi_simple_text_input_key_cache_t *) lv_ll_ins_tail(&indev_ctx->key_cache);
LV_ASSERT_MALLOC(cache);
cache->key = key;
cache->pressed = false;
}
static uint32_t _utf8_from_unicode(UINT32 unicode)
{
uint8_t bytes[4] = {0, 0, 0, 0};
/* unicode < 128 -> 1 byte */
if(unicode < 128) {
bytes[0] |= unicode;
}
/* unicode < 2048 -> 2 byte */
else if(unicode < 2048) {
bytes[0] = 0xC0;
bytes[0] |= unicode >> 6;
bytes[1] = 0x80;
bytes[1] |= (unicode & 0x003F);
}
/* unicode < 65536 -> 3 byte */
else if(unicode < 65536) {
bytes[0] = 0xE0;
bytes[0] |= unicode >> 12;
bytes[1] = 0x80;
bytes[1] |= ((unicode >> 6) & 0x003F);
bytes[2] = 0x80;
bytes[2] |= (unicode & 0x003F);
}
return *((uint32_t *)bytes);
}
static uint32_t _key_from_uefi_key(const EFI_KEY_DATA * key)
{
LV_ASSERT_NULL(key);
switch(key->Key.ScanCode) {
case 0x01:
return LV_KEY_UP;
case 0x02:
return LV_KEY_DOWN;
case 0x04:
return LV_KEY_LEFT;
case 0x03:
return LV_KEY_RIGHT;
case 0x08:
return LV_KEY_DEL;
case 0x05:
return LV_KEY_HOME;
case 0x06:
return LV_KEY_END;
case 0x17:
return LV_KEY_ESC;
/* ignore all other scan codes */
default:
break;
}
switch(key->Key.UnicodeChar) {
case 0x09:
return (key->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) &&
(key->KeyState.KeyShiftState & (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED)) ?
LV_KEY_PREV :
LV_KEY_NEXT;
case 0x08:
return LV_KEY_BACKSPACE;
case 0x0D:
return LV_KEY_ENTER;
case 0x18:
return LV_KEY_ESC;
default:
return _utf8_from_unicode(key->Key.UnicodeChar);
}
}
#endif

View File

@ -0,0 +1,285 @@
/**
* @file lv_uefi_indev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#include "../../stdlib/lv_mem.h"
#include "../../misc/lv_types.h"
#include "../../misc/lv_text.h"
#if LV_USE_UEFI
#include "lv_uefi_indev.h"
#include "lv_uefi_private.h"
/*********************
* DEFINES
*********************/
#define SIMPLE_POINTER_INDEV_SIGNATURE 0x53505449
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_uefi_simple_pointer_handle_context_t {
EFI_HANDLE handle;
EFI_SIMPLE_POINTER_PROTOCOL * interface;
lv_point_t pixel_per_step_8; /**< How many pixels does the mouse cursor move in one step*/
} lv_uefi_simple_pointer_handle_context_t;
typedef struct _lv_uefi_simple_pointer_context_t {
uint32_t signature; /**< Has to be checked to avoid access to a different indev*/
lv_point_t display_res;
lv_point_t position;
lv_ll_t handles;
} lv_uefi_simple_pointer_context_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void _simple_pointer_indev_event_cb(lv_event_t * e);
static void _simple_pointer_read_cb(lv_indev_t * indev, lv_indev_data_t * data);
static void _simple_pointer_handle_context_free(void * ptr);
static void _simple_pointer_context_free(lv_uefi_simple_pointer_context_t * indev_ctx);
static bool _simple_pointer_interface_is_valid(const EFI_SIMPLE_POINTER_PROTOCOL * interface);
static void _simple_pointer_read(lv_uefi_simple_pointer_context_t * indev_ctx,
lv_uefi_simple_pointer_handle_context_t * handle_ctx, bool * was_pressed);
/**********************
* STATIC VARIABLES
**********************/
static EFI_GUID _uefi_guid_simple_pointer = EFI_SIMPLE_POINTER_PROTOCOL_GUID;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Create an indev object.
* @param display_res The resolution of the display in pixels, needed to scale the input.
* If NULL the resolution of the current default display will be used.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_simple_pointer_indev_create(lv_point_t * display_res)
{
lv_indev_t * indev = NULL;
lv_uefi_simple_pointer_context_t * indev_ctx = NULL;
indev_ctx = lv_calloc(1, sizeof(lv_uefi_simple_pointer_context_t));
LV_ASSERT_MALLOC(indev_ctx);
indev_ctx->signature = SIMPLE_POINTER_INDEV_SIGNATURE;
if(display_res != NULL) {
indev_ctx->display_res.x = display_res->x;
indev_ctx->display_res.y = display_res->y;
}
else {
indev_ctx->display_res.x = lv_display_get_horizontal_resolution(lv_display_get_default());
indev_ctx->display_res.y = lv_display_get_vertical_resolution(lv_display_get_default());
}
lv_ll_init(&indev_ctx->handles, sizeof(lv_uefi_simple_pointer_handle_context_t));
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_user_data(indev, indev_ctx);
lv_indev_add_event_cb(indev, _simple_pointer_indev_event_cb, LV_EVENT_DELETE, indev);
lv_indev_set_read_cb(indev, _simple_pointer_read_cb);
return indev;
}
/**
* @brief Add an EFI_SIMPLE_POINTER_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_simple_pointer_indev_create.
* @param handle The handle on which an instance of the EFI_SIMPLE_POINTER_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_simple_pointer_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle)
{
EFI_SIMPLE_POINTER_PROTOCOL * interface = NULL;
lv_uefi_simple_pointer_handle_context_t * handle_ctx = NULL;
lv_uefi_simple_pointer_context_t * indev_ctx = (lv_uefi_simple_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != SIMPLE_POINTER_INDEV_SIGNATURE) return false;
interface = (EFI_SIMPLE_POINTER_PROTOCOL *)lv_uefi_protocol_open(handle, &_uefi_guid_simple_pointer);
if(!_simple_pointer_interface_is_valid(interface)) {
lv_uefi_protocol_close(handle, &_uefi_guid_simple_pointer);
LV_LOG_WARN("[lv_uefi] The SIMPLE_POINTER interface is not valid.");
return false;
}
handle_ctx = (lv_uefi_simple_pointer_handle_context_t *) lv_ll_ins_head(&indev_ctx->handles);
LV_ASSERT_MALLOC(handle_ctx);
handle_ctx->handle = handle;
handle_ctx->interface = interface;
handle_ctx->pixel_per_step_8.x = (((indev_ctx->display_res.x) << 8) / 50) /
interface->Mode->ResolutionX;
handle_ctx->pixel_per_step_8.y = (((indev_ctx->display_res.y) << 8) / 50) /
interface->Mode->ResolutionY;
return true;
}
/**
* @brief Add all available EFI_SIMPLE_POINTER_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_simple_pointer_indev_create.
*/
void lv_uefi_simple_pointer_indev_add_all(lv_indev_t * indev)
{
EFI_STATUS status;
EFI_HANDLE * handles = NULL;
UINTN no_handles;
UINTN index;
lv_uefi_simple_pointer_context_t * indev_ctx = (lv_uefi_simple_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != SIMPLE_POINTER_INDEV_SIGNATURE) return;
status = gLvEfiBS->LocateHandleBuffer(ByProtocol, &_uefi_guid_simple_pointer, NULL, &no_handles, &handles);
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] LocateHandleBuffer(SIMPLE_POINTER) failed with error code %llx.", status);
return;
}
for(index = 0; index < no_handles; index++) {
lv_uefi_simple_pointer_indev_add_handle(indev, handles[index]);
}
if(handles != NULL) gLvEfiBS->FreePool(handles);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _simple_pointer_indev_event_cb(lv_event_t * e)
{
lv_indev_t * indev;
lv_uefi_simple_pointer_context_t * indev_ctx;
if(lv_event_get_code(e) != LV_EVENT_DELETE) return;
indev = (lv_indev_t *)lv_event_get_user_data(e);
if(indev == NULL) return;
indev_ctx = (lv_uefi_simple_pointer_context_t *)lv_indev_get_user_data(indev);
lv_indev_set_user_data(indev, NULL);
if(indev_ctx != NULL) _simple_pointer_context_free(indev_ctx);
}
static void _simple_pointer_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
{
void * node = NULL;
lv_uefi_simple_pointer_context_t * indev_ctx = (lv_uefi_simple_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
/* Read from all registered devices */
for(node = lv_ll_get_head(&indev_ctx->handles); node != NULL; node = lv_ll_get_next(&indev_ctx->handles, node)) {
lv_uefi_simple_pointer_handle_context_t * handle_ctx = (lv_uefi_simple_pointer_handle_context_t *) node;
bool was_pressed = false;
_simple_pointer_read(indev_ctx, handle_ctx, &was_pressed);
data->state |= was_pressed ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
/* Sanitize the events position */
if(indev_ctx->position.x < 0) {
indev_ctx->position.x = 0;
}
else if(indev_ctx->position.x > indev_ctx->display_res.x - 1) {
indev_ctx->position.x = indev_ctx->display_res.x - 1;
}
if(indev_ctx->position.y < 0) {
indev_ctx->position.y = 0;
}
else if(indev_ctx->position.y > indev_ctx->display_res.y - 1) {
indev_ctx->position.y = indev_ctx->display_res.y - 1;
}
data->point.x = indev_ctx->position.x;
data->point.y = indev_ctx->position.y;
data->continue_reading = FALSE;
}
static void _simple_pointer_context_free(lv_uefi_simple_pointer_context_t * indev_ctx)
{
if(indev_ctx == NULL) return;
lv_ll_clear_custom(&indev_ctx->handles, _simple_pointer_handle_context_free);
lv_free(indev_ctx);
}
static bool _simple_pointer_interface_is_valid(const EFI_SIMPLE_POINTER_PROTOCOL * interface)
{
if(interface == NULL) return FALSE;
if(interface->Mode == NULL) return FALSE;
if(interface->Mode->ResolutionX == 0) return FALSE;
if(interface->Mode->ResolutionX >= 256) return FALSE;
if(interface->Mode->ResolutionY == 0) return FALSE;
if(interface->Mode->ResolutionY >= 256) return FALSE;
return TRUE;
}
static void _simple_pointer_handle_context_free(void * ptr)
{
lv_uefi_simple_pointer_handle_context_t * handle_ctx = (lv_uefi_simple_pointer_handle_context_t *)ptr;
if(handle_ctx == NULL) return;
if(handle_ctx->interface) lv_uefi_protocol_close(handle_ctx->handle, &_uefi_guid_simple_pointer);
lv_free(handle_ctx);
}
static void _simple_pointer_read(lv_uefi_simple_pointer_context_t * indev_ctx,
lv_uefi_simple_pointer_handle_context_t * handle_ctx, bool * was_pressed)
{
EFI_STATUS status;
EFI_SIMPLE_POINTER_STATE state;
lv_point_t pointer_mov;
LV_ASSERT_NULL(indev_ctx);
LV_ASSERT_NULL(handle_ctx);
LV_ASSERT_NULL(was_pressed);
status = handle_ctx->interface->GetState(
handle_ctx->interface,
&state);
if(status == EFI_NOT_READY) return;
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] GetState failed.");
return;
}
pointer_mov.x = (state.RelativeMovementX * handle_ctx->pixel_per_step_8.x) >> 8;
pointer_mov.y = (state.RelativeMovementY * handle_ctx->pixel_per_step_8.y) >> 8;
indev_ctx->position.x += pointer_mov.x;
indev_ctx->position.y += pointer_mov.y;
/* Set the state to pressed if one of the interfaces reports a press */
*was_pressed = state.LeftButton;
}
#endif

View File

@ -0,0 +1,290 @@
/**
* @file lv_uefi_indev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#include "../../stdlib/lv_mem.h"
#include "../../misc/lv_types.h"
#include "../../misc/lv_text.h"
#if LV_USE_UEFI
#include "lv_uefi_indev.h"
#include "lv_uefi_private.h"
/*********************
* DEFINES
*********************/
#define ABSOLUTE_POINTER_INDEV_SIGNATURE 0x41505449
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_uefi_absolute_pointer_handle_context_t {
EFI_HANDLE handle;
EFI_ABSOLUTE_POINTER_PROTOCOL * interface;
lv_point_t range; /**< The touchscreen resolution*/
lv_point_t factor_8; /**< The scaling factor between the touchscreen and the display resolution*/
} lv_uefi_absolute_pointer_handle_context_t;
typedef struct _lv_uefi_absolute_pointer_context_t {
uint32_t signature; /**< Has to be checked to avoid access to a different indev*/
lv_point_t display_res;
lv_point_t position;
lv_ll_t handles;
} lv_uefi_absolute_pointer_context_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void _absolute_pointer_indev_event_cb(lv_event_t * e);
static void _absolute_pointer_read_cb(lv_indev_t * indev, lv_indev_data_t * data);
static void _absolute_pointer_handle_context_free(void * ptr);
static void _absolute_pointer_context_free(lv_uefi_absolute_pointer_context_t * indev_ctx);
static bool _absolute_pointer_interface_is_valid(const EFI_ABSOLUTE_POINTER_PROTOCOL * interface);
static void _absolute_pointer_read(lv_uefi_absolute_pointer_context_t * indev_ctx,
lv_uefi_absolute_pointer_handle_context_t * handle_ctx, bool * was_pressed);
/**********************
* STATIC VARIABLES
**********************/
static EFI_GUID _uefi_guid_absolute_pointer = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Create a LVGL indev object.
* @param display_res The resolution of the display in pixels, needed to scale the input.
* @return The created LVGL indev object.
*/
lv_indev_t * lv_uefi_absolute_pointer_indev_create(lv_point_t * display_res)
{
lv_indev_t * indev = NULL;
lv_uefi_absolute_pointer_context_t * indev_ctx = NULL;
indev_ctx = lv_calloc(1, sizeof(lv_uefi_absolute_pointer_context_t));
LV_ASSERT_MALLOC(indev_ctx);
indev_ctx->signature = ABSOLUTE_POINTER_INDEV_SIGNATURE;
if(display_res != NULL) {
indev_ctx->display_res.x = display_res->x;
indev_ctx->display_res.y = display_res->y;
}
else {
indev_ctx->display_res.x = lv_display_get_horizontal_resolution(lv_display_get_default());
indev_ctx->display_res.y = lv_display_get_vertical_resolution(lv_display_get_default());
}
lv_ll_init(&indev_ctx->handles, sizeof(lv_uefi_absolute_pointer_handle_context_t));
indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_user_data(indev, indev_ctx);
lv_indev_add_event_cb(indev, _absolute_pointer_indev_event_cb, LV_EVENT_DELETE, indev);
lv_indev_set_read_cb(indev, _absolute_pointer_read_cb);
return indev;
}
/**
* @brief Add an EFI_ABSOLUTE_POINTER_PROTOCOL interface to the indev.
* @param indev Indev that was created with lv_uefi_absolute_pointer_indev_create.
* @param handle The handle on which an instance of the EFI_ABSOLUTE_POINTER_PROTOCOL protocol is installed.
* @return True if the interface was added.
*/
bool lv_uefi_absolute_pointer_indev_add_handle(lv_indev_t * indev, EFI_HANDLE handle)
{
EFI_ABSOLUTE_POINTER_PROTOCOL * interface = NULL;
lv_uefi_absolute_pointer_handle_context_t * handle_ctx = NULL;
lv_uefi_absolute_pointer_context_t * indev_ctx = (lv_uefi_absolute_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != ABSOLUTE_POINTER_INDEV_SIGNATURE) return false;
interface = (EFI_ABSOLUTE_POINTER_PROTOCOL *)lv_uefi_protocol_open(handle, &_uefi_guid_absolute_pointer);
if(!_absolute_pointer_interface_is_valid(interface)) {
lv_uefi_protocol_close(handle, &_uefi_guid_absolute_pointer);
LV_LOG_WARN("[lv_uefi] The ABSOLUTE_POINTER interface is not valid.");
return false;
}
handle_ctx = (lv_uefi_absolute_pointer_handle_context_t *) lv_ll_ins_head(&indev_ctx->handles);
LV_ASSERT_MALLOC(handle_ctx);
handle_ctx->handle = handle;
handle_ctx->interface = interface;
handle_ctx->range.x = handle_ctx->interface->Mode->AbsoluteMaxX -
handle_ctx->interface->Mode->AbsoluteMinX;
handle_ctx->range.y = handle_ctx->interface->Mode->AbsoluteMaxY -
handle_ctx->interface->Mode->AbsoluteMinY;
handle_ctx->factor_8.x = (indev_ctx->display_res.x << 8) / handle_ctx->range.x;
handle_ctx->factor_8.y = (indev_ctx->display_res.y << 8) / handle_ctx->range.y;
return true;
}
/**
* @brief Add all available EFI_ABSOLUTE_POINTER_PROTOCOL interfaces to the indev.
* @param indev Indev that was created with lv_uefi_absolute_pointer_indev_create.
*/
void lv_uefi_absolute_pointer_indev_add_all(lv_indev_t * indev)
{
EFI_STATUS status;
EFI_HANDLE * handles = NULL;
UINTN no_handles;
UINTN index;
lv_uefi_absolute_pointer_context_t * indev_ctx = (lv_uefi_absolute_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
if(indev_ctx->signature != ABSOLUTE_POINTER_INDEV_SIGNATURE) return;
status = gLvEfiBS->LocateHandleBuffer(ByProtocol, &_uefi_guid_absolute_pointer, NULL, &no_handles, &handles);
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] LocateHandleBuffer(ABSOLUTE_POINTER) failed with error code %llx.", status);
return;
}
for(index = 0; index < no_handles; index++) {
lv_uefi_absolute_pointer_indev_add_handle(indev, handles[index]);
}
if(handles != NULL) gLvEfiBS->FreePool(handles);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void _absolute_pointer_indev_event_cb(lv_event_t * e)
{
lv_indev_t * indev;
lv_uefi_absolute_pointer_context_t * indev_ctx;
if(lv_event_get_code(e) != LV_EVENT_DELETE) return;
indev = (lv_indev_t *)lv_event_get_user_data(e);
if(indev == NULL) return;
indev_ctx = (lv_uefi_absolute_pointer_context_t *)lv_indev_get_user_data(indev);
lv_indev_set_user_data(indev, NULL);
if(indev_ctx != NULL) _absolute_pointer_context_free(indev_ctx);
}
static void _absolute_pointer_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
{
void * node = NULL;
lv_uefi_absolute_pointer_context_t * indev_ctx = (lv_uefi_absolute_pointer_context_t *)lv_indev_get_user_data(indev);
LV_ASSERT_NULL(indev_ctx);
/* Read from all registered devices */
for(node = lv_ll_get_head(&indev_ctx->handles); node != NULL; node = lv_ll_get_next(&indev_ctx->handles, node)) {
lv_uefi_absolute_pointer_handle_context_t * handle_ctx = (lv_uefi_absolute_pointer_handle_context_t *) node;
bool was_pressed = false;
_absolute_pointer_read(indev_ctx, handle_ctx, &was_pressed);
data->state |= was_pressed ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
/* Sanitize the events position */
if(indev_ctx->position.x < 0) {
indev_ctx->position.x = 0;
}
else if(indev_ctx->position.x > indev_ctx->display_res.x - 1) {
indev_ctx->position.x = indev_ctx->display_res.x - 1;
}
if(indev_ctx->position.y < 0) {
indev_ctx->position.y = 0;
}
else if(indev_ctx->position.y > indev_ctx->display_res.y - 1) {
indev_ctx->position.y = indev_ctx->display_res.y - 1;
}
data->point.x = indev_ctx->position.x;
data->point.y = indev_ctx->position.y;
data->continue_reading = FALSE;
}
static void _absolute_pointer_context_free(lv_uefi_absolute_pointer_context_t * indev_ctx)
{
if(indev_ctx == NULL) return;
lv_ll_clear_custom(&indev_ctx->handles, _absolute_pointer_handle_context_free);
lv_free(indev_ctx);
}
static bool _absolute_pointer_interface_is_valid(const EFI_ABSOLUTE_POINTER_PROTOCOL * interface)
{
if(interface == NULL) return FALSE;
if(interface->Mode == NULL) return FALSE;
if(interface->Mode->AbsoluteMaxX <= interface->Mode->AbsoluteMinX) return FALSE;
if(interface->Mode->AbsoluteMaxY <= interface->Mode->AbsoluteMinY) return FALSE;
return TRUE;
}
static void _absolute_pointer_handle_context_free(void * ptr)
{
lv_uefi_absolute_pointer_handle_context_t * handle_ctx = (lv_uefi_absolute_pointer_handle_context_t *) ptr;
if(handle_ctx == NULL) return;
if(handle_ctx->interface) lv_uefi_protocol_close(handle_ctx->handle, &_uefi_guid_absolute_pointer);
lv_free(handle_ctx);
}
static void _absolute_pointer_read(lv_uefi_absolute_pointer_context_t * indev_ctx,
lv_uefi_absolute_pointer_handle_context_t * handle_ctx, bool * was_pressed)
{
EFI_STATUS status;
EFI_ABSOLUTE_POINTER_STATE state;
lv_point_t pointer_pos;
LV_ASSERT_NULL(indev_ctx);
LV_ASSERT_NULL(handle_ctx);
LV_ASSERT_NULL(was_pressed);
status = handle_ctx->interface->GetState(
handle_ctx->interface,
&state);
if(status == EFI_NOT_READY) return;
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] GetState failed.");
return;
}
/* verify the state */
if(state.CurrentX < handle_ctx->interface->Mode->AbsoluteMinX) return;
if(state.CurrentY < handle_ctx->interface->Mode->AbsoluteMinY) return;
pointer_pos.x = state.CurrentX - handle_ctx->interface->Mode->AbsoluteMinX;
pointer_pos.y = state.CurrentY - handle_ctx->interface->Mode->AbsoluteMinY;
indev_ctx->position.x = (pointer_pos.x * handle_ctx->factor_8.x) >> 8;
indev_ctx->position.y = (pointer_pos.y * handle_ctx->factor_8.y) >> 8;
/* Set the state to pressed if one of the interfaces reports a press */
*was_pressed = (state.ActiveButtons & EFI_ABSP_TouchActive) != 0;
}
#endif

View File

@ -0,0 +1,225 @@
/**
* @file lv_uefi_private.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_UEFI
#include "lv_uefi_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* GOLBAL VARIABLES
**********************/
EFI_HANDLE gLvEfiImageHandle = NULL;
EFI_SYSTEM_TABLE * gLvEfiST = NULL;
EFI_BOOT_SERVICES * gLvEfiBS = NULL;
EFI_RUNTIME_SERVICES * gLvEfiRT = NULL;
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* @brief Test if a protocol is installed at a handle.
* @param handle The handle on which the protocol might be installed.
* @param protocol The guid of the protocol.
* @return TRUE if the protocol is installed, FALSE if not.
*/
bool lv_uefi_protocol_test(EFI_HANDLE handle, EFI_GUID * protocol)
{
EFI_STATUS status;
void * interface = NULL;
if(handle == NULL) return false;
if(protocol == NULL) return false;
status = gLvEfiBS->OpenProtocol(
handle,
protocol,
&interface,
gLvEfiImageHandle,
NULL,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
if(status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
LV_LOG_WARN("couldn't test protocol");
return FALSE;
}
else if(status == EFI_UNSUPPORTED) {
return FALSE;
}
return TRUE;
}
/**
* @brief Open a protocol.
* @param handle The handle on which the protocol is installed.
* @param protocol The guid of the protocol.
* @return A pointer to the interface, NULL if the protocol couldn't be opened.
*/
void * lv_uefi_protocol_open(EFI_HANDLE handle, EFI_GUID * protocol)
{
EFI_STATUS status;
void * interface = NULL;
if(handle == NULL) return NULL;
if(protocol == NULL) return NULL;
status = gLvEfiBS->OpenProtocol(
handle,
protocol,
&interface,
gLvEfiImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if(status != EFI_SUCCESS) {
LV_LOG_ERROR("[lv_uefi] Couldn't open protocol %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X, error code: %llx.",
protocol->Data1,
protocol->Data2,
protocol->Data3,
protocol->Data4[0],
protocol->Data4[1],
protocol->Data4[2],
protocol->Data4[3],
protocol->Data4[4],
protocol->Data4[5],
protocol->Data4[6],
protocol->Data4[7],
status);
interface = NULL;
}
return interface;
}
/**
* @brief Close a protocol.
* @param handle The handle on which the protocol is installed.
* @param protocol The guid of the protocol.
*/
void lv_uefi_protocol_close(EFI_HANDLE handle, EFI_GUID * protocol)
{
EFI_STATUS status;
if(handle == NULL) return;
if(protocol == NULL) return;
status = gLvEfiBS->CloseProtocol(
handle,
protocol,
gLvEfiImageHandle,
NULL);
if(status != EFI_SUCCESS) {
LV_LOG_WARN("[lv_uefi] Couldn't close protocol %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X, error code: %llx.",
protocol->Data1,
protocol->Data2,
protocol->Data3,
protocol->Data4[0],
protocol->Data4[1],
protocol->Data4[2],
protocol->Data4[3],
protocol->Data4[4],
protocol->Data4[5],
protocol->Data4[6],
protocol->Data4[7],
status);
}
}
/**
* @brief Convert an UCS-2 string to an ASCII string.
* The string must contain only characters >= 0x20 and <= 0X7E.
* @param ucs2 The UCS-2 string.
* @param ascii The buffer to store the ASCII string.
* @param ascii_len The size of the buffer in ASCII characters.
* @return The number of characters written to the buffer or 0 if
* there was an error.
*/
size_t lv_uefi_ucs2_to_ascii(const CHAR16 * ucs2, char * ascii, size_t ascii_len)
{
size_t invalid_character_count;
size_t string_index;
if(ucs2 == NULL || ascii == NULL || ascii_len == 0) {
return 0;
}
invalid_character_count = 0;
for(string_index = 0; ucs2[string_index] != 0x0000 && string_index < ascii_len - 1; string_index++) {
if(ucs2[string_index] < 0x20 || ucs2[string_index] > 0x7E) {
invalid_character_count++;
}
ascii[string_index] = (char) ucs2[string_index];
}
/* terminate the string even if there was an error */
ascii[string_index] = 0x00;
return invalid_character_count == 0 ? string_index : 0;
}
/**
* @brief Convert an ASCII string to an UCS-2 string.
* The string must contain only characters >= 0x20 and <= 0X7E.
* @param ascii The ASCII string.
* @param ucs2 The buffer to store the UCS-2 string.
* @param ucs2_len The size of the buffer in UCS-2 characters.
* @return The number of bytes written to the buffer or 0 if
* there was an error.
*/
size_t lv_uefi_ascii_to_ucs2(const char * ascii, CHAR16 * ucs2, size_t ucs2_len)
{
size_t invalid_character_count;
size_t string_index;
if(ascii == NULL || ucs2 == NULL || ucs2_len == 0) {
return 0;
}
invalid_character_count = 0;
for(string_index = 0; ascii[string_index] != 0x0000 && string_index < ucs2_len - 1; string_index++) {
if(ascii[string_index] < 0x20 || ascii[string_index] > 0x7E) {
invalid_character_count++;
}
ucs2[string_index] = (CHAR16) ascii[string_index];
}
/* terminate the string even if there was an error */
ucs2[string_index] = 0x0000;
return invalid_character_count == 0 ? string_index : 0;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -0,0 +1,107 @@
/**
* @file lv_uefi_private.h
*
*/
#ifndef __LV_UEFI_PRIVATE_H__
#define __LV_UEFI_PRIVATE_H__
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_UEFI
#include "lv_uefi.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Internal cache for the image handle (source: application entry point)
*/
extern EFI_HANDLE gLvEfiImageHandle;
/**
* Internal cache for the system table (source: application entry point)
*/
extern EFI_SYSTEM_TABLE * gLvEfiST;
/**
* Internal cache for the boot services table (source: gLvEfiST)
*/
extern EFI_BOOT_SERVICES * gLvEfiBS;
/**
* Internal cache for the boot runtime service table (source: gLvEfiST)
*/
extern EFI_RUNTIME_SERVICES * gLvEfiRT;
/**
* @brief Test if a protocol is installed at a handle.
* @param handle The handle on which the protocol might be installed.
* @param protocol The guid of the protocol.
* @return TRUE if the protocol is installed, FALSE if not.
*/
bool lv_uefi_protocol_test(EFI_HANDLE handle, EFI_GUID * protocol);
/**
* @brief Open a protocol.
* @param handle The handle on which the protocol is installed.
* @param protocol The guid of the protocol.
* @return A pointer to the interface, NULL if the protocol couldn't be opened.
*/
void * lv_uefi_protocol_open(EFI_HANDLE handle, EFI_GUID * protocol);
/**
* @brief Close a protocol.
* @param handle The handle on which the protocol is installed.
* @param protocol The guid of the protocol.
*/
void lv_uefi_protocol_close(EFI_HANDLE handle, EFI_GUID * protocol);
/**
* @brief Convert an UCS-2 string to an ASCII string.
* The string must contain only characters >= 0x20 and <= 0X7E.
* @param ucs2 The UCS-2 string.
* @param ascii The buffer to store the ASCII string.
* @param ascii_len The size of the buffer in ASCII characters.
* @return The number of characters written to the buffer or 0 if
* there was an error.
*/
size_t lv_uefi_ucs2_to_ascii(const CHAR16 * ucs2, char * ascii, size_t ascii_len);
/**
* @brief Convert an ASCII string to an UCS-2 string.
* The string must contain only characters >= 0x20 and <= 0X7E.
* @param ascii The ASCII string.
* @param ucs2 The buffer to store the UCS-2 string.
* @param ucs2_len The size of the buffer in UCS-2 characters.
* @return The number of bytes written to the buffer or 0 if
* there was an error.
*/
size_t lv_uefi_ascii_to_ucs2(const char * ascii, CHAR16 * ucs2, size_t ucs2_len);
/**********************
* MACROS
**********************/
#endif
#ifdef __cplusplus
}
#endif
#endif //__LV_UEFI_PRIVATE_H__

View File

@ -0,0 +1,155 @@
/**
* @file lv_uefi_std_wrapper.h
*
*/
#ifndef LV_UEFI_STD_WRAPPER_H
#define LV_UEFI_STD_WRAPPER_H
#if LV_USE_UEFI
#include LV_USE_UEFI_INCLUDE
/*************************************
* TYPES
*************************************/
typedef UINT8 uint8_t;
typedef UINT16 uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
typedef INT8 int8_t;
typedef INT16 int16_t;
typedef INT32 int32_t;
typedef INT64 int64_t;
typedef uint32_t uint_fast32_t;
typedef UINTN uintptr_t;
typedef UINTN size_t;
typedef INTN intptr_t;
typedef INTN intmax_t;
typedef INTN ptrdiff_t;
typedef UINT8 bool;
/*************************************
* DEFINES
*************************************/
#define false 0
#define true 1
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "d"
#define PRId64 "d"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIu64 "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIx64 "x"
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIX32 "X"
#define PRIX64 "X"
/*************************************
* LIMITS
*************************************/
#ifndef INT8_MAX
#define INT8_MAX (0x7F)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (0xFF)
#endif
#ifndef INT16_MAX
#define INT16_MAX (0x7FFF)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (0xFFFF)
#endif
#ifndef INT32_MAX
#define INT32_MAX (0x7FFFFFFF)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (0xFFFFFFFF)
#endif
#ifndef INT64_MAX
#define INT64_MAX (0x7FFFFFFFFFFFFFFFULL)
#endif
#ifndef UINT64_MAX
#define UINT64_MAX (0xFFFFFFFFFFFFFFFFULL)
#endif
#ifndef INT_MAX
#define INT_MAX (0x7FFFFFFFFFFFFFFFULL)
#endif
#ifndef UINT_MAX
#define UINT_MAX (0xFFFFFFFFFFFFFFFFULL)
#endif
///
/// Minimum values for the signed UEFI Data Types
///
#ifndef INT8_MIN
#define INT8_MIN (( -127) - 1)
#endif
#ifndef INT16_MIN
#define INT16_MIN (( -32767) - 1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (( -2147483647) - 1)
#endif
#ifndef INT64_MIN
#define INT64_MIN (( -9223372036854775807LL) - 1)
#endif
#ifndef SIZE_MAX
#define SIZE_MAX (0xFFFFFFFF)
#endif
#ifndef LONG_MAX
#define LONG_MAX (0x7FFFFFFF)
#endif
#ifndef ULONG_MAX
#define ULONG_MAX (0xFFFFFFFF)
#endif
#ifndef USHRT_MAX
#define USHRT_MAX (0xFFFF)
#endif
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
/*************************************
* VA_ARG
*************************************/
#if LV_UEFI_EDK2_HEADERS
#define va_list VA_LIST
#define va_start(Marker, Parameter) VA_START(Marker, Parameter)
#define va_arg(Marker, TYPE) VA_ARG(Marker, TYPE)
#define va_end(Marker) VA_END(Marker)
#define va_copy(Dest, Start) VA_COPY(Dest, Start)
#endif
#endif
#endif

607
src/libs/fsdrv/lv_fs_uefi.c Normal file
View File

@ -0,0 +1,607 @@
/**
* @file lv_fs_uefi.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_FS_UEFI && LV_USE_UEFI
#include "../../drivers/uefi/lv_uefi_private.h"
#include "../../core/lv_global.h"
/*********************
* DEFINES
*********************/
#if LV_FS_UEFI_LETTER == '\0'
#error "LV_FS_UEFI_LETTER must be set to a valid value"
#else
#if (LV_FS_UEFI_LETTER < 'A') || (LV_FS_UEFI_LETTER > 'Z')
#if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/
#error "LV_FS_UEFI_LETTER must be an upper case ASCII letter"
#else /*Lean rules for backward compatibility*/
#warning LV_FS_UEFI_LETTER should be an upper case ASCII letter. \
Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism
#endif
#endif
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_uefi_fs_file_context_t {
EFI_FILE_PROTOCOL * interface;
} lv_uefi_fs_file_context_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_fs_drv_uefi_init(lv_fs_drv_t * drv, char fs_drive_letter, EFI_HANDLE fs_handle);
static void lv_fs_drv_uefi_deinit(lv_fs_drv_t * drv);
static void lv_fs_uefi_lvgl_path_to_uefi_path(CHAR16 * path);
static void lv_fs_uefi_uefi_path_to_lvgl_path(CHAR16 * path);
static bool lv_fs_uefi_is_dot_path(CONST CHAR16 * path);
static bool lv_fs_uefi_is_dir(EFI_FILE_PROTOCOL * dir);
static bool lv_fs_uefi_is_file(EFI_FILE_PROTOCOL * file);
static EFI_FILE_INFO * lv_fs_uefi_get_info(EFI_FILE_PROTOCOL * file);
static bool lv_fs_uefi_ready_cb(lv_fs_drv_t * drv);
static void * lv_fs_uefi_open_cb(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t lv_fs_uefi_close_cb(lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t lv_fs_uefi_read_cb(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t lv_fs_uefi_write_cb(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t lv_fs_uefi_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t lv_fs_uefi_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static void * lv_fs_uefi_dir_open_cb(lv_fs_drv_t * drv, const char * path);
static lv_fs_res_t lv_fs_uefi_dir_read_cb(lv_fs_drv_t * drv, void * rddir_p, char * fn, uint32_t fn_len);
static lv_fs_res_t lv_fs_uefi_dir_close_cb(lv_fs_drv_t * drv, void * rddir_p);
/**********************
* STATIC VARIABLES
**********************/
static EFI_GUID _uefi_guid_simple_file_system = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
static EFI_GUID _uefi_guid_loaded_image = EFI_LOADED_IMAGE_PROTOCOL_GUID;
static EFI_GUID _uefi_guid_file_info = EFI_FILE_INFO_ID;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register a driver for the File system interface
*/
void lv_fs_uefi_init(void)
{
EFI_LOADED_IMAGE_PROTOCOL * interface_loaded_image = NULL;
EFI_HANDLE fs_handle = NULL;
/*---------------------------------------------------
* Register the file system interface in LVGL
*--------------------------------------------------*/
interface_loaded_image = lv_uefi_protocol_open(gLvEfiImageHandle, &_uefi_guid_loaded_image);
LV_ASSERT_NULL(interface_loaded_image);
fs_handle = interface_loaded_image->DeviceHandle;
if(fs_handle == NULL) return;
lv_uefi_protocol_close(gLvEfiImageHandle, &_uefi_guid_loaded_image);
/*Add a simple driver to open images*/
lv_fs_drv_t * fs_drv_p = &(LV_GLOBAL_DEFAULT()->uefi_fs_drv);
lv_fs_drv_uefi_init(fs_drv_p, LV_FS_UEFI_LETTER, fs_handle);
lv_fs_drv_register(fs_drv_p);
}
/**********************
* STATIC FUNCTIONS
**********************/
static bool lv_fs_uefi_ready_cb(lv_fs_drv_t * drv)
{
EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
return fs_handle != NULL;
}
static void * lv_fs_uefi_open_cb(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
EFI_STATUS status;
EFI_FILE_PROTOCOL * fs_root = NULL;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * fs_interface = NULL;
CHAR16 path_ucs2[LV_FS_MAX_PATH_LENGTH + 1];
lv_uefi_fs_file_context_t * file_ctx = NULL;
UINT64 uefi_mode = 0;
EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
fs_interface = lv_uefi_protocol_open(fs_handle, &_uefi_guid_simple_file_system);
if(fs_interface == NULL) {
LV_LOG_WARN("[lv_uefi] Unable to open file system protocol.");
goto error;
}
status = fs_interface->OpenVolume(fs_interface, &fs_root);
if(status != EFI_SUCCESS) {
LV_LOG_WARN("[lv_uefi] Unable to open file system root.");
goto error;
}
if(lv_uefi_ascii_to_ucs2(path, path_ucs2, LV_FS_MAX_PATH_LENGTH + 1) == 0) {
LV_LOG_WARN("[lv_uefi] Unable to convert the ASCII path into an UCS-2 path.");
goto error;
}
lv_fs_uefi_lvgl_path_to_uefi_path(path_ucs2);
file_ctx = lv_calloc(1, sizeof(lv_uefi_fs_file_context_t));
LV_ASSERT_MALLOC(file_ctx);
if(mode == LV_FS_MODE_WR) {
uefi_mode = EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE;
}
else {
uefi_mode = EFI_FILE_MODE_READ;
}
status = fs_root->Open(
fs_root,
&file_ctx->interface,
path_ucs2,
uefi_mode,
0);
if(status != EFI_SUCCESS) {
LV_LOG_WARN("[lv_uefi] Unable to open file '%s'.", path);
goto error;
}
if(!lv_fs_uefi_is_file(file_ctx->interface)) {
goto error;
}
goto finish;
error:
if(file_ctx != NULL) {
if(file_ctx->interface != NULL) file_ctx->interface->Close(file_ctx->interface);
lv_free(file_ctx);
file_ctx = NULL;
}
finish:
if(fs_interface != NULL) lv_uefi_protocol_close(fs_handle, &_uefi_guid_simple_file_system);
if(fs_root != NULL) fs_root->Close(fs_root);
return file_ctx;
}
static lv_fs_res_t lv_fs_uefi_close_cb(lv_fs_drv_t * drv, void * file_p)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
status = file_ctx->interface->Close(file_ctx->interface);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
lv_free(file_ctx);
return LV_FS_RES_OK;
}
static lv_fs_res_t lv_fs_uefi_read_cb(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
UINTN buf_size = btr;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
status = file_ctx->interface->Read(
file_ctx->interface,
&buf_size,
buf);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
*br = (uint32_t) buf_size;
return LV_FS_RES_OK;
}
static lv_fs_res_t lv_fs_uefi_write_cb(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
UINTN buf_size = btw;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
status = file_ctx->interface->Write(
file_ctx->interface,
&buf_size,
(VOID *)buf);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
file_ctx->interface->Flush(file_ctx->interface);
*bw = (uint32_t) buf_size;
return LV_FS_RES_OK;
}
static lv_fs_res_t lv_fs_uefi_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
UINT64 new_pos;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
if(whence == LV_FS_SEEK_END) {
status = file_ctx->interface->SetPosition(
file_ctx->interface,
UINT64_MAX);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
status = file_ctx->interface->GetPosition(
file_ctx->interface,
&new_pos);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
if(new_pos < pos) {
new_pos = 0;
}
else {
new_pos -= pos;
}
}
else if(whence == LV_FS_SEEK_SET) {
new_pos = pos;
}
else if(whence == LV_FS_SEEK_CUR) {
status = file_ctx->interface->GetPosition(
file_ctx->interface,
&new_pos);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
new_pos += pos;
}
else {
return LV_FS_RES_INV_PARAM;
}
status = file_ctx->interface->SetPosition(
file_ctx->interface,
new_pos);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
return LV_FS_RES_OK;
}
static lv_fs_res_t lv_fs_uefi_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
UINT64 pos;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
status = file_ctx->interface->GetPosition(
file_ctx->interface,
&pos);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
if(pos > UINT32_MAX) return LV_FS_RES_UNKNOWN;
*pos_p = (uint32_t) pos;
return LV_FS_RES_OK;
}
static void * lv_fs_uefi_dir_open_cb(lv_fs_drv_t * drv, const char * path)
{
EFI_STATUS status;
EFI_FILE_PROTOCOL * fs_root = NULL;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * fs_interface = NULL;
CHAR16 path_ucs2[LV_FS_MAX_PATH_LENGTH + 1];
lv_uefi_fs_file_context_t * file_ctx = NULL;
UINT64 mode = 0;
UINT64 attributes = 0;
EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
fs_interface = lv_uefi_protocol_open(fs_handle, &_uefi_guid_simple_file_system);
if(fs_interface == NULL) {
LV_LOG_WARN("[lv_uefi] Unable to open file system protocol.");
goto error;
}
status = fs_interface->OpenVolume(fs_interface, &fs_root);
if(status != EFI_SUCCESS) {
LV_LOG_WARN("[lv_uefi] Unable to open file system root.");
goto error;
}
if(path != NULL && path[0] != '\0') {
if(lv_uefi_ascii_to_ucs2(path, path_ucs2, LV_FS_MAX_PATH_LENGTH + 1) == 0) {
LV_LOG_WARN("[lv_uefi] Unable to convert the ASCII path into an UCS-2 path.");
goto error;
}
}
else {
path_ucs2[0] = '\\';
path_ucs2[1] = '\0';
}
lv_fs_uefi_lvgl_path_to_uefi_path(path_ucs2);
file_ctx = lv_calloc(1, sizeof(lv_uefi_fs_file_context_t));
LV_ASSERT_MALLOC(file_ctx);
mode = EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE;
attributes = EFI_FILE_DIRECTORY;
status = fs_root->Open(
fs_root,
&file_ctx->interface,
path_ucs2,
mode,
attributes);
if(status != EFI_SUCCESS) {
LV_LOG_WARN("[lv_uefi] Unable to open directory '%s'.", path);
goto error;
}
if(!lv_fs_uefi_is_dir(file_ctx->interface)) {
goto error;
}
goto finish;
error:
if(file_ctx != NULL) {
if(file_ctx->interface != NULL) {
file_ctx->interface->Close(file_ctx->interface);
}
lv_free(file_ctx);
file_ctx = NULL;
}
finish:
if(fs_interface != NULL) lv_uefi_protocol_close(fs_handle, &_uefi_guid_simple_file_system);
if(fs_root != NULL) fs_root->Close(fs_root);
return file_ctx;
}
static lv_fs_res_t lv_fs_uefi_dir_read_cb(lv_fs_drv_t * drv, void * rddir_p, char * fn, uint32_t fn_len)
{
lv_fs_res_t return_code;
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)rddir_p;
EFI_FILE_INFO * info = NULL;
UINTN size;
CONST CHAR16 * fn_ucs2;
if(fn == NULL || fn_len == 0) return LV_FS_RES_INV_PARAM;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
// skip . and ..
do {
if(info != NULL) lv_free(info);
info = NULL;
size = 0;
status = file_ctx->interface->Read(
file_ctx->interface,
&size,
info);
if(status == EFI_SUCCESS && size == 0) {
return_code = LV_FS_RES_OK;
*fn = '\0';
goto finish;
}
else if(status != EFI_BUFFER_TOO_SMALL) {
return_code = LV_FS_RES_NOT_EX;
goto error;
}
info = lv_calloc(1, size);
LV_ASSERT_MALLOC(info);
status = file_ctx->interface->Read(
file_ctx->interface,
&size,
info);
if(status != EFI_SUCCESS) {
return_code = LV_FS_RES_HW_ERR;
goto error;
}
} while(lv_fs_uefi_is_dot_path(info->FileName));
lv_fs_uefi_uefi_path_to_lvgl_path(info->FileName);
// skip leading \ and /
for(fn_ucs2 = info->FileName; *fn_ucs2 != L'\0'; fn_ucs2++) {
if(*fn_ucs2 != L'\\' && *fn_ucs2 != L'/') {
break;
}
}
if((info->Attribute & EFI_FILE_DIRECTORY) != 0) {
if(fn_len == 0) {
return_code = LV_FS_RES_UNKNOWN;
goto error;
}
fn[0] = '/';
fn++;
fn_len--;
}
if(lv_uefi_ucs2_to_ascii(fn_ucs2, fn, fn_len) == 0) {
LV_LOG_WARN("[lv_uefi] Unable to convert the UCS-2 path into an ascii path.");
return_code = LV_FS_RES_UNKNOWN;
goto error;
}
return_code = LV_FS_RES_OK;
goto finish;
error:
finish:
if(info) lv_free(info);
return return_code;
}
static lv_fs_res_t lv_fs_uefi_dir_close_cb(lv_fs_drv_t * drv, void * rddir_p)
{
EFI_STATUS status;
lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)rddir_p;
if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
status = file_ctx->interface->Close(file_ctx->interface);
if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
lv_free(file_ctx);
return LV_FS_RES_OK;
}
static void lv_fs_drv_uefi_init(lv_fs_drv_t * drv, char fs_drive_letter, EFI_HANDLE fs_handle)
{
LV_ASSERT_NULL(drv);
LV_ASSERT_NULL(fs_handle);
lv_fs_drv_init(drv);
drv->letter = fs_drive_letter;
drv->cache_size = 0;
drv->ready_cb = lv_fs_uefi_ready_cb;
drv->open_cb = lv_fs_uefi_open_cb;
drv->close_cb = lv_fs_uefi_close_cb;
drv->read_cb = lv_fs_uefi_read_cb;
drv->write_cb = lv_fs_uefi_write_cb;
drv->seek_cb = lv_fs_uefi_seek_cb;
drv->tell_cb = lv_fs_uefi_tell_cb;
drv->dir_open_cb = lv_fs_uefi_dir_open_cb;
drv->dir_read_cb = lv_fs_uefi_dir_read_cb;
drv->dir_close_cb = lv_fs_uefi_dir_close_cb;
drv->user_data = (void *) fs_handle;
}
static void lv_fs_drv_uefi_deinit(lv_fs_drv_t * drv)
{
LV_ASSERT_NULL(drv);
drv->user_data = NULL;
}
static void lv_fs_uefi_lvgl_path_to_uefi_path(CHAR16 * path)
{
if(path == NULL) return;
for(; *path != '\0'; path++) {
if(*path == L'/') *path = L'\\';
}
}
static void lv_fs_uefi_uefi_path_to_lvgl_path(CHAR16 * path)
{
if(path == NULL) return;
for(; *path != '\0'; path++) {
if(*path == L'\\') *path = L'/';
}
}
static bool lv_fs_uefi_is_dot_path(CONST CHAR16 * path)
{
if(path == NULL) return FALSE;
if(path[0] == L'.' && path[1] == L'\0') return TRUE;
if(path[0] == L'.' && path[1] == L'.' && path[2] == L'\0') return TRUE;
return FALSE;
}
static bool lv_fs_uefi_is_dir(EFI_FILE_PROTOCOL * dir)
{
UINT64 attributes;
if(dir == NULL) return FALSE;
EFI_FILE_INFO * info = lv_fs_uefi_get_info(dir);
if(info == NULL) return FALSE;
attributes = info->Attribute;
lv_free(info);
return (attributes & EFI_FILE_DIRECTORY) != 0;
}
static bool lv_fs_uefi_is_file(EFI_FILE_PROTOCOL * file)
{
UINT64 attributes;
if(file == NULL) return FALSE;
EFI_FILE_INFO * info = lv_fs_uefi_get_info(file);
if(info == NULL) return FALSE;
attributes = info->Attribute;
lv_free(info);
return (attributes & EFI_FILE_DIRECTORY) == 0;
}
static EFI_FILE_INFO * lv_fs_uefi_get_info(EFI_FILE_PROTOCOL * file)
{
EFI_STATUS status;
EFI_FILE_INFO * info = NULL;
UINTN size = 0;
status = file->GetInfo(file, &_uefi_guid_file_info, &size, info);
if(status != EFI_BUFFER_TOO_SMALL) return NULL;
info = lv_calloc(1, size);
LV_ASSERT_MALLOC(info);
status = file->GetInfo(file, &_uefi_guid_file_info, &size, info);
if(status != EFI_SUCCESS) {
lv_free(info);
return NULL;
}
return info;
}
#else /* LV_FS_UEFI_LETTER == 0*/
#if defined(LV_FS_UEFI_LETTER) && LV_FS_UEFI_LETTER != '\0'
#warning "LV_FS_UEFI is not enabled but LV_FS_UEFI_LETTER is set"
#endif
#endif

View File

@ -63,6 +63,10 @@ void lv_fs_arduino_esp_littlefs_init(void);
void lv_fs_arduino_sd_init(void); void lv_fs_arduino_sd_init(void);
#endif #endif
#if LV_USE_FS_UEFI
void lv_fs_uefi_init(void);
#endif
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/

View File

@ -2749,6 +2749,24 @@
#endif #endif
#endif #endif
/** API for UEFI */
#ifndef LV_USE_FS_UEFI
#ifdef CONFIG_LV_USE_FS_UEFI
#define LV_USE_FS_UEFI CONFIG_LV_USE_FS_UEFI
#else
#define LV_USE_FS_UEFI 0
#endif
#endif
#if LV_USE_FS_UEFI
#ifndef LV_FS_UEFI_LETTER
#ifdef CONFIG_LV_FS_UEFI_LETTER
#define LV_FS_UEFI_LETTER CONFIG_LV_FS_UEFI_LETTER
#else
#define LV_FS_UEFI_LETTER '\0' /**< Set an upper cased letter on which the drive will accessible (e.g. 'A') */
#endif
#endif
#endif
/** LODEPNG decoder library */ /** LODEPNG decoder library */
#ifndef LV_USE_LODEPNG #ifndef LV_USE_LODEPNG
#ifdef CONFIG_LV_USE_LODEPNG #ifdef CONFIG_LV_USE_LODEPNG
@ -3901,6 +3919,31 @@
#endif #endif
#endif #endif
/** LVGL UEFI backend */
#ifndef LV_USE_UEFI
#ifdef CONFIG_LV_USE_UEFI
#define LV_USE_UEFI CONFIG_LV_USE_UEFI
#else
#define LV_USE_UEFI 0
#endif
#endif
#if LV_USE_UEFI
#ifndef LV_USE_UEFI_INCLUDE
#ifdef CONFIG_LV_USE_UEFI_INCLUDE
#define LV_USE_UEFI_INCLUDE CONFIG_LV_USE_UEFI_INCLUDE
#else
#define LV_USE_UEFI_INCLUDE "myefi.h" /**< Header that hides the actual framework (EDK2, gnu-efi, ...) */
#endif
#endif
#ifndef LV_UEFI_USE_MEMORY_SERVICES
#ifdef CONFIG_LV_UEFI_USE_MEMORY_SERVICES
#define LV_UEFI_USE_MEMORY_SERVICES CONFIG_LV_UEFI_USE_MEMORY_SERVICES
#else
#define LV_UEFI_USE_MEMORY_SERVICES 0 /**< Use the memory functions from the boot services table */
#endif
#endif
#endif
/** Use OpenGL to open window on PC and handle mouse and keyboard */ /** Use OpenGL to open window on PC and handle mouse and keyboard */
#ifndef LV_USE_OPENGLES #ifndef LV_USE_OPENGLES
#ifdef CONFIG_LV_USE_OPENGLES #ifdef CONFIG_LV_USE_OPENGLES

View File

@ -70,6 +70,9 @@
#if LV_USE_WINDOWS #if LV_USE_WINDOWS
#include "drivers/windows/lv_windows_context.h" #include "drivers/windows/lv_windows_context.h"
#endif #endif
#if LV_USE_UEFI
#include "drivers/uefi/lv_uefi_context.h"
#endif
/********************* /*********************
* DEFINES * DEFINES
@ -247,6 +250,10 @@ void lv_init(void)
lv_windows_platform_init(); lv_windows_platform_init();
#endif #endif
#if LV_USE_UEFI
lv_uefi_platform_init();
#endif
lv_obj_style_init(); lv_obj_style_init();
/*Initialize the screen refresh system*/ /*Initialize the screen refresh system*/
@ -332,6 +339,10 @@ void lv_init(void)
lv_fs_arduino_sd_init(); lv_fs_arduino_sd_init();
#endif #endif
#if LV_USE_FS_UEFI
lv_fs_uefi_init();
#endif
#if LV_USE_LODEPNG #if LV_USE_LODEPNG
lv_lodepng_init(); lv_lodepng_init();
#endif #endif
@ -413,6 +424,10 @@ void lv_deinit(void)
lv_obj_style_deinit(); lv_obj_style_deinit();
#if LV_USE_UEFI
lv_uefi_platform_deinit();
#endif
#if LV_USE_PXP #if LV_USE_PXP
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP #if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
lv_draw_pxp_deinit(); lv_draw_pxp_deinit();

View File

@ -0,0 +1,116 @@
/**
* @file lv_mem_core_uefi.c
*/
/*********************
* INCLUDES
*********************/
#include "../lv_mem.h"
#if LV_USE_UEFI
#if LV_UEFI_USE_MEMORY_SERVICES && LV_USE_STDLIB_MALLOC == LV_STDLIB_CUSTOM
#include "../drivers/uefi/lv_uefi_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
typedef struct _mem_header_t {
size_t size;
uint8_t data[0];
} mem_header_t;
void lv_mem_init(void)
{
LV_ASSERT_NULL(gLvEfiBS);
return; /*Nothing to init*/
}
void lv_mem_deinit(void)
{
return; /*Nothing to deinit*/
}
void * lv_malloc_core(size_t size)
{
size_t size_with_header = size + sizeof(mem_header_t);
mem_header_t * ptr = NULL;
if(gLvEfiBS->AllocatePool(EfiBootServicesData, size_with_header, (void **)&ptr) != EFI_SUCCESS) return NULL;
ptr->size = size;
return ptr->data;
}
void * lv_realloc_core(void * p, size_t new_size)
{
mem_header_t * p_header = NULL;
uintptr_t p_address = (uintptr_t)p;
void * p_new = NULL;
if(p == NULL) return lv_malloc_core(new_size);
// Check for invalid pointers
if(p_address < sizeof(mem_header_t)) return NULL;
p_address -= sizeof(mem_header_t);
p_header = (mem_header_t *) p_address;
// UEFI supportes no realloc, if the size grows a new memory block has to be allocated
if(p_header->size > new_size) return p;
p_new = lv_malloc_core(new_size);
lv_memcpy(p_new, p, p_header->size);
lv_free_core(p);
return p_new;
}
void lv_free_core(void * p)
{
uintptr_t p_address = (uintptr_t)p;
if(p_address < sizeof(mem_header_t)) return;
p_address -= sizeof(mem_header_t);
gLvEfiBS->FreePool((void *)p_address);
}
void lv_mem_monitor_core(lv_mem_monitor_t * mon_p)
{
/*Not supported*/
LV_UNUSED(mon_p);
return;
}
lv_result_t lv_mem_test_core(void)
{
/*Not supported*/
return LV_RESULT_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif
#endif