From 6eaea5ca33cfaeea7a7fc9434e082ce1a9e0c6c5 Mon Sep 17 00:00:00 2001 From: Malte Voos Date: Wed, 3 Apr 2024 18:12:50 +0200 Subject: init --- fakefbdev/FakeFBDev.cpp | 59 +++++++++++++ fakefbdev/IOCTL.cpp | 43 ++++++++++ fakefbdev/IOCTL.h | 3 + fakefbdev/Makefile | 5 ++ fakefbdev/SharedBuffer.cpp | 46 +++++++++++ fakefbdev/SharedBuffer.h | 38 +++++++++ fakefbdev/mxcfb.h | 201 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 395 insertions(+) create mode 100644 fakefbdev/FakeFBDev.cpp create mode 100644 fakefbdev/IOCTL.cpp create mode 100644 fakefbdev/IOCTL.h create mode 100644 fakefbdev/Makefile create mode 100644 fakefbdev/SharedBuffer.cpp create mode 100644 fakefbdev/SharedBuffer.h create mode 100644 fakefbdev/mxcfb.h (limited to 'fakefbdev') diff --git a/fakefbdev/FakeFBDev.cpp b/fakefbdev/FakeFBDev.cpp new file mode 100644 index 0000000..a37b0a0 --- /dev/null +++ b/fakefbdev/FakeFBDev.cpp @@ -0,0 +1,59 @@ +#include "IOCTL.h" +#include "SharedBuffer.h" + +#include +#include +#include +#include +#include + +SharedFB fb(default_fb_name); + +extern "C" { + +int +open64(const char* pathname, int flags, mode_t mode = 0) { + if (pathname == std::string("/dev/fb0")) { + return fb.fd; + } + + static const auto func_open = + (int (*)(const char*, int, mode_t))dlsym(RTLD_NEXT, "open64"); + + return func_open(pathname, flags, mode); +} + +int +open(const char* pathname, int flags, mode_t mode = 0) { + if (pathname == std::string("/dev/fb0")) { + return fb.fd; + } + + static const auto func_open = + (int (*)(const char*, int, mode_t))dlsym(RTLD_NEXT, "open"); + + return func_open(pathname, flags, mode); +} + +int +close(int fd) { + if (fd == fb.fd) { + return 0; + } + + static const auto func_close = (int (*)(int))dlsym(RTLD_NEXT, "close"); + return func_close(fd); +} + +int +ioctl(int fd, unsigned long request, char* ptr) { + if (fd == fb.fd) { + return handleIOCTL(request, ptr); + } + + static auto func_ioctl = + (int (*)(int, unsigned long request, ...))dlsym(RTLD_NEXT, "ioctl"); + + return func_ioctl(fd, request, ptr); +} +} diff --git a/fakefbdev/IOCTL.cpp b/fakefbdev/IOCTL.cpp new file mode 100644 index 0000000..90e2583 --- /dev/null +++ b/fakefbdev/IOCTL.cpp @@ -0,0 +1,43 @@ +#include "IOCTL.h" +#include "SharedBuffer.h" + +#include +#include + +#include "mxcfb.h" + +int +handleIOCTL(unsigned long request, char* ptr) { + if (request == FBIOGET_VSCREENINFO) { + + fb_var_screeninfo* screeninfo = (fb_var_screeninfo*)ptr; + screeninfo->xres = fb_width; + screeninfo->yres = fb_height; + screeninfo->grayscale = 0; + screeninfo->bits_per_pixel = 8 * fb_pixel_size; + screeninfo->xres_virtual = fb_width; + screeninfo->yres_virtual = fb_height; + + // set to RGB565 + screeninfo->red.offset = 11; + screeninfo->red.length = 5; + screeninfo->green.offset = 5; + screeninfo->green.length = 6; + screeninfo->blue.offset = 0; + screeninfo->blue.length = 5; + + return 0; + } else if (request == FBIOGET_FSCREENINFO) { + + fb_fix_screeninfo* screeninfo = (fb_fix_screeninfo*)ptr; + screeninfo->smem_len = fb_size; + screeninfo->smem_start = (unsigned long)0x1000; + screeninfo->line_length = fb_width * fb_pixel_size; + constexpr char fb_id[] = "mxcfb"; + std::memcpy(screeninfo->id, fb_id, sizeof(fb_id)); + + return 0; + } else { + return 0; + } +} diff --git a/fakefbdev/IOCTL.h b/fakefbdev/IOCTL.h new file mode 100644 index 0000000..423531a --- /dev/null +++ b/fakefbdev/IOCTL.h @@ -0,0 +1,3 @@ +#pragma once + +int handleIOCTL(unsigned long request, char* ptr); diff --git a/fakefbdev/Makefile b/fakefbdev/Makefile new file mode 100644 index 0000000..516802f --- /dev/null +++ b/fakefbdev/Makefile @@ -0,0 +1,5 @@ +libfakefbdev.so: + $(CXX) -fPIC FakeFBDev.cpp IOCTL.cpp SharedBuffer.cpp -shared -o libfakefbdev.so + +install: + install -Dm755 libfakefbdev.so $(DESTDIR)/lib/libfakefbdev.so diff --git a/fakefbdev/SharedBuffer.cpp b/fakefbdev/SharedBuffer.cpp new file mode 100644 index 0000000..fbc3121 --- /dev/null +++ b/fakefbdev/SharedBuffer.cpp @@ -0,0 +1,46 @@ +#include "SharedBuffer.h" + +#include +#include +#include +#include +#include +#include +#include + +SharedFB::SharedFB(const char* path) : fd(shm_open(path, O_RDWR, 0755)) { + if (fd == -1) { + fd = shm_open(path, O_RDWR | O_CREAT, 0755); + } + + if (fd < 0) { + perror("Can't open shm"); + return; + } + + ftruncate(fd, fb_size); + mem = (uint16_t*)mmap(nullptr, fb_size, PROT_WRITE, MAP_SHARED, fd, 0); +} + +SharedFB::~SharedFB() { + if (mem != nullptr) { + munmap(mem, fb_size); + } +} + +SharedFB::SharedFB(SharedFB&& other) noexcept : fd(other.fd), mem(other.mem) { + other.fd = -1; + other.mem = nullptr; +} + +SharedFB& +SharedFB::operator=(SharedFB&& other) noexcept { + // TODO: release + this->fd = other.fd; + this->mem = other.mem; + + other.fd = -1; + other.mem = nullptr; + + return *this; +} diff --git a/fakefbdev/SharedBuffer.h b/fakefbdev/SharedBuffer.h new file mode 100644 index 0000000..8c96668 --- /dev/null +++ b/fakefbdev/SharedBuffer.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +constexpr int fb_width = 1404; +constexpr int fb_height = 1872; +constexpr int fb_pixel_size = sizeof(uint16_t); + +// this is the number of bytes that xochitl mmaps() from the framebuffer. +// MIGHT CHANGE BETWEEN XOCHITL VERSIONS! +// the below value was extracted from xochitl 3.10.2.2063. +// +// to figure out this value, decompile xochitl using ghidra and +// - search for the string "Error writing variable information" +// - this string should be used in a call to perror() which is contained +// in the if-part of a branch +// - look for the corresponding else-branch: the first statement should be +// a call to mmap() with the below size. +// (of course, these instruction might become outdated if remarkable folks +// rewrite this part of xochitl :/) +constexpr int fb_size = 0x17bd800; + +constexpr auto default_fb_name = "/rm2fb.01"; + +// TODO: use unistdpp +struct SharedFB { + int fd = -1; + uint16_t* mem = nullptr; + + SharedFB(const char* path); + ~SharedFB(); + + SharedFB(const SharedFB& other) = delete; + SharedFB& operator=(const SharedFB& other) = delete; + + SharedFB(SharedFB&& other) noexcept; + SharedFB& operator=(SharedFB&& other) noexcept; +}; diff --git a/fakefbdev/mxcfb.h b/fakefbdev/mxcfb.h new file mode 100644 index 0000000..3e05795 --- /dev/null +++ b/fakefbdev/mxcfb.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * @file uapi/linux/mxcfb.h + * + * @brief Global header file for the MXC frame buffer + * + * @ingroup Framebuffer + */ +#ifndef __ASM_ARCH_MXCFB_H__ +#define __ASM_ARCH_MXCFB_H__ + +#include +#include + +#define FB_SYNC_OE_LOW_ACT 0x80000000 +#define FB_SYNC_CLK_LAT_FALL 0x40000000 +#define FB_SYNC_DATA_INVERT 0x20000000 +#define FB_SYNC_CLK_IDLE_EN 0x10000000 +#define FB_SYNC_SHARP_MODE 0x08000000 +#define FB_SYNC_SWAP_RGB 0x04000000 +#define FB_ACCEL_TRIPLE_FLAG 0x00000000 +#define FB_ACCEL_DOUBLE_FLAG 0x00000001 + +struct mxcfb_gbl_alpha { + int enable; + int alpha; +}; + +struct mxcfb_loc_alpha { + int enable; + int alpha_in_pixel; + unsigned long alpha_phy_addr0; + unsigned long alpha_phy_addr1; +}; + +struct mxcfb_color_key { + int enable; + __u32 color_key; +}; + +struct mxcfb_pos { + __u16 x; + __u16 y; +}; + +struct mxcfb_gamma { + int enable; + int constk[16]; + int slopek[16]; +}; + +struct mxcfb_gpu_split_fmt { + struct fb_var_screeninfo var; + unsigned long offset; +}; + +struct mxcfb_rect { + __u32 top; + __u32 left; + __u32 width; + __u32 height; +}; + +#define GRAYSCALE_8BIT 0x1 +#define GRAYSCALE_8BIT_INVERTED 0x2 +#define GRAYSCALE_4BIT 0x3 +#define GRAYSCALE_4BIT_INVERTED 0x4 + +#define AUTO_UPDATE_MODE_REGION_MODE 0 +#define AUTO_UPDATE_MODE_AUTOMATIC_MODE 1 + +#define UPDATE_SCHEME_SNAPSHOT 0 +#define UPDATE_SCHEME_QUEUE 1 +#define UPDATE_SCHEME_QUEUE_AND_MERGE 2 + +#define UPDATE_MODE_PARTIAL 0x0 +#define UPDATE_MODE_FULL 0x1 + +#define WAVEFORM_MODE_GLR16 4 +#define WAVEFORM_MODE_GLD16 5 +#define WAVEFORM_MODE_AUTO 257 + +#define TEMP_USE_AMBIENT 0x1000 + +#define EPDC_FLAG_ENABLE_INVERSION 0x01 +#define EPDC_FLAG_FORCE_MONOCHROME 0x02 +#define EPDC_FLAG_USE_CMAP 0x04 +#define EPDC_FLAG_USE_ALT_BUFFER 0x100 +#define EPDC_FLAG_TEST_COLLISION 0x200 +#define EPDC_FLAG_GROUP_UPDATE 0x400 +#define EPDC_FLAG_USE_DITHERING_Y1 0x2000 +#define EPDC_FLAG_USE_DITHERING_Y4 0x4000 +#define EPDC_FLAG_USE_REGAL 0x8000 + +enum mxcfb_dithering_mode { + EPDC_FLAG_USE_DITHERING_PASSTHROUGH = 0x0, + EPDC_FLAG_USE_DITHERING_FLOYD_STEINBERG, + EPDC_FLAG_USE_DITHERING_ATKINSON, + EPDC_FLAG_USE_DITHERING_ORDERED, + EPDC_FLAG_USE_DITHERING_QUANT_ONLY, + EPDC_FLAG_USE_DITHERING_MAX, +}; + +#define FB_POWERDOWN_DISABLE -1 +#define FB_TEMP_AUTO_UPDATE_DISABLE -1 + +struct mxcfb_alt_buffer_data { + __u32 phys_addr; + __u32 width; /* width of entire buffer */ + __u32 height; /* height of entire buffer */ + struct mxcfb_rect alt_update_region; /* region within buffer to update */ +}; + +struct mxcfb_update_data { + struct mxcfb_rect update_region; + __u32 waveform_mode; + __u32 update_mode; + __u32 update_marker; + int temp; + unsigned int flags; + int dither_mode; + int quant_bit; + struct mxcfb_alt_buffer_data alt_buffer_data; +}; + +struct mxcfb_update_marker_data { + __u32 update_marker; + __u32 collision_test; +}; + +/* + * Structure used to define waveform modes for driver + * Needed for driver to perform auto-waveform selection + */ +struct mxcfb_waveform_modes { + int mode_init; + int mode_du; + int mode_gc4; + int mode_gc8; + int mode_gc16; + int mode_gc32; +}; + +/* + * Structure used to define a 5*3 matrix of parameters for + * setting IPU DP CSC module related to this framebuffer. + */ +struct mxcfb_csc_matrix { + int param[5][3]; +}; + +#define MXCFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) +#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha) +#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key) +#define MXCFB_SET_OVERLAY_POS _IOWR('F', 0x24, struct mxcfb_pos) +#define MXCFB_GET_FB_IPU_CHAN _IOR('F', 0x25, u_int32_t) +#define MXCFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mxcfb_loc_alpha) +#define MXCFB_SET_LOC_ALP_BUF _IOW('F', 0x27, unsigned long) +#define MXCFB_SET_GAMMA _IOW('F', 0x28, struct mxcfb_gamma) +#define MXCFB_GET_FB_IPU_DI _IOR('F', 0x29, u_int32_t) +#define MXCFB_GET_DIFMT _IOR('F', 0x2A, u_int32_t) +#define MXCFB_GET_FB_BLANK _IOR('F', 0x2B, u_int32_t) +#define MXCFB_SET_DIFMT _IOW('F', 0x2C, u_int32_t) +#define MXCFB_CSC_UPDATE _IOW('F', 0x2D, struct mxcfb_csc_matrix) +#define MXCFB_SET_GPU_SPLIT_FMT _IOW('F', 0x2F, struct mxcfb_gpu_split_fmt) +#define MXCFB_SET_PREFETCH _IOW('F', 0x30, int) +#define MXCFB_GET_PREFETCH _IOR('F', 0x31, int) + +/* IOCTLs for E-ink panel updates */ +#define MXCFB_SET_WAVEFORM_MODES _IOW('F', 0x2B, struct mxcfb_waveform_modes) +#define MXCFB_SET_TEMPERATURE _IOW('F', 0x2C, int32_t) +#define MXCFB_SET_AUTO_UPDATE_MODE _IOW('F', 0x2D, __u32) +#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data) +#define MXCFB_WAIT_FOR_UPDATE_COMPLETE _IOWR('F', 0x2F, struct mxcfb_update_marker_data) +#define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t) +#define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t) +#define MXCFB_SET_UPDATE_SCHEME _IOW('F', 0x32, __u32) +#define MXCFB_GET_WORK_BUFFER _IOWR('F', 0x34, unsigned long) +#define MXCFB_SET_TEMP_AUTO_UPDATE_PERIOD _IOW('F', 0x36, int32_t) +#define MXCFB_DISABLE_EPDC_ACCESS _IO('F', 0x35) +#define MXCFB_ENABLE_EPDC_ACCESS _IO('F', 0x36) +#endif -- cgit 1.4.1