Remarkable port (#5828)

Touchscreen is mirrored in X & Y and has a different resolution from the eink panel.

Uses systemd for time/date/suspend/poweroff/reboot
Two systemd units for platform integration. button-listen is a very
simple launcher.
to-do: add support for wifi by implementing  a wpa supplicant dbus client.

Authored-by: Thomas Spurden <tcrs@users.noreply.github.com>
reviewable/pr5829/r1
Martín Fernández 4 years ago committed by GitHub
parent 3856f04445
commit 67627ce2d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -49,6 +49,7 @@ DEBIAN_DIR=$(PLATFORM_DIR)/debian
KINDLE_DIR=$(PLATFORM_DIR)/kindle
KOBO_DIR=$(PLATFORM_DIR)/kobo
POCKETBOOK_DIR=$(PLATFORM_DIR)/pocketbook
REMARKABLE_DIR=$(PLATFORM_DIR)/remarkable
SONY_PRSTUX_DIR=$(PLATFORM_DIR)/sony-prstux
UBUNTUTOUCH_DIR=$(PLATFORM_DIR)/ubuntu-touch
UBUNTUTOUCH_SDL_DIR:=$(UBUNTUTOUCH_DIR)/ubuntu-touch-sdl
@ -385,6 +386,35 @@ debianupdate: all
rm -rf resources/fonts resources/icons/src && \
rm -rf ev_replay.py
REMARKABLE_PACKAGE:=koreader-remarkable$(KODEDUG_SUFFIX)-$(VERSION).zip
REMARKABLE_PACKAGE_OTA:=koreader-remarkable$(KODEDUG_SUFFIX)-$(VERSION).targz
remarkableupdate: all
# ensure that the binaries were built for ARM
file $(INSTALL_DIR)/koreader/luajit | grep ARM || exit 1
# remove old package if any
rm -f $(REMARKABLE_PACKAGE)
# Remarkable scripts
cp $(REMARKABLE_DIR)/* $(INSTALL_DIR)/koreader
cp $(COMMON_DIR)/spinning_zsync $(INSTALL_DIR)/koreader
# create new package
cd $(INSTALL_DIR) && \
zip -9 -r \
../$(REMARKABLE_PACKAGE) \
koreader -x "koreader/resources/fonts/*" \
"koreader/resources/icons/src/*" "koreader/spec/*" \
$(ZIP_EXCLUDE)
# generate update package index file
zipinfo -1 $(REMARKABLE_PACKAGE) > \
$(INSTALL_DIR)/koreader/ota/package.index
echo "koreader/ota/package.index" >> $(INSTALL_DIR)/koreader/ota/package.index
# update index file in zip package
cd $(INSTALL_DIR) && zip -u ../$(REMARKABLE_PACKAGE) \
koreader/ota/package.index
# make gzip remarkable update for zsync OTA update
cd $(INSTALL_DIR) && \
tar -I"gzip --rsyncable" -cah --no-recursion -f ../$(REMARKABLE_PACKAGE_OTA) \
-T koreader/ota/package.index
SONY_PRSTUX_PACKAGE:=koreader-sony-prstux$(KODEDUG_SUFFIX)-$(VERSION).zip
SONY_PRSTUX_PACKAGE_OTA:=koreader-sony-prstux$(KODEDUG_SUFFIX)-$(VERSION).targz
sony-prstuxupdate: all
@ -461,6 +491,8 @@ else ifeq ($(TARGET), pocketbook)
make pbupdate
else ifeq ($(TARGET), sony-prstux)
make sony-prstuxupdate
else ifeq ($(TARGET), remarkable)
make remarkableupdate
else ifeq ($(TARGET), ubuntu-touch)
make utupdate
else ifeq ($(TARGET), debian)

@ -18,6 +18,8 @@ function filemanagerutil.getDefaultDir()
return "/mnt/us/documents"
elseif Device:isKobo() then
return "/mnt/onboard"
elseif Device:isRemarkable() then
return "/home/root"
else
return "."
end

@ -26,6 +26,11 @@ local function probeDevice()
return require("device/pocketbook/device")
end
local remarkable_test_stat = lfs.attributes("/usr/bin/xochitl")
if remarkable_test_stat then
return require("device/remarkable/device")
end
local sony_prstux_test_stat = lfs.attributes("/etc/PRSTUX")
if sony_prstux_test_stat then
return require("device/sony-prstux/device")

@ -63,6 +63,7 @@ local Device = {
isKindle = no,
isKobo = no,
isPocketBook = no,
isRemarkable = no,
isSonyPRSTUX = no,
isSDL = no,
isEmulator = no,

@ -0,0 +1,116 @@
local Generic = require("device/generic/device") -- <= look at this file!
local logger = require("logger")
local TimeVal = require("ui/timeval")
local ffi = require("ffi")
local function yes() return true end
local function no() return false end
local Remarkable = Generic:new{
model = "reMarkable",
isRemarkable = yes,
hasKeys = yes,
hasOTAUpdates = yes,
canReboot = yes,
canPowerOff = yes,
isTouchDevice = yes,
hasKeys = yes,
hasFrontlight = no,
display_dpi = 226,
}
local EV_ABS = 3
local ABS_X = 00
local ABS_Y = 01
local ABS_MT_POSITION_X = 53
local ABS_MT_POSITION_Y = 54
-- Resolutions from libremarkable src/framebuffer/common.rs
local mt_width = 767
local mt_height = 1023
local mt_scale_x = 1404 / mt_width
local mt_scale_y = 1872 / mt_height
local adjustTouchEvt = function(self, ev)
if ev.type == EV_ABS then
-- Mirror X and scale up both X & Y as touch input is different res from
-- display
if ev.code == ABS_X or ev.code == ABS_MT_POSITION_X then
ev.value = (mt_width - ev.value) * mt_scale_x
end
if ev.code == ABS_Y or ev.code == ABS_MT_POSITION_Y then
ev.value = (mt_height - ev.value) * mt_scale_y
end
end
end
function Remarkable:init()
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
self.powerd = require("device/remarkable/powerd"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/remarkable/event_map"),
}
self.input.open("/dev/input/event0") -- Wacom
self.input.open("/dev/input/event1") -- Touchscreen
self.input.open("/dev/input/event2") -- Buttons
self.input:registerEventAdjustHook(adjustTouchEvt)
-- USB plug/unplug, battery charge/not charging are generated as fake events
self.input.open("fake_events")
local rotation_mode = self.screen.ORIENTATION_PORTRAIT
self.screen.native_rotation_mode = rotation_mode
self.screen.cur_rotation_mode = rotation_mode
Generic.init(self)
end
function Remarkable:supportsScreensaver() return true end
function Remarkable:setDateTime(year, month, day, hour, min, sec)
if hour == nil or min == nil then return true end
local command
if year and month and day then
command = string.format("timedatectl set-time '%d-%d-%d %d:%d:%d'", year, month, day, hour, min, sec)
else
command = string.format("timedatectl set-time '%d:%d'",hour, min)
end
return os.execute(command) == 0
end
function Remarkable:intoScreenSaver()
local Screensaver = require("ui/screensaver")
if self.screen_saver_mode == false then
Screensaver:show()
end
self.powerd:beforeSuspend()
self.screen_saver_mode = true
end
function Remarkable:outofScreenSaver()
if self.screen_saver_mode == true then
local Screensaver = require("ui/screensaver")
Screensaver:close()
local UIManager = require("ui/uimanager")
UIManager:nextTick(function() UIManager:setDirty("all", "full") end)
end
self.powerd:afterResume()
self.screen_saver_mode = false
end
function Remarkable:suspend()
os.execute("systemctl suspend")
end
function Remarkable:resume()
end
function Remarkable:powerOff()
os.execute("systemctl poweroff")
end
function Remarkable:reboot()
os.execute("systemctl reboot")
end
return Remarkable

@ -0,0 +1,7 @@
return {
[102] = "Home",
[105] = "LPgBack",
[106] = "RPgFwd",
[116] = "Power",
}
-- TODO libremarkable has 143 as "wakeup" - don't know what that corresponds to?

@ -0,0 +1,30 @@
local BasePowerD = require("device/generic/powerd")
-- TODO older firmware doesn't have the -0 on the end of the file path
local base_path = '/sys/class/power_supply/bq27441-0/'
local Remarkable_PowerD = BasePowerD:new{
is_charging = nil,
capacity_file = base_path .. 'capacity',
status_file = base_path .. 'status'
}
function Remarkable_PowerD:init()
end
function Remarkable_PowerD:frontlightIntensityHW()
return 0
end
function Remarkable_PowerD:setIntensityHW(intensity)
end
function Remarkable_PowerD:getCapacityHW()
return self:read_int_file(self.capacity_file)
end
function Remarkable_PowerD:isChargingHW()
return self:read_str_file(self.status_file) == "Charging\n"
end
return Remarkable_PowerD

@ -127,6 +127,8 @@ function OTAManager:getOTAModel()
return "kobo"
elseif Device:isPocketBook() then
return "pocketbook"
elseif Device:isRemarkable() then
return "remarkable"
elseif Device:isSonyPRSTUX() then
return "sony-prstux"
else

@ -192,6 +192,37 @@ function UIManager:init()
Device:usbPlugOut()
self:_afterNotCharging()
end
elseif Device:isRemarkable() then
self.event_handlers["PowerPress"] = function()
UIManager:scheduleIn(2, self.poweroff_action)
end
self.event_handlers["PowerRelease"] = function()
if not self._entered_poweroff_stage then
UIManager:unschedule(self.poweroff_action)
-- resume if we were suspended
if Device.screen_saver_mode then
self:resume()
else
self:suspend()
end
end
end
self.event_handlers["Suspend"] = function()
self:_beforeSuspend()
Device:intoScreenSaver()
Device:suspend()
end
self.event_handlers["Resume"] = function()
Device:resume()
Device:outofScreenSaver()
self:_afterResume()
end
self.event_handlers["__default__"] = function(input_event)
-- Same as in Kobo: we want to ignore keys during suspension
if not Device.screen_saver_mode then
self:sendEvent(input_event)
end
end
elseif Device:isSonyPRSTUX() then
self.event_handlers["PowerPress"] = function()
UIManager:scheduleIn(2, self.poweroff_action)
@ -1155,7 +1186,7 @@ end
-- Executes all the operations of a suspending request. This function usually puts the device into
-- suspension.
function UIManager:suspend()
if Device:isCervantes() or Device:isKobo() or Device:isSDL() or Device:isSonyPRSTUX() then
if Device:isCervantes() or Device:isKobo() or Device:isSDL() or Device:isRemarkable() or Device:isSonyPRSTUX() then
self.event_handlers["Suspend"]()
elseif Device:isKindle() then
Device.powerd:toggleSuspend()
@ -1164,7 +1195,7 @@ end
-- Executes all the operations of a resume request. This function usually wakes up the device.
function UIManager:resume()
if Device:isCervantes() or Device:isKobo() or Device:isSDL() or Device:isSonyPRSTUX() then
if Device:isCervantes() or Device:isKobo() or Device:isSDL() or Device:isRemarkable() or Device:isSonyPRSTUX() then
self.event_handlers["Resume"]()
elseif Device:isKindle() then
self.event_handlers["OutOfSS"]()

12
kodev

@ -116,6 +116,7 @@ SUPPORTED_TARGETS="
kindle-legacy Needed only for Kindle2/3/DXG
kobo
cervantes
remarkable
sony-prstux
android
pocketbook
@ -187,6 +188,10 @@ ${SUPPORTED_TARGETS}"
make TARGET=kobo
assert_ret_zero $?
;;
remarkable)
make TARGET=remarkable
assert_ret_zero $?
;;
sony-prstux)
make TARGET=sony-prstux
assert_ret_zero $?
@ -303,6 +308,9 @@ ${SUPPORTED_TARGETS}"
kobo)
make TARGET=kobo clean
;;
remarkable)
make TARGET=remarkable clean
;;
sony-prstux)
make TARGET=sony-prstux clean
;;
@ -413,6 +421,10 @@ ${SUPPORTED_RELEASE_TARGETS}"
kodev-build kobo
make TARGET=kobo update
;;
remarkable)
kodev-build remarkable
make TARGET=remarkable update
;;
sony-prstux)
kodev-build sony-prstux
make TARGET=sony-prstux update

@ -0,0 +1,24 @@
# General
When connected to WiFi you can find the IP address and root password for your
reMarkable in Settings -> About, then scroll down the GPLv3 compliance on the
right (finger drag scroll, not the page forward/back buttons). This should also
work for the USB network you get if you connect the reMarkable to your computer
with a USB cable.
# Install
scp <koreader-package>.zip root@<your-remarkable>:
ssh root@<your-remarkable>
unzip <koreader-package>.zip
cp -v koreader/*.service /etc/systemd/system/
systemctl enable --now button-listen
Hold down the middle button for 3 seconds to start koreader. To return to
xochitl just exit koreader (swipe down from the top of the screen, select icon
in the top right, Exit, Exit).
Some reMarkable software updates will wipe the new systemd units so you will have
to run the last two steps again when that happens.

@ -0,0 +1,14 @@
[Unit]
Description=KOReader Button Listener
StartLimitIntervalSec=600
StartLimitBurst=4
After=home.mount
[Service]
ExecStart=/home/root/koreader/button-listen
Restart=on-failure
[Install]
WantedBy=multi-user.target

@ -0,0 +1,18 @@
[Unit]
Description=KOReader
StartLimitIntervalSec=600
StartLimitBurst=4
After=home.mount
After=xochitl.service
Conflicts=xochitl.service
OnFailure=xochitl.service
[Service]
ExecStart=/home/root/koreader/koreader.sh
ExecStopPost=/bin/false
Restart=no
[Install]
WantedBy=multi-user.target

@ -0,0 +1,233 @@
#!/bin/sh
export LC_ALL="en_US.UTF-8"
# working directory of koreader
KOREADER_DIR="${0%/*}"
# we're always starting from our working directory
cd "${KOREADER_DIR}" || exit
# update to new version from OTA directory
ko_update_check() {
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
if [ -f "${NEWUPDATE}" ]; then
# If button-listen service is running then stop it during update so that
# the update can overwite the binary
systemctl is-active --quiet button-listen
USING_BUTTON_LISTEN=$?
if [ ${USING_BUTTON_LISTEN} -eq 0 ]; then
systemctl stop button-listen
fi
./fbink -q -y -7 -pmh "Updating KOReader"
# NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature
# NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;).
FILESIZE="$(stat -c %b "${NEWUPDATE}")"
BLOCKS="$((FILESIZE / 20))"
export CPOINTS="$((BLOCKS / 100))"
# shellcheck disable=SC2016
./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))'
fail=$?
# Cleanup behind us...
if [ "${fail}" -eq 0 ]; then
mv "${NEWUPDATE}" "${INSTALLED}"
./fbink -q -y -6 -pm "Update successful :)"
./fbink -q -y -5 -pm "KOReader will start momentarily . . ."
else
# Uh oh...
./fbink -q -y -6 -pmh "Update failed :("
./fbink -q -y -5 -pm "KOReader may fail to function properly!"
fi
rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop
unset BLOCKS CPOINTS
# Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage!
sync
if [ ${USING_BUTTON_LISTEN} -eq 0 ]; then
systemctl start button-listen
fi
fi
}
# NOTE: Keep doing an initial update check, in addition to one during the restart loop, so we can pickup potential updates of this very script...
ko_update_check
# If an update happened, and was successful, reexec
if [ -n "${fail}" ] && [ "${fail}" -eq 0 ]; then
# By now, we know we're in the right directory, and our script name is pretty much set in stone, so we can forgo using $0
exec ./koreader.sh "${@}"
fi
# load our own shared libraries if possible
export LD_LIBRARY_PATH="${KOREADER_DIR}/libs:${LD_LIBRARY_PATH}"
# export trained OCR data directory
export TESSDATA_PREFIX="data"
# export dict directory
export STARDICT_DATA_DIR="data/dict"
# export external font directory
export EXT_FONT_DIR="/usr/share/fonts/ttf;/usr/share/fonts/opentype"
# We'll want to ensure Portrait rotation to allow us to use faster blitting codepaths @ 8bpp,
# so remember the current one before fbdepth does its thing.
ORIG_FB_ROTA="$(./fbdepth -o)"
# In the same vein, swap to 8bpp,
# because 16bpp is the worst idea in the history of time, as RGB565 is generally a PITA without hardware blitting,
# and 32bpp usually gains us nothing except a performance hit (we're not Qt5 with its QPainter constraints).
# The reduced size & complexity should hopefully make things snappier,
# (and hopefully prevent the JIT from going crazy on high-density screens...).
# NOTE: Even though both pickel & Nickel appear to restore their preferred fb setup, we'll have to do it ourselves,
# as they fail to flip the grayscale flag properly. Plus, we get to play nice with every launch method that way.
# So, remember the current bitdepth, so we can restore it on exit.
ORIG_FB_BPP="$(./fbdepth -g)"
echo "Original fb settings: bitdepth = ${ORIG_FB_BPP}, rotation = ${ORIG_FB_ROTA}" >>crash.log 2>&1
# Sanity check...
case "${ORIG_FB_BPP}" in
16) ;;
32) ;;
*)
# Uh oh? Don't do anything...
unset ORIG_FB_BPP
;;
esac
# The actual swap is done in a function, because we can disable it in the Developer settings, and we want to honor it on restart.
ko_do_fbdepth() {
# Check if the swap has been disabled...
if grep -q '\["dev_startup_no_fbdepth"\] = true' 'settings.reader.lua' 2>/dev/null; then
# Swap back to the original bitdepth (in case this was a restart)
if [ -n "${ORIG_FB_BPP}" ]; then
echo "Making sure we're using the original fb bitdepth @ ${ORIG_FB_BPP}bpp & rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1
./fbdepth -d "${ORIG_FB_BPP}" -r "${ORIG_FB_ROTA}" >>crash.log 2>&1
fi
else
# Swap to 8bpp if things look sane
if [ -n "${ORIG_FB_BPP}" ]; then
echo "Switching fb bitdepth to 8bpp & rotation to Portrait" >>crash.log 2>&1
./fbdepth -d 8 -r -1 >>crash.log 2>&1
fi
fi
}
# we keep at most 500KB worth of crash log
if [ -e crash.log ]; then
tail -c 500000 crash.log >crash.log.new
mv -f crash.log.new crash.log
fi
CRASH_COUNT=0
CRASH_TS=0
CRASH_PREV_TS=0
# Because we *want* an initial fbdepth pass ;).
RETURN_VALUE=85
while [ ${RETURN_VALUE} -ne 0 ]; do
# 85 is what we return when asking for a KOReader restart
if [ ${RETURN_VALUE} -eq 85 ]; then
# Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;).
ko_update_check
# Do or double-check the fb depth switch, or restore original bitdepth if requested
ko_do_fbdepth
fi
./reader.lua >>crash.log 2>&1
RETURN_VALUE=$?
# Did we crash?
if [ ${RETURN_VALUE} -ne 0 ] && [ ${RETURN_VALUE} -ne 85 ]; then
# Increment the crash counter
CRASH_COUNT=$((CRASH_COUNT + 1))
CRASH_TS=$(date +'%s')
# Reset it to a first crash if it's been a while since our last crash...
if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then
CRASH_COUNT=1
fi
# Check if the user requested to always abort on crash
if grep -q '\["dev_abort_on_crash"\] = true' 'settings.reader.lua' 2>/dev/null; then
ALWAYS_ABORT="true"
# In which case, make sure we pause on *every* crash
CRASH_COUNT=1
else
ALWAYS_ABORT="false"
fi
# Show a fancy bomb on screen
viewWidth=600
viewHeight=800
FONTH=16
eval "$(./fbink -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')"
# Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device.
# Height @ ~56.7%, w/ a margin worth 1.5 lines
bombHeight=$((viewHeight / 2 + viewHeight / 15))
bombMargin=$((FONTH + FONTH / 2))
# With a little notice at the top of the screen, on a big gray screen of death ;).
./fbink -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})"
if [ ${CRASH_COUNT} -eq 1 ]; then
# Warn that we're waiting on a tap to continue...
./fbink -q -b -O -m -y 2 "Tap the screen to continue."
fi
# U+1F4A3, the hard way, because we can't use \u or \U escape sequences...
# shellcheck disable=SC2039
./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} $'\xf0\x9f\x92\xa3'
# And then print the tail end of the log on the bottom of the screen...
crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')"
# The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi
./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) "${crashLog}"
# So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh.
./fbink -q -f -s
# Cue a lemming's faceplant sound effect!
{
echo "!!!!"
echo "Uh oh, something went awry... (Crash n°${CRASH_COUNT}: $(date +'%x @ %X'))"
echo "Running on Linux $(uname -r) ($(uname -v))"
} >>crash.log 2>&1
if [ ${CRASH_COUNT} -lt 5 ] && [ "${ALWAYS_ABORT}" = "false" ]; then
echo "Attempting to restart KOReader . . ." >>crash.log 2>&1
echo "!!!!" >>crash.log 2>&1
fi
# Pause a bit if it's the first crash in a while, so that it actually has a chance of getting noticed ;).
if [ ${CRASH_COUNT} -eq 1 ]; then
# NOTE: We don't actually care about what read read, we're just using it as a fancy sleep ;).
# i.e., we pause either until the 15s timeout, or until the user touches the screen.
# shellcheck disable=SC2039
read -r -t 15 </dev/input/event1
fi
# Cycle the last crash timestamp
CRASH_PREV_TS=${CRASH_TS}
# But if we've crashed more than 5 consecutive times, exit, because we wouldn't want to be stuck in a loop...
# NOTE: No need to check for ALWAYS_ABORT, CRASH_COUNT will always be 1 when it's true ;).
if [ ${CRASH_COUNT} -ge 5 ]; then
echo "Too many consecutive crashes, aborting . . ." >>crash.log 2>&1
echo "!!!! ! !!!!" >>crash.log 2>&1
break
fi
# If the user requested to always abort on crash, do so.
if [ "${ALWAYS_ABORT}" = "true" ]; then
echo "Aborting . . ." >>crash.log 2>&1
echo "!!!! ! !!!!" >>crash.log 2>&1
break
fi
else
# Reset the crash counter if that was a sane exit/restart
CRASH_COUNT=0
fi
done
# Restore original fb bitdepth if need be...
# Since we also (almost) always enforce Portrait, we also have to restore the original rotation no matter what ;).
if [ -n "${ORIG_FB_BPP}" ]; then
echo "Restoring original fb bitdepth @ ${ORIG_FB_BPP}bpp & rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1
./fbdepth -d "${ORIG_FB_BPP}" -r "${ORIG_FB_ROTA}" >>crash.log 2>&1
else
echo "Restoring original fb rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1
./fbdepth -r "${ORIG_FB_ROTA}" >>crash.log 2>&1
fi
exit ${RETURN_VALUE}
Loading…
Cancel
Save