aboutsummaryrefslogtreecommitdiff
path: root/fakefbdev
diff options
context:
space:
mode:
Diffstat (limited to 'fakefbdev')
-rw-r--r--fakefbdev/FakeFBDev.cpp59
-rw-r--r--fakefbdev/IOCTL.cpp43
-rw-r--r--fakefbdev/IOCTL.h3
-rw-r--r--fakefbdev/Makefile5
-rw-r--r--fakefbdev/SharedBuffer.cpp46
-rw-r--r--fakefbdev/SharedBuffer.h38
-rw-r--r--fakefbdev/mxcfb.h201
7 files changed, 395 insertions, 0 deletions
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 <cstring>
+#include <dlfcn.h>
+#include <string>
+#include <sys/types.h>
+#include <unistd.h>
+
+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 <cstring>
+#include <linux/ioctl.h>
+
+#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 <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+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 <cstdint>
+
+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 <linux/ioctl.h>
+#include <linux/fb.h>
+
+#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