Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Remarkable port #1023

Merged
merged 14 commits into from Feb 2, 2020
Merged
16 changes: 12 additions & 4 deletions Makefile
Expand Up @@ -29,7 +29,8 @@ all: $(OUTPUT_DIR)/libs $(if $(ANDROID),,$(LUAJIT)) \
$(if $(or $(DARWIN),$(WIN32),$(ANDROID),$(UBUNTUTOUCH),$(APPIMAGE)),,$(OUTPUT_DIR)/dropbear) \
$(if $(or $(KINDLE),$(KOBO),$(CERVANTES)),$(OUTPUT_DIR)/sftp-server,) \
$(if $(or $(DARWIN),$(WIN32)),,$(OUTPUT_DIR)/tar) \
$(if $(or $(KINDLE),$(KOBO),$(CERVANTES)),$(OUTPUT_DIR)/fbink,) \
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(REMARKABLE)),$(OUTPUT_DIR)/fbink,) \
$(if $(REMARKABLE),$(OUTPUT_DIR)/button-listen,) \
$(SQLITE_LIB) \
$(LUA_LJ_SQLITE) $(OUTPUT_DIR)/common/xsys.lua
ifndef EMULATE_READER
Expand All @@ -41,8 +42,9 @@ ifndef KODEBUG
$(if $(or $(DARWIN),$(WIN32),$(ANDROID),$(UBUNTUTOUCH),$(APPIMAGE)),,$(OUTPUT_DIR)/dropbear) \
$(if $(or $(KINDLE),$(KOBO),$(CERVANTES)),$(OUTPUT_DIR)/sftp-server,) \
$(if $(or $(KINDLE),$(KOBO)),$(OUTPUT_DIR)/scp,) \
$(if $(or $(KINDLE),$(KOBO),$(CERVANTES)),$(OUTPUT_DIR)/fbink,) \
$(if $(KOBO),$(OUTPUT_DIR)/fbdepth,) \
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(REMARKABLE)),$(OUTPUT_DIR)/fbink,) \
$(if $(REMARKABLE),$(OUTPUT_DIR)/button-listen,) \
$(if $(or $(KOBO),$(REMARKABLE)),$(OUTPUT_DIR)/fbdepth,) \
$(if $(ANDROID),,$(LUAJIT)) \
$(OUTPUT_DIR)/libs/$(if $(WIN32),*.dll,*.so*)" ;\
$(STRIP) --strip-unneeded $${STRIP_FILES} ;\
Expand Down Expand Up @@ -95,7 +97,7 @@ libs: \
$(OUTPUT_DIR)/libs/libkoreader-input.so: input/*.c input/*.h $(if $(KINDLE),$(POPEN_NOSHELL_LIB),)
@echo "Building koreader input module..."
$(CC) $(DYNLIB_CFLAGS) -I$(POPEN_NOSHELL_DIR) -I./input \
$(if $(KOBO),-DKOBO,) $(if $(KINDLE),-DKINDLE,) $(if $(POCKETBOOK),-DPOCKETBOOK,) $(if $(SONY_PRSTUX),-DSONY_PRSTUX,) $(if $(CERVANTES),-DCERVANTES,)\
$(if $(CERVANTES),-DCERVANTES,) $(if $(KOBO),-DKOBO,) $(if $(KINDLE),-DKINDLE,) $(if $(POCKETBOOK),-DPOCKETBOOK,) $(if $(REMARKABLE),-DREMARKABLE,) $(if $(SONY_PRSTUX),-DSONY_PRSTUX,)\
-o $@ \
input/input.c \
$(if $(KINDLE),$(POPEN_NOSHELL_LIB),) \
Expand Down Expand Up @@ -201,6 +203,12 @@ ffi/lodepng_h.lua: ffi-cdecl/lodepng_decl.c $(LODEPNG_DIR)
# include all third party libs
include Makefile.third

# ===========================================================================
# very simple "launcher" for koreader on the remarkable

$(OUTPUT_DIR)/button-listen: button-listen.c
$(CC) $(CFLAGS) -o $@ $^

# ===========================================================================
# the attachment extraction tool:

