1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03: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"
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
bool "PNG decoder library"
@ -1938,6 +1945,20 @@ menu "LVGL configuration"
depends on LV_OS_WINDOWS
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
bool "Use GLFW and OpenGL to open window on PC and handle mouse and keyboard"
default n

View File

@ -14,3 +14,4 @@ Drivers
wayland
windows
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. */
#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 */
#define LV_USE_LODEPNG 0
@ -1206,6 +1212,13 @@
/** LVGL Windows backend */
#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 */
#define LV_USE_OPENGLES 0
#if LV_USE_OPENGLES

View File

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

View File

@ -54,6 +54,10 @@ extern "C" {
#include "wayland/lv_wayland.h"
#include "uefi/lv_uefi_context.h"
#include "uefi/lv_uefi_indev.h"
#include "uefi/lv_uefi_display.h"
/*********************
* 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);
#endif
#if LV_USE_FS_UEFI
void lv_fs_uefi_init(void);
#endif
/**********************
* MACROS
**********************/

View File

@ -2749,6 +2749,24 @@
#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 */
#ifndef LV_USE_LODEPNG
#ifdef CONFIG_LV_USE_LODEPNG
@ -3901,6 +3919,31 @@
#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 */
#ifndef LV_USE_OPENGLES
#ifdef CONFIG_LV_USE_OPENGLES

View File

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