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:
parent
f47879b67e
commit
20bfb4855b
21
Kconfig
21
Kconfig
@ -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
|
||||
|
@ -14,3 +14,4 @@ Drivers
|
||||
wayland
|
||||
windows
|
||||
X11
|
||||
uefi
|
||||
|
121
docs/details/integration/driver/uefi.rst
Normal file
121
docs/details/integration/driver/uefi.rst
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
106
src/drivers/uefi/lv_uefi.h
Normal 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
|
91
src/drivers/uefi/lv_uefi_context.c
Normal file
91
src/drivers/uefi/lv_uefi_context.c
Normal 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
|
71
src/drivers/uefi/lv_uefi_context.h
Normal file
71
src/drivers/uefi/lv_uefi_context.h
Normal 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__
|
284
src/drivers/uefi/lv_uefi_display.c
Normal file
284
src/drivers/uefi/lv_uefi_display.c
Normal 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
|
65
src/drivers/uefi/lv_uefi_display.h
Normal file
65
src/drivers/uefi/lv_uefi_display.h
Normal 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__
|
28
src/drivers/uefi/lv_uefi_edk2.h
Normal file
28
src/drivers/uefi/lv_uefi_edk2.h
Normal 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
|
17
src/drivers/uefi/lv_uefi_gnu_efi.h
Normal file
17
src/drivers/uefi/lv_uefi_gnu_efi.h
Normal 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
|
108
src/drivers/uefi/lv_uefi_indev.h
Normal file
108
src/drivers/uefi/lv_uefi_indev.h
Normal 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__
|
346
src/drivers/uefi/lv_uefi_indev_keyboard.c
Normal file
346
src/drivers/uefi/lv_uefi_indev_keyboard.c
Normal 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
|
285
src/drivers/uefi/lv_uefi_indev_pointer.c
Normal file
285
src/drivers/uefi/lv_uefi_indev_pointer.c
Normal 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
|
290
src/drivers/uefi/lv_uefi_indev_touch.c
Normal file
290
src/drivers/uefi/lv_uefi_indev_touch.c
Normal 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
|
225
src/drivers/uefi/lv_uefi_private.c
Normal file
225
src/drivers/uefi/lv_uefi_private.c
Normal 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
|
107
src/drivers/uefi/lv_uefi_private.h
Normal file
107
src/drivers/uefi/lv_uefi_private.h
Normal 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__
|
155
src/drivers/uefi/lv_uefi_std_wrapper.h
Normal file
155
src/drivers/uefi/lv_uefi_std_wrapper.h
Normal 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
607
src/libs/fsdrv/lv_fs_uefi.c
Normal 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
|
@ -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
|
||||
**********************/
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
116
src/stdlib/uefi/lv_mem_core_uefi.c
Normal file
116
src/stdlib/uefi/lv_mem_core_uefi.c
Normal 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
|
Loading…
x
Reference in New Issue
Block a user