Expand Down
6 changes: 6 additions & 0 deletions Makefile.defs
Expand Up @@ -147,6 +147,9 @@ else ifeq ($(TARGET), pocketbook)
export PATH:=$(POCKETBOOK_TOOLCHAIN)/bin:$(PATH)
export SYSROOT=$(POCKETBOOK_TOOLCHAIN)/arm-obreey-linux-gnueabi/sysroot
endif
else ifeq ($(TARGET), remarkable)
CHOST?=arm-remarkable-linux-gnueabihf
export REMARKABLE=1
else ifeq ($(TARGET), sony-prstux)
CHOST?=arm-linux-gnueabihf
export SONY_PRSTUX=1
Expand Down Expand Up @@ -393,6 +396,9 @@ else ifeq ($(TARGET), android)
ARM_ARCH+=-mfloat-abi=softfp
export ac_cv_type_in_port_t=yes
endif
else ifeq ($(TARGET), remarkable)
ARM_ARCH:=$(ARMV7_A9_ARCH)
ARM_ARCH+=-mfloat-abi=hard
else ifeq ($(TARGET), sony-prstux)
ARM_ARCH:=$(ARMV7_A8_ARCH)
ARM_ARCH+=-mfloat-abi=hard
Expand Down
3 changes: 3 additions & 0 deletions Makefile.third
Expand Up @@ -492,6 +492,9 @@ $(OUTPUT_DIR)/fbink: $(THIRDPARTY_DIR)/fbink/*.*
ifdef KOBO
cp $(FBINK_DIR)/fbdepth $(OUTPUT_DIR)/
endif
ifdef REMARKABLE
cp $(FBINK_DIR)/fbdepth $(OUTPUT_DIR)/
endif

# ===========================================================================
# common lua library for networking
Expand Down
41 changes: 41 additions & 0 deletions button-listen.c
@@ -0,0 +1,41 @@
#include <linux/input.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

static double timeval_diff(struct timeval const* start, struct timeval const* end)
{
double s = (double)end->tv_sec - (double)start->tv_sec;
double us = (double)end->tv_usec - (double)start->tv_usec;
return s + (us / 1e6);
}

int main(int argc, char** argv)
{
FILE* evf = fopen("/dev/input/event2", "rb");
if(!evf) {
fprintf(stderr, "Could not open /dev/input/event2\n");
return 1;
}

struct input_event ev;
struct timeval press_stamp = {0};
while(1) {
size_t sz = fread(&ev, sizeof(ev), 1, evf);
if(sz == 0) {
return 1;
}
if(ev.type == EV_KEY && ev.code == KEY_HOME) {
if(ev.value == 0) { /* keyrelease */
double t = timeval_diff(&press_stamp, &ev.time);
/* hold home (middle) button for 3 seconds to start koreader */
if(t >= 3.0) {
system("systemctl start koreader");
}
}
else if(ev.value == 1) { /* keypress */
press_stamp = ev.time;
}
}
}
}
267 changes: 267 additions & 0 deletions ffi-cdecl/include/mxcfb-remarkable.h
@@ -0,0 +1,267 @@
/*
NiLuJe marked this conversation as resolved.
Show resolved Hide resolved
* 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.
*/

/* Original source:
* https://github.com/reMarkable/linux/blob/zero-gravitas/include/uapi/linux/mxcfb.h
* Waveform modes constants originally from libremarkable:
* https://github.com/canselcik/libremarkable
* Then later cleaned up thanks to the official SDK:
* https://remarkable.engineering/
*/

