mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
617618d587
Devices with a single target might want to specify it in `Device.ota_model` Devices with multiple targets want to override the function or to specify `ota_model` variants for each target.
1794 lines
67 KiB
Lua
1794 lines
67 KiB
Lua
local Generic = require("device/generic/device")
|
|
local UIManager
|
|
local time = require("ui/time")
|
|
local lfs = require("libs/libkoreader-lfs")
|
|
local logger = require("logger")
|
|
|
|
-- We're going to need a few <linux/fb.h> & <linux/input.h> constants...
|
|
local ffi = require("ffi")
|
|
local C = ffi.C
|
|
require("ffi/linux_fb_h")
|
|
require("ffi/linux_input_h")
|
|
require("ffi/posix_h")
|
|
require("ffi/fbink_input_h")
|
|
|
|
local function yes() return true end
|
|
local function no() return false end -- luacheck: ignore
|
|
|
|
-- Try to detect WARIO+ Kindle boards (i.MX6 & i.MX7)
|
|
local function isWarioOrMore()
|
|
local cpu_hw = nil
|
|
-- Parse cpuinfo line by line, until we find the Hardware description
|
|
for line in io.lines("/proc/cpuinfo") do
|
|
if line:find("^Hardware") then
|
|
cpu_hw = line:match("^Hardware%s*:%s([%g%s]*)$")
|
|
end
|
|
end
|
|
-- NOTE: I couldn't dig up a cpuinfo dump from an Oasis 2 to check the CPU part value,
|
|
-- but for Wario (Cortex A9), matching that to 0xc09 would work, too.
|
|
-- On the other hand, I'm already using the Hardware match in MRPI, so, that sealed the deal ;).
|
|
|
|
-- If we've got a Hardware string, check if it mentions an i.MX 6 or 7 or a MTK...
|
|
if cpu_hw then
|
|
if cpu_hw:find("i%.MX%s?[6-7]") or cpu_hw:find("MT8110") then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Try to detect Kindle running hardfp firmware
|
|
local function isHardFP()
|
|
local util = require("util")
|
|
return util.pathExists("/lib/ld-linux-armhf.so.3")
|
|
end
|
|
|
|
local function kindleGetSavedNetworks()
|
|
local haslipc, lipc = pcall(require, "libopenlipclua") -- use our lua lipc library with access to hasharray properties
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.open_no_name()
|
|
end
|
|
if lipc_handle then
|
|
local ha_input = lipc_handle:new_hasharray() -- an empty hash array since we only want to read
|
|
local ha_result = lipc_handle:access_hash_property("com.lab126.wifid", "profileData", ha_input)
|
|
local profiles = ha_result:to_table()
|
|
ha_result:destroy()
|
|
ha_input:destroy()
|
|
lipc_handle:close()
|
|
return profiles
|
|
end
|
|
end
|
|
|
|
local function kindleGetCurrentProfile()
|
|
local haslipc, lipc = pcall(require, "libopenlipclua") -- use our lua lipc library with access to hasharray properties
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.open_no_name()
|
|
end
|
|
if lipc_handle then
|
|
local ha_input = lipc_handle:new_hasharray() -- an empty hash array since we only want to read
|
|
local ha_result = lipc_handle:access_hash_property("com.lab126.wifid", "currentEssid", ha_input)
|
|
local profile = ha_result:to_table()[1] -- theres only a single element
|
|
ha_input:destroy()
|
|
ha_result:destroy()
|
|
lipc_handle:close()
|
|
return profile
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local function kindleAuthenticateNetwork(essid)
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.init("com.github.koreader.networkmgr")
|
|
end
|
|
if lipc_handle then
|
|
lipc_handle:set_string_property("com.lab126.cmd", "ensureConnection", "wifi:" .. essid)
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
|
|
local function kindleSaveNetwork(data)
|
|
local haslipc, lipc = pcall(require, "libopenlipclua") -- use our lua lipc library with access to hasharray properties
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.open_no_name()
|
|
end
|
|
if lipc_handle then
|
|
local profile = lipc_handle:new_hasharray()
|
|
profile:add_hash()
|
|
profile:put_string(0, "essid", data.ssid)
|
|
if string.find(data.flags, "WPA") then
|
|
profile:put_string(0, "secured", "yes")
|
|
profile:put_string(0, "psk", data.password)
|
|
profile:put_int(0, "store_nw_user_pref", 0) -- tells amazon we don't want them to have our password
|
|
else
|
|
profile:put_string(0, "secured", "no")
|
|
end
|
|
lipc_handle:access_hash_property("com.lab126.wifid", "createProfile", profile):destroy() -- destroy the returned empty ha
|
|
profile:destroy()
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
|
|
local function kindleGetScanList()
|
|
local _ = require("gettext")
|
|
local haslipc, lipc = pcall(require, "libopenlipclua") -- use our lua lipc library with access to hasharray properties
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.open_no_name()
|
|
end
|
|
if lipc_handle then
|
|
if lipc_handle:get_string_property("com.lab126.wifid", "cmState") ~= "CONNECTED" then
|
|
local ha_input = lipc_handle:new_hasharray()
|
|
local ha_results = lipc_handle:access_hash_property("com.lab126.wifid", "scanList", ha_input)
|
|
if ha_results == nil then
|
|
-- Shouldn't really happen, access_hash_property will throw if LipcAccessHasharrayProperty failed
|
|
ha_input:destroy()
|
|
lipc_handle:close()
|
|
-- NetworkMgr will ask for a re-scan on seeing an empty table, the second attempt *should* work ;).
|
|
return {}, nil
|
|
end
|
|
local scan_result = ha_results:to_table()
|
|
ha_results:destroy()
|
|
ha_input:destroy()
|
|
lipc_handle:close()
|
|
if not scan_result then
|
|
-- e.g., to_table hit lha->ha == NULL
|
|
return {}, nil
|
|
else
|
|
return scan_result, nil
|
|
end
|
|
end
|
|
lipc_handle:close()
|
|
-- return a fake scan list containing only the currently connected profile :)
|
|
local profile = kindleGetCurrentProfile()
|
|
return { profile }, nil
|
|
else
|
|
logger.dbg("kindleGetScanList: Failed to acquire an anonymous lipc handle")
|
|
return nil, _("Unable to communicate with the Wi-Fi backend")
|
|
end
|
|
end
|
|
|
|
local function kindleScanThenGetResults()
|
|
local _ = require("gettext")
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.init("com.github.koreader.networkmgr")
|
|
end
|
|
if not lipc_handle then
|
|
logger.dbg("kindleScanThenGetResults: Failed to acquire a lipc handle for NetworkMgr")
|
|
return nil, _("Unable to communicate with the Wi-Fi backend")
|
|
end
|
|
|
|
lipc_handle:set_string_property("com.lab126.wifid", "scan", "") -- trigger a scan
|
|
|
|
-- Mimic WpaClient:scanThenGetResults: block while waiting for the scan to finish.
|
|
-- Ideally, we'd do this via a poll/event workflow, but, eh', this is going to be good enough for now ;p.
|
|
-- For future reference, see `lipc-wait-event -m -s 0 -t com.lab126.wifid '*'`
|
|
--[[
|
|
-- For a connection:
|
|
[00:00:04.675699] cmStateChange "PENDING"
|
|
[00:00:04.677402] scanning
|
|
[00:00:05.488043] scanComplete
|
|
[00:00:05.973188] cmConnected
|
|
[00:00:05.977862] cmStateChange "CONNECTED"
|
|
[00:00:05.980698] signalStrength "1/5"
|
|
[00:00:06.417549] cmConnected
|
|
|
|
-- And a disconnection:
|
|
[00:01:34.094652] cmDisconnected
|
|
[00:01:34.096088] cmStateChange "NA"
|
|
[00:01:34.219802] signalStrength "0/5"
|
|
[00:01:34.221802] cmStateChange "READY"
|
|
[00:01:35.656375] cmIntfNotAvailable
|
|
[00:01:35.658710] cmStateChange "NA"
|
|
--]]
|
|
local done_scanning = false
|
|
local wait_cnt = 80 -- 20s in chunks on 250ms
|
|
while wait_cnt > 0 do
|
|
local scan_state = lipc_handle:get_string_property("com.lab126.wifid", "scanState")
|
|
|
|
if scan_state == "idle" then
|
|
done_scanning = true
|
|
logger.dbg("kindleScanThenGetResults: Wi-Fi scan took", (80 - wait_cnt) * 0.25, "seconds")
|
|
break
|
|
end
|
|
|
|
-- Whether it's still "scanning" or in whatever other state we don't know about,
|
|
-- try again until it says it's done.
|
|
wait_cnt = wait_cnt - 1
|
|
C.usleep(250 * 1000)
|
|
end
|
|
lipc_handle:close()
|
|
|
|
if done_scanning then
|
|
return kindleGetScanList()
|
|
else
|
|
logger.warn("kindleScanThenGetResults: Timed-out scanning for Wi-Fi networks")
|
|
return nil, _("Scanning for Wi-Fi networks timed out")
|
|
end
|
|
end
|
|
|
|
local function kindleEnableWifi(toggle)
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.init("com.github.koreader.networkmgr")
|
|
end
|
|
if lipc_handle then
|
|
-- Be extremely thorough... c.f., #6019
|
|
-- NOTE: I *assume* this'll also ensure we prefer Wi-Fi over 3G/4G, which is a plus in my book...
|
|
if toggle == 1 then
|
|
lipc_handle:set_int_property("com.lab126.cmd", "wirelessEnable", 1)
|
|
lipc_handle:set_int_property("com.lab126.wifid", "enable", 1)
|
|
else
|
|
lipc_handle:set_int_property("com.lab126.wifid", "enable", 0)
|
|
lipc_handle:set_int_property("com.lab126.cmd", "wirelessEnable", 0)
|
|
end
|
|
lipc_handle:close()
|
|
else
|
|
-- No liblipclua on FW < 5.x ;)
|
|
-- Always kill 3G first...
|
|
os.execute("lipc-set-prop -i com.lab126.wan enable 0")
|
|
os.execute("lipc-set-prop -i com.lab126.wifid enable " .. toggle)
|
|
end
|
|
end
|
|
|
|
-- Check if wifid thinks that the WiFi is enabled
|
|
--[[
|
|
local function isWifiUp()
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
local lipc_handle
|
|
if haslipc then
|
|
lipc_handle = lipc.init("com.github.koreader.networkmgr")
|
|
end
|
|
if lipc_handle then
|
|
local status = lipc_handle:get_int_property("com.lab126.wifid", "enable") or 0
|
|
lipc_handle:close()
|
|
|
|
return status == 1
|
|
else
|
|
local std_out = io.popen("lipc-get-prop -i com.lab126.wifid enable", "r")
|
|
if std_out then
|
|
local result = std_out:read("*number")
|
|
std_out:close()
|
|
|
|
if not result then
|
|
return false
|
|
end
|
|
|
|
return result == 1
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
--]]
|
|
|
|
--[[
|
|
Test if a kindle device is flagged as a Special Offers device (i.e., ad supported) (FW >= 5.x)
|
|
--]]
|
|
local function isSpecialOffers()
|
|
-- Look at the current blanket modules to see if the SO screensavers are enabled...
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if not haslipc then
|
|
logger.warn("could not load liblipclua:", lipc)
|
|
return true
|
|
end
|
|
local lipc_handle = lipc.init("com.github.koreader.device")
|
|
if not lipc_handle then
|
|
logger.warn("could not get lipc handle")
|
|
return true
|
|
end
|
|
local is_so
|
|
local loaded_blanket_modules = lipc_handle:get_string_property("com.lab126.blanket", "load")
|
|
if not loaded_blanket_modules then
|
|
logger.warn("could not get lipc property")
|
|
return true
|
|
end
|
|
if string.find(loaded_blanket_modules, "ad_screensaver") then
|
|
is_so = true
|
|
else
|
|
is_so = false
|
|
end
|
|
lipc_handle:close()
|
|
return is_so
|
|
end
|
|
|
|
--[[
|
|
Test if a kindle device has *received* Special Offers (FW < 5.x)
|
|
--]]
|
|
local function hasSpecialOffers()
|
|
if lfs.attributes("/mnt/us/system/.assets", "mode") == "directory" then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local function frameworkStopped()
|
|
if os.getenv("STOP_FRAMEWORK") == "yes" then
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if not haslipc then
|
|
logger.warn("could not load liblibclua")
|
|
return
|
|
end
|
|
local lipc_handle = lipc.init("com.lab126.kaf")
|
|
if not lipc_handle then
|
|
logger.warn("could not get lipc handle")
|
|
return
|
|
end
|
|
local frameworkStarted = lipc_handle:register_int_property("frameworkStarted", "r")
|
|
frameworkStarted.value = 1
|
|
lipc_handle:set_string_property("com.lab126.blanket", "unload", "splash")
|
|
lipc_handle:set_string_property("com.lab126.blanket", "unload", "screensaver")
|
|
return lipc_handle
|
|
end
|
|
end
|
|
|
|
local Kindle = Generic:extend{
|
|
model = "Kindle",
|
|
isKindle = yes,
|
|
-- NOTE: We can cheat by adding a platform-specific entry here, because the only code that will check for this is here.
|
|
isSpecialOffers = isSpecialOffers(),
|
|
hasOTAUpdates = yes,
|
|
hasFastWifiStatusQuery = yes,
|
|
hasWifiRestore = yes,
|
|
-- NOTE: HW inversion is generally safe on mxcfb Kindles
|
|
canHWInvert = yes,
|
|
-- NOTE: And the fb driver is generally sane on those, too
|
|
canModifyFBInfo = yes,
|
|
-- NOTE: Newer devices will turn the frontlight off at 0
|
|
canTurnFrontlightOff = yes,
|
|
-- NOTE: Via powerd.toggleSuspend
|
|
canSuspend = yes,
|
|
home_dir = "/mnt/us",
|
|
-- New devices are REAGL-aware, default to REAGL
|
|
isREAGL = yes,
|
|
-- Rex & Zelda devices sport an updated driver.
|
|
isZelda = no,
|
|
isRex = no,
|
|
-- So do devices running on a MediaTek SoC
|
|
isMTK = no,
|
|
-- But of course, some devices don't actually support all the features the kernel exposes...
|
|
isNightModeChallenged = no,
|
|
-- NOTE: While this ought to behave on Zelda/Rex, turns out, nope, it really doesn't work on *any* of 'em :/ (c.f., ko#5884).
|
|
canHWDither = no,
|
|
-- Device has an Ambient Light Sensor
|
|
hasLightSensor = no,
|
|
-- The time the device went into suspend
|
|
suspend_time = 0,
|
|
framework_lipc_handle = frameworkStopped(),
|
|
}
|
|
|
|
function Kindle:initNetworkManager(NetworkMgr)
|
|
local haslipc, _ = pcall(require, "liblipclua")
|
|
if haslipc then
|
|
function NetworkMgr:turnOnWifi(complete_callback, interactive)
|
|
kindleEnableWifi(1)
|
|
return self:reconnectOrShowNetworkMenu(complete_callback, interactive)
|
|
end
|
|
else
|
|
-- If we can't use the lipc Lua bindings, we can't support any kind of interactive Wi-Fi UI...
|
|
function NetworkMgr:turnOnWifi(complete_callback, interactive)
|
|
kindleEnableWifi(1)
|
|
if complete_callback then
|
|
complete_callback()
|
|
end
|
|
end
|
|
end
|
|
|
|
function NetworkMgr:turnOffWifi(complete_callback)
|
|
kindleEnableWifi(0)
|
|
-- NOTE: Same here, except disconnect is simpler, so a dumb delay will do...
|
|
if complete_callback then
|
|
UIManager:scheduleIn(2, complete_callback)
|
|
end
|
|
end
|
|
|
|
function NetworkMgr:getNetworkInterfaceName()
|
|
return "wlan0" -- so far, all Kindles appear to use wlan0
|
|
end
|
|
|
|
function NetworkMgr:restoreWifiAsync()
|
|
kindleEnableWifi(1)
|
|
end
|
|
|
|
function NetworkMgr:authenticateNetwork(network)
|
|
kindleAuthenticateNetwork(network.ssid)
|
|
return true, nil
|
|
end
|
|
|
|
-- NOTE: We don't have a disconnectNetwork & releaseIP implementation,
|
|
-- which means the "disconnect" button in NetworkSetting kind of does nothing ;p.
|
|
|
|
function NetworkMgr:saveNetwork(setting)
|
|
kindleSaveNetwork(setting)
|
|
end
|
|
|
|
function NetworkMgr:getNetworkList()
|
|
local scan_list, err = kindleScanThenGetResults()
|
|
if not scan_list then
|
|
return nil, err
|
|
end
|
|
|
|
-- trick ui/widget/networksetting into displaying the correct signal strength icon
|
|
local qualities = {
|
|
[1] = 0,
|
|
[2] = 6,
|
|
[3] = 31,
|
|
[4] = 56,
|
|
[5] = 81
|
|
}
|
|
|
|
local network_list = {}
|
|
local saved_profiles = kindleGetSavedNetworks()
|
|
local current_profile = kindleGetCurrentProfile()
|
|
for _, network in ipairs(scan_list) do
|
|
local password = nil
|
|
if network.known == "yes" then
|
|
for _, p in ipairs(saved_profiles) do
|
|
-- Earlier FW do not have a netid field at all, fall back to essid as that's the best we'll get (we don't get bssid either)...
|
|
if (p.netid and p.netid == network.netid) or (p.netid == nil and p.essid == network.essid) then
|
|
password = p.psk
|
|
break
|
|
end
|
|
end
|
|
end
|
|
table.insert(network_list, {
|
|
-- signal_level is purely for fun, the widget doesn't do anything with it. The WpaClient backend stores the raw dBa attenuation in it.
|
|
signal_level = string.format("%d/%d", network.signal, network.signal_max),
|
|
signal_quality = qualities[network.signal],
|
|
-- See comment above about netid being unfortunately optional...
|
|
connected = (current_profile.netid and current_profile.netid ~= -1 and current_profile.netid == network.netid)
|
|
or (current_profile.netid == nil and current_profile.essid ~= "" and current_profile.essid == network.essid),
|
|
flags = network.key_mgmt,
|
|
ssid = network.essid ~= "" and network.essid,
|
|
password = password,
|
|
})
|
|
end
|
|
return network_list, nil
|
|
end
|
|
|
|
function NetworkMgr:getCurrentNetwork()
|
|
return { ssid = kindleGetCurrentProfile().essid }
|
|
end
|
|
|
|
NetworkMgr.isWifiOn = NetworkMgr.sysfsWifiOn
|
|
NetworkMgr.isConnected = NetworkMgr.ifHasAnAddress
|
|
end
|
|
|
|
function Kindle:supportsScreensaver()
|
|
if self.isSpecialOffers then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
function Kindle:openInputDevices()
|
|
-- Auto-detect input devices (via FBInk's fbink_input_scan)
|
|
local ok, FBInkInput = pcall(ffi.load, "fbink_input")
|
|
if not ok then
|
|
-- NOP fallback for the testsuite...
|
|
FBInkInput = { fbink_input_scan = function() end }
|
|
end
|
|
local dev_count = ffi.new("size_t[1]")
|
|
-- We care about: the touchscreen, a properly scaled stylus, pagination buttons, a home button and a fiveway.
|
|
local match_mask = bit.bor(C.INPUT_TOUCHSCREEN, C.INPUT_SCALED_TABLET, C.INPUT_PAGINATION_BUTTONS, C.INPUT_HOME_BUTTON, C.INPUT_DPAD)
|
|
local devices = FBInkInput.fbink_input_scan(match_mask, 0, 0, dev_count)
|
|
if devices ~= nil then
|
|
for i = 0, tonumber(dev_count[0]) - 1 do
|
|
local dev = devices[i]
|
|
if dev.matched then
|
|
self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
|
end
|
|
end
|
|
C.free(devices)
|
|
else
|
|
-- Auto-detection failed, warn and fall back to defaults
|
|
logger.warn("We failed to auto-detect the proper input devices, input handling may be inconsistent!")
|
|
if self.touch_dev then
|
|
-- We've got a preferred path specified for the touch panel
|
|
self.input.open(self.touch_dev)
|
|
else
|
|
-- That generally works out well enough on legacy devices...
|
|
self.input.open("/dev/input/event0")
|
|
self.input.open("/dev/input/event1")
|
|
end
|
|
end
|
|
|
|
-- Getting the device where rotation events end up without catching a bunch of false-positives is... trickier,
|
|
-- thanks to the inane event code being used...
|
|
if self:hasGSensor() then
|
|
-- i.e., we want something that reports EV_ABS:ABS_PRESSURE that isn't *also* a pen (because those are pretty much guaranteed to report pressure...).
|
|
-- And let's add that isn't also a touchscreen to the mix, because while not true at time of writing, that's an event touchscreens sure can support...
|
|
devices = FBInkInput.fbink_input_scan(C.INPUT_ROTATION_EVENT, bit.bor(C.INPUT_TABLET, C.INPUT_TOUCHSCREEN), C.NO_RECAP, dev_count)
|
|
if devices ~= nil then
|
|
for i = 0, tonumber(dev_count[0]) - 1 do
|
|
local dev = devices[i]
|
|
if dev.matched then
|
|
self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
|
end
|
|
end
|
|
C.free(devices)
|
|
end
|
|
end
|
|
|
|
self.input.open("fake_events")
|
|
end
|
|
|
|
function Kindle:otaModel()
|
|
local model
|
|
if self:isTouchDevice() or self.model == "Kindle4" then
|
|
if isHardFP() then
|
|
model = "kindlehf"
|
|
elseif isWarioOrMore() then
|
|
model = "kindlepw2"
|
|
else
|
|
model = "kindle"
|
|
end
|
|
else
|
|
model = "kindle-legacy"
|
|
end
|
|
return model, "ota"
|
|
end
|
|
|
|
function Kindle:init()
|
|
-- Check if the device supports deep sleep/quick boot
|
|
if lfs.attributes("/sys/devices/platform/falconblk/uevent", "mode") == "file" then
|
|
-- Now, poke the appreg db to see if it's actually *enabled*...
|
|
-- NOTE: The setting is only available on registered devices, as such, it *can* be missing,
|
|
-- which is why we check for it existing and being *disabled*, as that ensures user interaction.
|
|
local SQ3 = require("lua-ljsqlite3/init")
|
|
local appreg = SQ3.open("/var/local/appreg.db", "ro")
|
|
local hibernation_disabled = tonumber(appreg:rowexec(
|
|
"SELECT EXISTS(SELECT value FROM properties WHERE handlerId = 'dcc' AND name = 'hibernate.enabled' AND value = 0);"
|
|
))
|
|
-- Check the actual delay while we're there...
|
|
local hibernation_delay =
|
|
appreg:rowexec("SELECT value FROM properties WHERE handlerId = 'dcc' AND name = 'hibernate.s2h.rtc.secs'") or
|
|
appreg:rowexec("SELECT value FROM properties WHERE handlerId = 'dcd' AND name = 'hibernate.s2h.rtc.secs'") or
|
|
3600
|
|
appreg:close()
|
|
if hibernation_disabled == 1 then
|
|
self.canDeepSleep = false
|
|
else
|
|
self.canDeepSleep = true
|
|
self.hibernationDelay = tonumber(hibernation_delay)
|
|
logger.dbg("Kindle: Device supports hibernation, enters hibernation after", self.hibernationDelay, "seconds in suspend")
|
|
end
|
|
else
|
|
self.canDeepSleep = false
|
|
end
|
|
|
|
-- If the device-specific init hasn't done so already (devices without keys don't), instantiate Input.
|
|
if not self.input then
|
|
self.input = require("device/input"):new{ device = self }
|
|
end
|
|
|
|
-- Auto-detect & open input devices
|
|
self:openInputDevices()
|
|
|
|
Generic.init(self)
|
|
end
|
|
|
|
function Kindle:setDateTime(year, month, day, hour, min, sec)
|
|
if hour == nil or min == nil then return true end
|
|
|
|
-- Prefer using the setdate wrapper if possible, as it will poke the native UI, too.
|
|
if lfs.attributes("/usr/sbin/setdate", "mode") == "file" then
|
|
local t = os.date("*t") -- Start with now to make sure we have a full table
|
|
t.year = year or t.year
|
|
t.month = month or t.month
|
|
t.day = day or t.day
|
|
t.hour = hour
|
|
t.min = min
|
|
t.sec = sec or t.sec
|
|
local epoch = os.time(t)
|
|
|
|
local command = string.format("/usr/sbin/setdate '%d'", epoch)
|
|
return os.execute(command) == 0
|
|
else
|
|
local command
|
|
if year and month and day then
|
|
command = string.format("date -s '%d-%d-%d %d:%d:%d' '+%%Y-%%m-%%d %%H:%%M:%%S'", year, month, day, hour, min, sec)
|
|
else
|
|
command = string.format("date -s '%d:%d' '+%%H:%%M'", hour, min)
|
|
end
|
|
if os.execute(command) == 0 then
|
|
os.execute("hwclock -u -w")
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
function Kindle:usbPlugIn()
|
|
-- NOTE: We cannot support running in USBMS mode (we cannot, we live on the partition being exported!).
|
|
-- But since that's the default state of the Kindle system, we have to try to make nice...
|
|
-- To that end, we're currently SIGSTOPping volumd to inhibit the system's USBMS mode handling.
|
|
-- It's not perfect (e.g., if the system is setup for USBMS and not USBNet,
|
|
-- the frontlight will be turned off when plugged in), but it at least prevents users from completely
|
|
-- shooting themselves in the foot (c.f., https://github.com/koreader/koreader/issues/3220)!
|
|
-- On the upside, we don't have to bother waking up the WM to show us the USBMS screen :D.
|
|
-- NOTE: If the device is put in USBNet mode before we even start, everything's peachy, though :).
|
|
end
|
|
|
|
-- Hopefully, the event sources are fairly portable...
|
|
-- c.f., https://github.com/koreader/koreader/pull/11174#issuecomment-1830064445
|
|
-- NOTE: There's no distinction between real button presses and powerd_test -p or lipc-set-prop -i com.lab126.powerd powerButton 1
|
|
local POWERD_EVENT_SOURCES = {
|
|
[1] = "BUTTON_WAKEUP", -- outOfScreenSaver 1
|
|
[2] = "BUTTON_SUSPEND", -- goingToScreenSaver 2
|
|
[4] = "HALL_SUSPEND", -- goingToScreenSaver 4
|
|
[6] = "HALL_WAKEUP", -- outOfScreenSaver 6
|
|
}
|
|
|
|
function Kindle:intoScreenSaver(source)
|
|
logger.dbg("Kindle:intoScreenSaver via", POWERD_EVENT_SOURCES[source] or string.format("UNKNOWN_SUSPEND (%d)", source or -1))
|
|
if not self.screen_saver_mode then
|
|
if self:supportsScreensaver() then
|
|
-- NOTE: Meaning this is not a SO device ;)
|
|
local Screensaver = require("ui/screensaver")
|
|
Screensaver:setup()
|
|
Screensaver:show()
|
|
else
|
|
-- Let the native system handle screensavers on SO devices...
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
elseif os.getenv("CVM_STOPPED") == "yes" then
|
|
os.execute("killall -CONT cvm")
|
|
end
|
|
|
|
-- Don't forget to flag ourselves in ScreenSaver mode like Screensaver:show would,
|
|
-- so that we do the right thing on resume ;).
|
|
self.screen_saver_mode = true
|
|
end
|
|
end
|
|
|
|
self.powerd:beforeSuspend()
|
|
end
|
|
|
|
function Kindle:outofScreenSaver(source)
|
|
logger.dbg("Kindle:outofScreenSaver via", POWERD_EVENT_SOURCES[source] or string.format("UNKNOWN_WAKEUP (%d)", source or -1))
|
|
if self.screen_saver_mode then
|
|
if self:supportsScreensaver() then
|
|
local Screensaver = require("ui/screensaver")
|
|
local widget_was_closed = Screensaver:close()
|
|
if widget_was_closed then
|
|
-- And redraw everything in case the framework managed to screw us over...
|
|
UIManager:nextTick(function() UIManager:setDirty("all", "full") end)
|
|
end
|
|
|
|
-- If the device supports deep sleep, and we woke up from hibernation (which kicks in at the 1H mark),
|
|
-- chuck an extra tiny refresh to get rid of the "waking up" banner if the above refresh was too early...
|
|
if self.canDeepSleep and self.last_suspend_time > time.s(self.hibernationDelay) then
|
|
if lfs.attributes("/var/local/system/powerd/hibernate_session_tracker", "mode") == "file" then
|
|
local mtime = lfs.attributes("/var/local/system/powerd/hibernate_session_tracker", "modification")
|
|
local now = os.time()
|
|
if math.abs(now - mtime) <= 60 then
|
|
-- That was less than a minute ago, assume we're golden.
|
|
logger.dbg("Kindle: Woke up from hibernation")
|
|
-- The banner on a 1236x1648 PW5 is 1235x125; we refresh the bottom 10% of the screen to be safe.
|
|
local Geom = require("ui/geometry")
|
|
local screen_height = self.screen:getHeight()
|
|
local refresh_height = math.ceil(screen_height * (1/10))
|
|
local refresh_region = Geom:new{
|
|
x = 0,
|
|
y = screen_height - 1 - refresh_height,
|
|
w = self.screen:getWidth(),
|
|
h = refresh_height
|
|
}
|
|
UIManager:scheduleIn(1.5, function()
|
|
UIManager:setDirty("all", "ui", refresh_region)
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- Stop awesome again if need be...
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -STOP awesome")
|
|
elseif os.getenv("CVM_STOPPED") == "yes" then
|
|
os.execute("killall -STOP cvm")
|
|
end
|
|
-- NOTE: We redraw after a slightly longer delay to take care of the potentially dynamic ad screen...
|
|
-- This is obviously brittle as all hell. Tested on a slow-ass PW1.
|
|
UIManager:scheduleIn(3, function() UIManager:setDirty("all", "full") end)
|
|
-- Flip the switch again
|
|
self.screen_saver_mode = false
|
|
end
|
|
end
|
|
|
|
self.powerd:afterResume()
|
|
end
|
|
|
|
-- On stock, there's a distinction between OutOfSS (which *requests* closing the SS) and ExitingSS, which fires once they're *actually* closed...
|
|
function Kindle:exitingScreenSaver() end
|
|
|
|
function Kindle:usbPlugOut()
|
|
-- NOTE: See usbPlugIn(), we don't have anything fancy to do here either.
|
|
end
|
|
|
|
function Kindle:wakeupFromSuspend(ts)
|
|
logger.dbg("Kindle:wakeupFromSuspend", ts)
|
|
self.powerd:wakeupFromSuspend(ts)
|
|
self.last_suspend_time = time.boottime_or_realtime_coarse() - self.suspend_time
|
|
self.total_suspend_time = self.total_suspend_time + self.last_suspend_time
|
|
end
|
|
|
|
function Kindle:readyToSuspend(delay)
|
|
logger.dbg("Kindle:readyToSuspend", delay)
|
|
self.powerd:readyToSuspend(delay)
|
|
self.suspend_time = time.boottime_or_realtime_coarse()
|
|
end
|
|
|
|
-- We add --no-same-permissions --no-same-owner to make the userstore fuse proxy happy...
|
|
function Kindle:untar(archive, extract_to)
|
|
return os.execute(("./tar --no-same-permissions --no-same-owner -xf %q -C %q"):format(archive, extract_to))
|
|
end
|
|
|
|
function Kindle:UIManagerReady(uimgr)
|
|
UIManager = uimgr
|
|
end
|
|
|
|
function Kindle:setEventHandlers(uimgr)
|
|
-- These custom fake events *will* pass an argument...
|
|
self.input.fake_event_args.IntoSS = {}
|
|
self.input.fake_event_args.OutOfSS = {}
|
|
self.input.fake_event_args.WakeupFromSuspend = {}
|
|
self.input.fake_event_args.ReadyToSuspend = {}
|
|
|
|
UIManager.event_handlers.Suspend = function()
|
|
self.powerd:toggleSuspend()
|
|
end
|
|
UIManager.event_handlers.IntoSS = function(input_event)
|
|
-- Retrieve the argument set by Input:handleKeyBoardEv
|
|
local arg = table.remove(self.input.fake_event_args[input_event])
|
|
self:intoScreenSaver(arg)
|
|
end
|
|
UIManager.event_handlers.OutOfSS = function(input_event)
|
|
local arg = table.remove(self.input.fake_event_args[input_event])
|
|
self:outofScreenSaver(arg)
|
|
end
|
|
UIManager.event_handlers.ExitingSS = function()
|
|
self:exitingScreenSaver()
|
|
end
|
|
UIManager.event_handlers.Charging = function()
|
|
self:_beforeCharging()
|
|
self:usbPlugIn()
|
|
end
|
|
UIManager.event_handlers.NotCharging = function()
|
|
self:usbPlugOut()
|
|
self:_afterNotCharging()
|
|
end
|
|
UIManager.event_handlers.WakeupFromSuspend = function(input_event)
|
|
local arg = table.remove(self.input.fake_event_args[input_event])
|
|
self:wakeupFromSuspend(arg)
|
|
end
|
|
UIManager.event_handlers.ReadyToSuspend = function(input_event)
|
|
local arg = table.remove(self.input.fake_event_args[input_event])
|
|
self:readyToSuspend(arg)
|
|
end
|
|
end
|
|
|
|
function Kindle:ambientBrightnessLevel()
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if not haslipc or lipc == nil then return 0 end
|
|
local lipc_handle = lipc.init("com.github.koreader.ambientbrightness")
|
|
if not lipc_handle then return 0 end
|
|
local value = lipc_handle:get_int_property("com.lab126.powerd", "alsLux")
|
|
lipc_handle:close()
|
|
if type(value) ~= "number" then return 0 end
|
|
if value < 10 then return 0 end
|
|
if value < 96 then return 1 end
|
|
if value < 192 then return 2 end
|
|
if value < 32768 then return 3 end
|
|
return 4
|
|
end
|
|
|
|
local Kindle2 = Kindle:extend{
|
|
model = "Kindle2",
|
|
isREAGL = no,
|
|
hasKeyboard = yes,
|
|
hasKeys = yes,
|
|
hasSymKey = yes,
|
|
hasDPad = yes,
|
|
useDPadAsActionKeys = yes,
|
|
canHWInvert = no,
|
|
canModifyFBInfo = no,
|
|
canUseCBB = no, -- 4bpp
|
|
canUseWAL = no, -- Kernel too old to support mmap'ed I/O on /mnt/us
|
|
supportsScreensaver = yes, -- The first ad-supported device was the K3
|
|
}
|
|
|
|
local KindleDXG = Kindle:extend{
|
|
model = "KindleDXG",
|
|
isREAGL = no,
|
|
hasKeyboard = yes,
|
|
hasKeys = yes,
|
|
hasSymKey = yes,
|
|
hasDPad = yes,
|
|
useDPadAsActionKeys = yes,
|
|
canHWInvert = no,
|
|
canModifyFBInfo = no,
|
|
canUseCBB = no, -- 4bpp
|
|
canUseWAL = no, -- Kernel too old to support mmap'ed I/O on /mnt/us
|
|
supportsScreensaver = yes, -- The first ad-supported device was the K3
|
|
}
|
|
|
|
local Kindle3 = Kindle:extend{
|
|
model = "Kindle3",
|
|
isREAGL = no,
|
|
hasKeyboard = yes,
|
|
hasKeys = yes,
|
|
hasSymKey = yes,
|
|
hasDPad = yes,
|
|
useDPadAsActionKeys = yes,
|
|
canHWInvert = no,
|
|
canModifyFBInfo = no,
|
|
canUseCBB = no, -- 4bpp
|
|
isSpecialOffers = hasSpecialOffers(),
|
|
}
|
|
|
|
local Kindle4 = Kindle:extend{
|
|
model = "Kindle4",
|
|
isREAGL = no,
|
|
hasKeys = yes,
|
|
hasScreenKB = yes,
|
|
hasDPad = yes,
|
|
useDPadAsActionKeys = yes,
|
|
canHWInvert = no,
|
|
canModifyFBInfo = no,
|
|
-- NOTE: It could *technically* use the C BB, as it's running @ 8bpp, but it's expecting an inverted palette...
|
|
canUseCBB = no,
|
|
isSpecialOffers = hasSpecialOffers(),
|
|
}
|
|
|
|
local KindleTouch = Kindle:extend{
|
|
model = "KindleTouch",
|
|
isREAGL = no,
|
|
isTouchDevice = yes,
|
|
hasKeys = yes,
|
|
touch_dev = "/dev/input/event3",
|
|
}
|
|
|
|
local KindlePaperWhite = Kindle:extend{
|
|
model = "KindlePaperWhite",
|
|
isREAGL = no,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
canTurnFrontlightOff = no,
|
|
display_dpi = 212,
|
|
touch_dev = "/dev/input/event0",
|
|
}
|
|
|
|
local KindlePaperWhite2 = Kindle:extend{
|
|
model = "KindlePaperWhite2",
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
canTurnFrontlightOff = no,
|
|
display_dpi = 212,
|
|
touch_dev = "/dev/input/event1",
|
|
}
|
|
|
|
local KindleBasic = Kindle:extend{
|
|
model = "KindleBasic",
|
|
isTouchDevice = yes,
|
|
touch_dev = "/dev/input/event1",
|
|
}
|
|
|
|
local KindleVoyage = Kindle:extend{
|
|
model = "KindleVoyage",
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
canTurnFrontlightOff = no,
|
|
hasLightSensor = yes,
|
|
hasKeys = yes,
|
|
display_dpi = 300,
|
|
touch_dev = "/dev/input/event1",
|
|
}
|
|
|
|
local KindlePaperWhite3 = Kindle:extend{
|
|
model = "KindlePaperWhite3",
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
canTurnFrontlightOff = no,
|
|
display_dpi = 300,
|
|
touch_dev = "/dev/input/event1",
|
|
}
|
|
|
|
local KindleOasis = Kindle:extend{
|
|
model = "KindleOasis",
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
hasKeys = yes,
|
|
hasGSensor = yes,
|
|
display_dpi = 300,
|
|
--[[
|
|
-- NOTE: Points to event3 on Wi-Fi devices, event4 on 3G devices...
|
|
-- 3G devices apparently have an extra SX9500 Proximity/Capacitive controller for mysterious purposes...
|
|
-- This evidently screws with the ordering, so, use the udev by-path path instead to avoid hackier workarounds.
|
|
-- cf. #2181
|
|
--]]
|
|
touch_dev = "/dev/input/by-path/platform-imx-i2c.1-event",
|
|
}
|
|
|
|
local KindleOasis2 = Kindle:extend{
|
|
model = "KindleOasis2",
|
|
isZelda = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
hasLightSensor = yes,
|
|
hasKeys = yes,
|
|
hasGSensor = yes,
|
|
display_dpi = 300,
|
|
touch_dev = "/dev/input/by-path/platform-30a30000.i2c-event",
|
|
}
|
|
|
|
local KindleOasis3 = Kindle:extend{
|
|
model = "KindleOasis3",
|
|
isZelda = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
hasNaturalLight = yes,
|
|
hasNaturalLightMixer = yes,
|
|
hasLightSensor = yes,
|
|
hasKeys = yes,
|
|
hasGSensor = yes,
|
|
display_dpi = 300,
|
|
touch_dev = "/dev/input/by-path/platform-30a30000.i2c-event",
|
|
}
|
|
|
|
local KindleBasic2 = Kindle:extend{
|
|
model = "KindleBasic2",
|
|
isTouchDevice = yes,
|
|
touch_dev = "/dev/input/event0",
|
|
}
|
|
|
|
local KindlePaperWhite4 = Kindle:extend{
|
|
model = "KindlePaperWhite4",
|
|
isRex = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
display_dpi = 300,
|
|
-- NOTE: LTE devices once again have a mysterious extra SX9310 proximity sensor...
|
|
-- Except this time, we can't rely on by-path, because there's no entry for the TS :/.
|
|
-- Should be event2 on Wi-Fi, event3 on LTE, we'll fix it in init.
|
|
touch_dev = "/dev/input/event2",
|
|
}
|
|
|
|
local KindleBasic3 = Kindle:extend{
|
|
model = "KindleBasic3",
|
|
isRex = yes,
|
|
-- NOTE: Apparently, the KT4 doesn't actually support the fancy nightmode waveforms, c.f., ko/#5076
|
|
-- It also doesn't handle HW dithering, c.f., base/#1039
|
|
isNightModeChallenged = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
touch_dev = "/dev/input/event2",
|
|
}
|
|
|
|
local KindlePaperWhite5 = Kindle:extend{
|
|
model = "KindlePaperWhite5",
|
|
isMTK = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
hasNaturalLight = yes,
|
|
-- NOTE: We *can* technically control both LEDs independently,
|
|
-- but the mix is device-specific, we don't have access to the LUT for the mix powerd is using,
|
|
-- and the widget is designed for the Kobo Aura One anyway, so, hahaha, nope.
|
|
hasNaturalLightMixer = yes,
|
|
display_dpi = 300,
|
|
-- NOTE: While hardware dithering (via MDP) should be a thing, it doesn't appear to do anything right now :/.
|
|
canHWDither = no,
|
|
canDoSwipeAnimation = yes,
|
|
-- NOTE: Input device path is variable, see findInputDevices
|
|
}
|
|
|
|
local KindleBasic4 = Kindle:extend{
|
|
model = "KindleBasic4",
|
|
isMTK = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
display_dpi = 300,
|
|
canHWDither = no,
|
|
canDoSwipeAnimation = yes,
|
|
-- NOTE: Like the PW5, input device path is variable, see findInputDevices
|
|
}
|
|
|
|
local KindleScribe = Kindle:extend{
|
|
model = "KindleScribe",
|
|
isMTK = yes,
|
|
isTouchDevice = yes,
|
|
hasFrontlight = yes,
|
|
hasNaturalLight = yes,
|
|
-- NOTE: We *can* technically control both LEDs independently,
|
|
-- but the mix is device-specific, we don't have access to the LUT for the mix powerd is using,
|
|
-- and the widget is designed for the Kobo Aura One anyway, so, hahaha, nope.
|
|
hasNaturalLightMixer = yes,
|
|
hasLightSensor = yes,
|
|
hasGSensor = yes,
|
|
display_dpi = 300,
|
|
touch_dev = "/dev/input/touch",
|
|
canHWDither = yes,
|
|
canDoSwipeAnimation = yes,
|
|
}
|
|
|
|
function Kindle2:init()
|
|
self.screen = require("ffi/framebuffer_einkfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
is_charging_file = "/sys/devices/platform/charger/charging",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = require("device/kindle/event_map_keyboard"),
|
|
}
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleDXG:init()
|
|
self.screen = require("ffi/framebuffer_einkfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
is_charging_file = "/sys/devices/platform/charger/charging",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = require("device/kindle/event_map_keyboard"),
|
|
}
|
|
self.keyboard_layout = require("device/kindle/keyboard_layout")
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function Kindle3:init()
|
|
self.screen = require("ffi/framebuffer_einkfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
batt_capacity_file = "/sys/devices/system/luigi_battery/luigi_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/platform/fsl-usb2-udc/charging",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = require("device/kindle/event_map_kindle4"),
|
|
}
|
|
self.keyboard_layout = require("device/kindle/keyboard_layout")
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function Kindle4:init()
|
|
self.screen = require("ffi/framebuffer_einkfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/platform/fsl-usb2-udc/charging",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = require("device/kindle/event_map_kindle4"),
|
|
}
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleTouch:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/platform/fsl-usb2-udc/charging",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
-- Kindle Touch has a single button
|
|
event_map = { [102] = "Home" },
|
|
}
|
|
|
|
-- Kindle Touch needs event modification for proper coordinates
|
|
self.input:registerEventAdjustHook(self.input.adjustTouchScale, {x=600/4095, y=800/4095})
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindlePaperWhite:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity",
|
|
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/platform/aplite_charger.0/charging",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindlePaperWhite2:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
|
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
|
batt_status_file = "/sys/class/power_supply/max77696-battery/status",
|
|
hall_file = "/sys/devices/system/wario_hall/wario_hall0/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleBasic:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
|
hall_file = "/sys/devices/system/wario_hall/wario_hall0/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleVoyage:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
|
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
|
hall_file = "/sys/devices/system/wario_hall/wario_hall0/hall_enable",
|
|
}
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
event_map = {
|
|
[104] = "LPgBack",
|
|
[109] = "LPgFwd",
|
|
},
|
|
}
|
|
-- touch gestures fall into these cold spots defined by (x, y, r)
|
|
-- will be rewritten to 'none' ges thus being ignored
|
|
-- x, y is the absolute position disregard of screen mode, r is spot radius
|
|
self.cold_spots = {
|
|
{
|
|
x = 1080 + 50, y = 485, r = 80
|
|
},
|
|
{
|
|
x = 1080 + 70, y = 910, r = 120
|
|
},
|
|
{
|
|
x = -50, y = 485, r = 80
|
|
},
|
|
{
|
|
x = -70, y = 910, r = 120
|
|
},
|
|
}
|
|
|
|
self.input:registerGestureAdjustHook(function(_, ges)
|
|
if ges then
|
|
local pos = ges.pos
|
|
for _, spot in ipairs(self.cold_spots) do
|
|
if (spot.x - pos.x) * (spot.x - pos.x) +
|
|
(spot.y - pos.y) * (spot.y - pos.y) < spot.r * spot.r then
|
|
ges.ges = "none"
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
Kindle.init(self)
|
|
|
|
-- Re-enable WhisperTouch keys when started without framework
|
|
if self.framework_lipc_handle then
|
|
self.framework_lipc_handle:set_int_property("com.lab126.deviced", "fsrkeypadEnable", 1)
|
|
self.framework_lipc_handle:set_int_property("com.lab126.deviced", "fsrkeypadPrevEnable", 1)
|
|
self.framework_lipc_handle:set_int_property("com.lab126.deviced", "fsrkeypadNextEnable", 1)
|
|
end
|
|
end
|
|
|
|
function KindlePaperWhite3:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
|
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
|
hall_file = "/sys/devices/system/wario_hall/wario_hall0/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
-- HAL for gyro orientation switches (EV_ABS:ABS_PRESSURE (?!) w/ custom values to EV_MSC:MSC_GYRO w/ our own custom values)
|
|
local function OasisGyroTranslation(this, ev)
|
|
local DEVICE_ORIENTATION_PORTRAIT_LEFT = 15
|
|
local DEVICE_ORIENTATION_PORTRAIT_RIGHT = 17
|
|
local DEVICE_ORIENTATION_PORTRAIT = 19
|
|
local DEVICE_ORIENTATION_PORTRAIT_ROTATED_LEFT = 16
|
|
local DEVICE_ORIENTATION_PORTRAIT_ROTATED_RIGHT = 18
|
|
local DEVICE_ORIENTATION_PORTRAIT_ROTATED = 20
|
|
local DEVICE_ORIENTATION_LANDSCAPE = 21
|
|
local DEVICE_ORIENTATION_LANDSCAPE_ROTATED = 22
|
|
|
|
if ev.type == C.EV_ABS and ev.code == C.ABS_PRESSURE then
|
|
if ev.value == DEVICE_ORIENTATION_PORTRAIT
|
|
or ev.value == DEVICE_ORIENTATION_PORTRAIT_LEFT
|
|
or ev.value == DEVICE_ORIENTATION_PORTRAIT_RIGHT then
|
|
-- i.e., UR
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_UPRIGHT
|
|
elseif ev.value == DEVICE_ORIENTATION_LANDSCAPE then
|
|
-- i.e., CW
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_CLOCKWISE
|
|
elseif ev.value == DEVICE_ORIENTATION_PORTRAIT_ROTATED
|
|
or ev.value == DEVICE_ORIENTATION_PORTRAIT_ROTATED_LEFT
|
|
or ev.value == DEVICE_ORIENTATION_PORTRAIT_ROTATED_RIGHT then
|
|
-- i.e., UD
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_UPSIDE_DOWN
|
|
elseif ev.value == DEVICE_ORIENTATION_LANDSCAPE_ROTATED then
|
|
-- i.e., CCW
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
|
end
|
|
end
|
|
end
|
|
|
|
function KindleOasis:init()
|
|
-- temporarily wake up awesome
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
end
|
|
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
|
-- NOTE: Points to the embedded battery. The one in the cover is codenamed "soda".
|
|
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
|
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
|
hall_file = "/sys/devices/system/wario_hall/wario_hall0/hall_enable",
|
|
}
|
|
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
|
|
event_map = {
|
|
[104] = "RPgFwd",
|
|
[109] = "RPgBack",
|
|
}
|
|
}
|
|
|
|
Kindle.init(self)
|
|
|
|
--- @note See comments in KindleOasis2:init() for details.
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if haslipc then
|
|
local lipc_handle = lipc.init("com.github.koreader.screen")
|
|
if lipc_handle then
|
|
local orientation_code = lipc_handle:get_string_property(
|
|
"com.lab126.winmgr", "accelerometer")
|
|
logger.dbg("orientation_code =", orientation_code)
|
|
local rotation_mode = 0
|
|
if orientation_code then
|
|
if orientation_code == "U" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
|
|
elseif orientation_code == "R" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_CLOCKWISE
|
|
elseif orientation_code == "D" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPSIDE_DOWN
|
|
elseif orientation_code == "L" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
|
end
|
|
end
|
|
if rotation_mode > 0 then
|
|
self.screen.native_rotation_mode = rotation_mode
|
|
end
|
|
self.screen:setRotationMode(rotation_mode)
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
-- put awesome back to sleep
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -STOP awesome")
|
|
end
|
|
|
|
self.input:registerEventAdjustHook(OasisGyroTranslation)
|
|
self.input.handleMiscEv = function(this, ev)
|
|
if ev.code == C.MSC_GYRO then
|
|
return this:handleGyroEv(ev)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- HAL for gyro orientation switches (EV_ABS:ABS_PRESSURE (?!) w/ custom values to EV_MSC:MSC_GYRO w/ our own custom values)
|
|
local function KindleGyroTransform(this, ev)
|
|
-- See source code:
|
|
-- c.f., drivers/input/misc/accel/bma2x2.c for KOA2/KOA3
|
|
-- c.f., drivers/input/misc/kx132/kx132.h for KS
|
|
local UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED = 15
|
|
local UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED = 16
|
|
local UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED = 17
|
|
local UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED = 18
|
|
|
|
if ev.type == C.EV_ABS and ev.code == C.ABS_PRESSURE then
|
|
if ev.value == UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED then
|
|
-- i.e., UR
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_UPRIGHT
|
|
elseif ev.value == UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED then
|
|
-- i.e., CW
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_CLOCKWISE
|
|
elseif ev.value == UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED then
|
|
-- i.e., UD
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_UPSIDE_DOWN
|
|
elseif ev.value == UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED then
|
|
-- i.e., CCW
|
|
ev.type = C.EV_MSC
|
|
ev.code = C.MSC_GYRO
|
|
ev.value = C.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
|
end
|
|
end
|
|
end
|
|
|
|
function KindleOasis2:init()
|
|
-- temporarily wake up awesome
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
end
|
|
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/max77796-bl/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/max77796-battery/capacity",
|
|
is_charging_file = "/sys/class/power_supply/max77796-charger/charging",
|
|
batt_status_file = "/sys/class/power_supply/max77796-charger/status",
|
|
}
|
|
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
|
|
-- Top, Bottom (yes, it's the reverse than on non-Oasis devices)
|
|
event_map = {
|
|
[104] = "RPgFwd",
|
|
[109] = "RPgBack",
|
|
}
|
|
}
|
|
|
|
Kindle.init(self)
|
|
|
|
--- @note When starting KOReader with the device upside down ("D"), touch input is registered wrong
|
|
-- (i.e., probably upside down).
|
|
-- If it's started upright ("U"), everything's okay, and turning it upside down after that works just fine.
|
|
-- See #2206 & #2209 for the original KOA implementation, which obviously doesn't quite cut it here...
|
|
-- See also <https://www.mobileread.com/forums/showthread.php?t=298302&page=5>
|
|
-- See also #11159 for details about the solution (Kindle Scribe as an example)
|
|
-- In regular mode, awesome is woken up for a brief moment for lipc calls.
|
|
-- In no-framework mode, this works as is.
|
|
-- NOTE: It'd take some effort to actually start KOReader while in a LANDSCAPE orientation,
|
|
-- since they're only exposed inside the stock reader, and not the Home/KUAL Booklets.
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if haslipc then
|
|
local lipc_handle = lipc.init("com.github.koreader.screen")
|
|
if lipc_handle then
|
|
local orientation_code = lipc_handle:get_string_property(
|
|
"com.lab126.winmgr", "accelerometer")
|
|
logger.dbg("orientation_code =", orientation_code)
|
|
local rotation_mode = 0
|
|
if orientation_code then
|
|
if orientation_code == "U" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
|
|
elseif orientation_code == "R" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_CLOCKWISE
|
|
elseif orientation_code == "D" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPSIDE_DOWN
|
|
elseif orientation_code == "L" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
|
end
|
|
end
|
|
if rotation_mode > 0 then
|
|
self.screen.native_rotation_mode = rotation_mode
|
|
end
|
|
self.screen:setRotationMode(rotation_mode)
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
-- put awesome back to sleep
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -STOP awesome")
|
|
end
|
|
|
|
self.input:registerEventAdjustHook(KindleGyroTransform)
|
|
self.input.handleMiscEv = function(this, ev)
|
|
if ev.code == C.MSC_GYRO then
|
|
return this:handleGyroEv(ev)
|
|
end
|
|
end
|
|
end
|
|
|
|
function KindleOasis3:init()
|
|
-- temporarily wake up awesome
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
end
|
|
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/lm3697-bl1/brightness",
|
|
warmth_intensity_file = "/sys/class/backlight/lm3697-bl0/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/max77796-battery/capacity",
|
|
is_charging_file = "/sys/class/power_supply/max77796-charger/charging",
|
|
batt_status_file = "/sys/class/power_supply/max77796-charger/status",
|
|
}
|
|
|
|
self.input = require("device/input"):new{
|
|
device = self,
|
|
|
|
-- Top, Bottom (yes, it's the reverse than on non-Oasis devices)
|
|
event_map = {
|
|
[104] = "RPgFwd",
|
|
[109] = "RPgBack",
|
|
}
|
|
}
|
|
|
|
Kindle.init(self)
|
|
|
|
--- @note The same quirks as on the Oasis 2 apply ;).
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if haslipc then
|
|
local lipc_handle = lipc.init("com.github.koreader.screen")
|
|
if lipc_handle then
|
|
local orientation_code = lipc_handle:get_string_property(
|
|
"com.lab126.winmgr", "accelerometer")
|
|
logger.dbg("orientation_code =", orientation_code)
|
|
local rotation_mode = 0
|
|
if orientation_code then
|
|
if orientation_code == "U" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
|
|
elseif orientation_code == "R" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_CLOCKWISE
|
|
elseif orientation_code == "D" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPSIDE_DOWN
|
|
elseif orientation_code == "L" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
|
end
|
|
end
|
|
if rotation_mode > 0 then
|
|
self.screen.native_rotation_mode = rotation_mode
|
|
end
|
|
self.screen:setRotationMode(rotation_mode)
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
-- put awesome back to sleep
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -STOP awesome")
|
|
end
|
|
|
|
self.input:registerEventAdjustHook(KindleGyroTransform)
|
|
self.input.handleMiscEv = function(this, ev)
|
|
if ev.code == C.MSC_GYRO then
|
|
return this:handleGyroEv(ev)
|
|
end
|
|
end
|
|
end
|
|
|
|
function KindleBasic2:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
batt_capacity_file = "/sys/class/power_supply/bd7181x_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd7181x_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd7181x_bat/status",
|
|
hall_file = "/sys/devices/system/heisenberg_hall/heisenberg_hall0/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindlePaperWhite4:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/bl/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/bd71827_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd71827_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd71827_bat/status",
|
|
hall_file = "/sys/bus/platform/drivers/hall_sensor/rex_hall/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleBasic3:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/bl/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/bd71827_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd71827_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd71827_bat/status",
|
|
hall_file = "/sys/bus/platform/drivers/hall_sensor/rex_hall/hall_enable",
|
|
}
|
|
|
|
Kindle.init(self)
|
|
|
|
-- This device doesn't emit ABS_MT_TRACKING_ID:-1 events on contact lift,
|
|
-- so we have to rely on contact lift detection via BTN_TOUCH:0,
|
|
-- c.f., https://github.com/koreader/koreader/issues/5070
|
|
self.input.snow_protocol = true
|
|
end
|
|
|
|
function KindlePaperWhite5:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/fp9966-bl1/brightness",
|
|
warmth_intensity_file = "/sys/class/backlight/fp9966-bl0/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/bd71827_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd71827_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd71827_bat/status",
|
|
hall_file = "/sys/devices/platform/eink_hall/hall_enable",
|
|
}
|
|
|
|
-- Enable the so-called "fast" mode, so as to prevent the driver from silently promoting refreshes to REAGL.
|
|
self.screen:_MTK_ToggleFastMode(true)
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleBasic4:init()
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/fp9966-bl1/brightness",
|
|
warmth_intensity_file = "/sys/class/backlight/fp9966-bl0/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/bd71827_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd71827_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd71827_bat/status",
|
|
}
|
|
|
|
-- Enable the so-called "fast" mode, so as to prevent the driver from silently promoting refreshes to REAGL.
|
|
self.screen:_MTK_ToggleFastMode(true)
|
|
|
|
Kindle.init(self)
|
|
end
|
|
|
|
function KindleScribe:init()
|
|
-- temporarily wake up awesome
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
end
|
|
|
|
self.screen = require("ffi/framebuffer_mxcfb"):new{device = self, debug = logger.dbg}
|
|
self.powerd = require("device/kindle/powerd"):new{
|
|
device = self,
|
|
fl_intensity_file = "/sys/class/backlight/fp9966-bl1/brightness",
|
|
warmth_intensity_file = "/sys/class/backlight/fp9966-bl0/brightness",
|
|
batt_capacity_file = "/sys/class/power_supply/bd71827_bat/capacity",
|
|
is_charging_file = "/sys/class/power_supply/bd71827_bat/charging",
|
|
batt_status_file = "/sys/class/power_supply/bd71827_bat/status",
|
|
hall_file = "/sys/devices/platform/eink_hall/hall_enable",
|
|
}
|
|
|
|
-- Enable the so-called "fast" mode, so as to prevent the driver from silently promoting refreshes to REAGL.
|
|
self.screen:_MTK_ToggleFastMode(true)
|
|
|
|
Kindle.init(self)
|
|
|
|
--- @note The same quirks as on the Oasis 2 and 3 apply ;).
|
|
local haslipc, lipc = pcall(require, "liblipclua")
|
|
if haslipc then
|
|
local lipc_handle = lipc.init("com.github.koreader.screen")
|
|
if lipc_handle then
|
|
local orientation_code = lipc_handle:get_string_property(
|
|
"com.lab126.winmgr", "accelerometer")
|
|
logger.dbg("orientation_code =", orientation_code)
|
|
local rotation_mode = 0
|
|
if orientation_code then
|
|
if orientation_code == "U" or "L" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
|
|
elseif orientation_code == "D" or "R" then
|
|
rotation_mode = self.screen.DEVICE_ROTATED_UPSIDE_DOWN
|
|
end
|
|
end
|
|
if rotation_mode > 0 then
|
|
self.screen.native_rotation_mode = rotation_mode
|
|
end
|
|
self.screen:setRotationMode(rotation_mode)
|
|
lipc_handle:close()
|
|
end
|
|
end
|
|
-- put awesome back to sleep
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -STOP awesome")
|
|
end
|
|
|
|
-- Setup accelerometer rotation input
|
|
self.input:registerEventAdjustHook(KindleGyroTransform)
|
|
self.input.handleMiscEv = function(this, ev)
|
|
if ev.code == C.MSC_GYRO then
|
|
return this:handleGyroEv(ev)
|
|
end
|
|
end
|
|
|
|
-- Setup pen input
|
|
self.input.wacom_protocol = true
|
|
end
|
|
|
|
function KindleTouch:exit()
|
|
if self:isMTK() then
|
|
-- Disable the so-called "fast" mode
|
|
self.screen:_MTK_ToggleFastMode(false)
|
|
end
|
|
|
|
if self.framework_lipc_handle then
|
|
-- Fixes missing *stock Amazon UI* screensavers on exiting out of "no framework" started KOReader
|
|
-- module was unloaded in frameworkStopped() function but wasn't (re)loaded on KOReader exit
|
|
self.framework_lipc_handle:set_string_property("com.lab126.blanket", "load", "screensaver")
|
|
self.framework_lipc_handle:close()
|
|
end
|
|
|
|
self.powerd:__gc()
|
|
|
|
Generic.exit(self)
|
|
|
|
if self.isSpecialOffers then
|
|
-- Wakey wakey...
|
|
if os.getenv("AWESOME_STOPPED") == "yes" then
|
|
os.execute("killall -CONT awesome")
|
|
end
|
|
-- fake a touch event
|
|
if self.touch_dev then
|
|
local width, height = self.screen:getScreenWidth(), self.screen:getScreenHeight()
|
|
require("ffi/input").fakeTapInput(self.touch_dev,
|
|
math.min(width, height)/2,
|
|
math.max(width, height)-30
|
|
)
|
|
end
|
|
end
|
|
end
|
|
KindlePaperWhite.exit = KindleTouch.exit
|
|
KindlePaperWhite2.exit = KindleTouch.exit
|
|
KindleBasic.exit = KindleTouch.exit
|
|
KindleVoyage.exit = KindleTouch.exit
|
|
KindlePaperWhite3.exit = KindleTouch.exit
|
|
KindleOasis.exit = KindleTouch.exit
|
|
KindleOasis2.exit = KindleTouch.exit
|
|
KindleBasic2.exit = KindleTouch.exit
|
|
KindlePaperWhite4.exit = KindleTouch.exit
|
|
KindleBasic3.exit = KindleTouch.exit
|
|
KindleOasis3.exit = KindleTouch.exit
|
|
KindlePaperWhite5.exit = KindleTouch.exit
|
|
KindleBasic4.exit = KindleTouch.exit
|
|
KindleScribe.exit = KindleTouch.exit
|
|
|
|
function Kindle3:exit()
|
|
-- send double menu key press events to trigger screen refresh
|
|
os.execute("echo 'send 139' > /proc/keypad;echo 'send 139' > /proc/keypad")
|
|
|
|
Generic.exit(self)
|
|
end
|
|
|
|
KindleDXG.exit = Kindle3.exit
|
|
|
|
|
|
----------------- device recognition: -------------------
|
|
|
|
local function Set(list)
|
|
local set = {}
|
|
for _, l in ipairs(list) do set[l] = true end
|
|
return set
|
|
end
|
|
|
|
|
|
local kindle_sn_fd = io.open("/proc/usid", "r")
|
|
if not kindle_sn_fd then return end
|
|
local kindle_sn = kindle_sn_fd:read("*line")
|
|
kindle_sn_fd:close()
|
|
-- NOTE: Attempt to sanely differentiate v1 from v2,
|
|
-- c.f., https://github.com/NiLuJe/FBInk/commit/8a1161734b3f5b4461247af461d26987f6f1632e
|
|
local kindle_sn_lead = string.sub(kindle_sn, 1, 1)
|
|
|
|
-- NOTE: Update me when new devices come out :)
|
|
-- c.f., https://wiki.mobileread.com/wiki/Kindle_Serial_Numbers for identified variants
|
|
-- c.f., https://github.com/NiLuJe/KindleTool/blob/master/KindleTool/kindle_tool.h#L174 for all variants
|
|
local k2_set = Set { "02", "03" }
|
|
local dx_set = Set { "04", "05" }
|
|
local dxg_set = Set { "09" }
|
|
local k3_set = Set { "08", "06", "0A" }
|
|
local k4_set = Set { "0E", "23" }
|
|
local touch_set = Set { "0F", "11", "10", "12" }
|
|
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
|
|
local pw2_set = Set { "D4", "5A", "D5", "D6", "D7", "D8", "F2", "17",
|
|
"60", "F4", "F9", "62", "61", "5F" }
|
|
local kt2_set = Set { "C6", "DD" }
|
|
local kv_set = Set { "13", "54", "2A", "4F", "52", "53" }
|
|
local pw3_set = Set { "0G1", "0G2", "0G4", "0G5", "0G6", "0G7",
|
|
"0KB", "0KC", "0KD", "0KE", "0KF", "0KG", "0LK", "0LL" }
|
|
local koa_set = Set { "0GC", "0GD", "0GR", "0GS", "0GT", "0GU" }
|
|
local koa2_set = Set { "0LM", "0LN", "0LP", "0LQ", "0P1", "0P2", "0P6",
|
|
"0P7", "0P8", "0S1", "0S2", "0S3", "0S4", "0S7", "0SA" }
|
|
local kt3_set = Set { "0DU", "0K9", "0KA" }
|
|
local pw4_set = Set { "0PP", "0T1", "0T2", "0T3", "0T4", "0T5", "0T6",
|
|
"0T7", "0TJ", "0TK", "0TL", "0TM", "0TN", "102", "103",
|
|
"16Q", "16R", "16S", "16T", "16U", "16V" }
|
|
local kt4_set = Set { "10L", "0WF", "0WG", "0WH", "0WJ", "0VB" }
|
|
local koa3_set = Set { "11L", "0WQ", "0WP", "0WN", "0WM", "0WL" }
|
|
local pw5_set = Set { "1LG", "1Q0", "1PX", "1VD", "219", "21A", "2BH", "2BJ", "2DK" }
|
|
local kt5_set = Set { "22D", "25T", "23A", "2AQ", "2AP", "1XH", "22C" }
|
|
local ks_set = Set { "27J", "2BL", "263", "227", "2BM", "23L", "23M", "270" }
|
|
|
|
if kindle_sn_lead == "B" or kindle_sn_lead == "9" then
|
|
local kindle_devcode = string.sub(kindle_sn, 3, 4)
|
|
|
|
if k2_set[kindle_devcode] then
|
|
return Kindle2
|
|
elseif dx_set[kindle_devcode] then
|
|
return Kindle2
|
|
elseif dxg_set[kindle_devcode] then
|
|
return KindleDXG
|
|
elseif k3_set[kindle_devcode] then
|
|
return Kindle3
|
|
elseif k4_set[kindle_devcode] then
|
|
return Kindle4
|
|
elseif touch_set[kindle_devcode] then
|
|
return KindleTouch
|
|
elseif pw_set[kindle_devcode] then
|
|
return KindlePaperWhite
|
|
elseif pw2_set[kindle_devcode] then
|
|
return KindlePaperWhite2
|
|
elseif kt2_set[kindle_devcode] then
|
|
return KindleBasic
|
|
elseif kv_set[kindle_devcode] then
|
|
return KindleVoyage
|
|
end
|
|
else
|
|
local kindle_devcode_v2 = string.sub(kindle_sn, 4, 6)
|
|
|
|
if pw3_set[kindle_devcode_v2] then
|
|
return KindlePaperWhite3
|
|
elseif koa_set[kindle_devcode_v2] then
|
|
return KindleOasis
|
|
elseif koa2_set[kindle_devcode_v2] then
|
|
return KindleOasis2
|
|
elseif kt3_set[kindle_devcode_v2] then
|
|
return KindleBasic2
|
|
elseif pw4_set[kindle_devcode_v2] then
|
|
return KindlePaperWhite4
|
|
elseif kt4_set[kindle_devcode_v2] then
|
|
return KindleBasic3
|
|
elseif koa3_set[kindle_devcode_v2] then
|
|
return KindleOasis3
|
|
elseif pw5_set[kindle_devcode_v2] then
|
|
return KindlePaperWhite5
|
|
elseif kt5_set[kindle_devcode_v2] then
|
|
return KindleBasic4
|
|
elseif ks_set[kindle_devcode_v2] then
|
|
return KindleScribe
|
|
end
|
|
end
|
|
|
|
local kindle_sn_prefix = string.sub(kindle_sn, 1, 6)
|
|
error("unknown Kindle model: " .. kindle_sn_prefix)
|