/*
* @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/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

// Findings courtesy of libremarkable
/*
// c.f., https://github.com/canselcik/libremarkable/blob/67ff7ea3926319a6d33a216a2b8c1f679916aa3c/src/framebuffer/common.rs#L338
// NOTE: Those constant names seem to be inspired from https://github.com/fread-ink/inkwave
// (which was itself built around Kindle waveforms, which is why some of those names will look familiar if you check mxcfb-kindle.h ;)).
// NOTE: Also added relevant enum names from libqsgepaper.a (it's part of the official SDK) as inline comments (AFAICT, here be dragons!).
// NOTE: Speaking of inkwave, it seems to confirm that the firmware blob only ships 5 different waveform modes, so I'd trust EPFrameBuffer::WaveformMode ;).
// Still, it was designed with Kindle firmware blobs in mind, so, take that with a grain of salt nonetheless.
#define WAVEFORM_MODE_INIT 0 // EPFrameBuffer::WaveformMode::Initialize EPFrameBuffer::Waveform::INIT
#define WAVEFORM_MODE_DU 1 // EPFrameBuffer::WaveformMode::Mono EPFrameBuffer::Waveform::DU
#define WAVEFORM_MODE_GC16 2 // EPFrameBuffer::WaveformMode::HighQualityGrayscale EPFrameBuffer::Waveform::GC16
#define WAVEFORM_MODE_GC16_FAST 3 // EPFrameBuffer::WaveformMode::Grayscale EPFrameBuffer::Waveform::GL16

#define WAVEFORM_MODE_GL16_FAST 6 // EPFrameBuffer::Waveform::A2
#define WAVEFORM_MODE_DU4 7 // EPFrameBuffer::Waveform::DU4
#define WAVEFORM_MODE_REAGL 8 // EPFrameBuffer::WaveformMode::Highlight EPFrameBuffer::Waveform::UNKNOWN
#define WAVEFORM_MODE_REAGLD 9 // EPFrameBuffer::Waveform::INIT2
#define WAVEFORM_MODE_GL4 0xA
#define WAVEFORM_MODE_GL16_INV 0xB

// NOTE: Those leftover constants from the upstream kernel sources are *extremely* confusingly named.
// libremarkable tests & comments hinted that this one was actually A2, which we've also confirmed.
#define WAVEFORM_MODE_GLR16 4 // EPFrameBuffer::Waveform::GLR16
#define WAVEFORM_MODE_A2 WAVEFORM_MODE_GLR16
// NOTE: Which would actually make this GL16 (purely by virtue of GL16 *usually* being A2 + 1)?
// Practical tests have yielded weird results, but with a weirdness consistent with GL16_FAST at least ^^.
#define WAVEFORM_MODE_GLD16 5 // EPFrameBuffer::Waveform::GLD16
#define WAVEFORM_MODE_GL16 WAVEFORM_MODE_GLD16
// NOTE: That one can't be bogus, because it's actually used by the driver to check for obviously invalid modes ;).
// Also, it's consistent with other platforms.
// Speaking of other platforms, usually, GLR16 == REAGL & GLD16 == REAGLD ;).
#define WAVEFORM_MODE_AUTO 257
*/

// Let's honor <epframebuffer.h> instead, it's slightly less confusing ;).
// c.f., https://github.com/NiLuJe/FBInk/pull/41#issuecomment-579579351
#define WAVEFORM_MODE_INIT 0
#define WAVEFORM_MODE_DU 1
#define WAVEFORM_MODE_GC16 2
#define WAVEFORM_MODE_GL16 3
// NOTE: Here be dragons!
// xochitl itself will never use any of those, and despite what's detailed in <epframebuffer.h>,
// testing on production devices reveals that no-one really should either, actually ;).
// c.f., https://github.com/NiLuJe/FBInk/pull/41#issuecomment-580926264
/*
#define WAVEFORM_MODE_GLR16 4
#define WAVEFORM_MODE_GLD16 5
#define WAVEFORM_MODE_A2 6
#define WAVEFORM_MODE_DU4 7
#define WAVEFORM_MODE_UNKNOWN 8
#define WAVEFORM_MODE_INIT2 9
*/
// NOTE: The only thing we can salvage is what's quite likely actually A2, according both to testing,
// and poking at the binary firmware blob.
#define WAVEFORM_MODE_A2 4

#define WAVEFORM_MODE_AUTO 257

#define TEMP_USE_AMBIENT 0x1000

// Again, pilfered from libremarkable ;).
// In practice, only appears to be used in conjunction w/ DU
// (c.f., https://github.com/NiLuJe/FBInk/pull/41#issuecomment-579424194)
#define TEMP_USE_REMARKABLE 0x0018

#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