diff --git a/base b/base index 13f0d3dec..85d96920d 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 13f0d3decc2c5c4cc7a1f17dfad8fd5d53721e68 +Subproject commit 85d96920d952ccb0f47f054df179a230a2a7544f diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index 7736b53d1..1d2f75ddf 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -434,7 +434,7 @@ To: }, } } - if Device:isKobo() then + if Device:isKobo() and not Device:isSunxi() then table.insert(self.menu_items.developer_options.sub_item_table, { text = _("Disable forced 8-bit pixel depth"), checked_func = function() @@ -524,7 +524,7 @@ To: if Device:hasEinkScreen() and Device:isKobo() then table.insert(self.menu_items.developer_options.sub_item_table, { -- @translators Highly technical (ioctl is a Linux API call, the uppercase stuff is a constant). What's translatable is essentially only the action ("bypass") and the article. - text = _("Bypass the MXCFB_WAIT_FOR_* ioctls"), + text = _("Bypass the WAIT_FOR ioctls"), checked_func = function() local mxcfb_bypass_wait_for if G_reader_settings:has("mxcfb_bypass_wait_for") then diff --git a/frontend/device/input.lua b/frontend/device/input.lua index 5620d55b1..9d506c87b 100644 --- a/frontend/device/input.lua +++ b/frontend/device/input.lua @@ -88,6 +88,7 @@ local linux_evdev_key_code_map = { [C.BTN_TOOL_RUBBER] = "BTN_TOOL_RUBBER", [C.BTN_TOUCH] = "BTN_TOUCH", [C.BTN_STYLUS] = "BTN_STYLUS", + [C.BTN_STYLUS2] = "BTN_STYLUS2", } local linux_evdev_abs_code_map = { @@ -589,6 +590,9 @@ function Input:handleTouchEv(ev) self:setCurrentMtSlot("x", ev.value) elseif ev.code == C.ABS_MT_POSITION_Y then self:setCurrentMtSlot("y", ev.value) + elseif ev.code == C.ABS_MT_PRESSURE and ev.value == 0 then + -- Drop hovering pen events + self:setCurrentMtSlot("id", -1) -- code to emulate mt protocol on kobos -- we "confirm" abs_x, abs_y only when pressure ~= 0 @@ -1101,30 +1105,33 @@ function Input:waitEvent(now, deadline) -- We're guaranteed that ev is an array of event tables. Might be an array of *one* event, but an array nonetheless ;). for __, event in ipairs(ev) do if DEBUG.is_on then + -- NOTE: This is rather spammy and computationally intensive, + -- and we can't conditionally prevent evalutation of function arguments, + -- so, just hide the whole thing behind a branch ;). DEBUG:logEv(event) if event.type == C.EV_KEY then logger.dbg(string.format( - "key event => code: %d (%s), value: %s, time: %d.%d", + "key event => code: %d (%s), value: %s, time: %d.%06d", event.code, self.event_map[event.code] or linux_evdev_key_code_map[event.code], event.value, event.time.sec, event.time.usec)) elseif event.type == C.EV_SYN then logger.dbg(string.format( - "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%d", + "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%06d", event.type, linux_evdev_type_map[event.type], event.code, linux_evdev_syn_code_map[event.code], event.value, event.time.sec, event.time.usec)) elseif event.type == C.EV_ABS then logger.dbg(string.format( - "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%d", + "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%06d", event.type, linux_evdev_type_map[event.type], event.code, linux_evdev_abs_code_map[event.code], event.value, event.time.sec, event.time.usec)) elseif event.type == C.EV_MSC then logger.dbg(string.format( - "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%d", + "input event => type: %d (%s), code: %d (%s), value: %s, time: %d.%06d", event.type, linux_evdev_type_map[event.type], event.code, linux_evdev_msc_code_map[event.code], event.value, event.time.sec, event.time.usec)) else logger.dbg(string.format( - "input event => type: %d (%s), code: %d, value: %s, time: %d.%d", + "input event => type: %d (%s), code: %d, value: %s, time: %d.%06d", event.type, linux_evdev_type_map[event.type], event.code, event.value, event.time.sec, event.time.usec)) end diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index 0f7f6e55c..0db85505e 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -5,6 +5,11 @@ local logger = require("logger") local util = require("ffi/util") local _ = require("gettext") +-- We're going to need a few constants... +local ffi = require("ffi") +local C = ffi.C +require("ffi/linux_fb_h") + local function yes() return true end local function no() return false end @@ -53,6 +58,16 @@ local Kobo = Generic:new{ isMk7 = no, -- MXCFB_WAIT_FOR_UPDATE_COMPLETE ioctls are generally reliable hasReliableMxcWaitFor = yes, + -- Sunxi devices require a completely different fb backend... + isSunxi = no, + -- On sunxi, "native" panel layout used to compute the G2D rotation handle (e.g., deviceQuirks.nxtBootRota in FBInk). + boot_rota = nil, + -- Standard sysfs path to the battery directory + battery_sysfs = "/sys/class/power_supply/mc13892_bat", + -- Stable path to the NTX input device + ntx_dev = "/dev/input/event0", + -- Stable path to the Touch input device + touch_dev = "/dev/input/event1", } --- @todo hasKeys for some devices? @@ -288,6 +303,22 @@ local KoboLuna = Kobo:new{ display_dpi = 212, } +-- Kobo Elipsa +local KoboEuropa = Kobo:new{ + model = "Kobo_europa", + isSunxi = yes, + canToggleChargingLED = yes, + hasFrontlight = yes, + hasGSensor = yes, + canToggleGSensor = yes, + misc_ntx_gsensor_protocol = true, + display_dpi = 227, + boot_rota = C.FB_ROTATE_CCW, + battery_sysfs = "/sys/class/power_supply/battery", + ntx_dev = "/dev/input/by-path/platform-ntx_event0-event", + touch_dev = "/dev/input/by-path/platform-0-0010-event", +} + function Kobo:init() -- Check if we need to disable MXCFB_WAIT_FOR_UPDATE_COMPLETE ioctls... local mxcfb_bypass_wait_for @@ -297,16 +328,29 @@ function Kobo:init() mxcfb_bypass_wait_for = not self:hasReliableMxcWaitFor() end - self.screen = require("ffi/framebuffer_mxcfb"):new{ - device = self, - debug = logger.dbg, - is_always_portrait = self.isAlwaysPortrait(), - mxcfb_bypass_wait_for = mxcfb_bypass_wait_for, - } - if self.screen.fb_bpp == 32 then - -- Ensure we decode images properly, as our framebuffer is BGRA... - logger.info("Enabling Kobo @ 32bpp BGR tweaks") - self.hasBGRFrameBuffer = yes + if self:isSunxi() then + self.screen = require("ffi/framebuffer_sunxi"):new{ + device = self, + debug = logger.dbg, + is_always_portrait = self.isAlwaysPortrait(), + mxcfb_bypass_wait_for = mxcfb_bypass_wait_for, + boot_rota = self.boot_rota, + } + + -- Sunxi means no HW inversion :( + self.canHWInvert = no + else + self.screen = require("ffi/framebuffer_mxcfb"):new{ + device = self, + debug = logger.dbg, + is_always_portrait = self.isAlwaysPortrait(), + mxcfb_bypass_wait_for = mxcfb_bypass_wait_for, + } + if self.screen.fb_bpp == 32 then + -- Ensure we decode images properly, as our framebuffer is BGRA... + logger.info("Enabling Kobo @ 32bpp BGR tweaks") + self.hasBGRFrameBuffer = yes + end end -- Automagically set this so we never have to remember to do it manually ;p @@ -318,17 +362,23 @@ function Kobo:init() self.canHWDither = yes end - self.powerd = require("device/kobo/powerd"):new{device = self} + self.powerd = require("device/kobo/powerd"):new{ + device = self, + battery_sysfs = self.battery_sysfs, + } -- NOTE: For the Forma, with the buttons on the right, 193 is Top, 194 Bottom. self.input = require("device/input"):new{ device = self, event_map = { + [35] = "SleepCover", -- KEY_H, Elipsa [59] = "SleepCover", [90] = "LightButton", [102] = "Home", [116] = "Power", [193] = "RPgBack", [194] = "RPgFwd", + [331] = "Eraser", + [332] = "Highlighter", }, event_map_adapter = { SleepCover = function(ev) @@ -350,8 +400,8 @@ function Kobo:init() Generic.init(self) -- When present, event2 is the raw accelerometer data (3-Axis Orientation/Motion Detection) - self.input.open("/dev/input/event0") -- Various HW Buttons, Switches & Synthetic NTX events - self.input.open("/dev/input/event1") + self.input.open(self.ntx_dev) -- Various HW Buttons, Switches & Synthetic NTX events + self.input.open(self.touch_dev) -- fake_events is only used for usb plug event so far -- NOTE: usb hotplug event is also available in /tmp/nickel-hardware-status (... but only when Nickel is running ;p) self.input.open("fake_events") @@ -791,7 +841,8 @@ function Kobo:toggleChargingLED(toggle) -- we've seen *extremely* weird behavior in the past when playing with it on older devices (c.f., #5479). -- In fact, Nickel itself doesn't provide this feature on said older devices -- (when it does, it's an option in the Energy saving settings), - -- which is why we also limit ourselves to "true" Mk. 7 devices. + -- which is why we also limit ourselves to "true" on devices where this was tested. + -- c.f., drivers/misc/ntx_misc_light.c local f = io.open("/sys/devices/platform/ntx_led/lit", "w") if not f then logger.err("cannot open /sys/devices/platform/ntx_led/lit for writing!") @@ -800,9 +851,18 @@ function Kobo:toggleChargingLED(toggle) -- c.f., strace -fittvyy -e trace=ioctl,file,signal,ipc,desc -s 256 -o /tmp/nickel.log -p $(pidof -s nickel) & -- This was observed on a Forma, so I'm mildly hopeful that it's safe on other Mk. 7 devices ;). + -- NOTE: ch stands for channel, cur for current, dc for duty cycle. c.f., the driver source. if toggle == true then -- NOTE: Technically, Nickel forces a toggle off before that, too. -- But since we do that on startup, it shouldn't be necessary here... + if self:isSunxi() then + f:write("ch 3") + f:flush() + f:write("cur 1") + f:flush() + f:write("dc 63") + f:flush() + end f:write("ch 4") f:flush() f:write("cur 1") @@ -881,6 +941,8 @@ elseif codename == "storm" then return KoboStorm elseif codename == "luna" then return KoboLuna +elseif codename == "europa" then + return KoboEuropa else error("unrecognized Kobo model "..codename) end diff --git a/frontend/device/kobo/powerd.lua b/frontend/device/kobo/powerd.lua index e4326e12d..af5d429a7 100644 --- a/frontend/device/kobo/powerd.lua +++ b/frontend/device/kobo/powerd.lua @@ -5,9 +5,6 @@ local SysfsLight = require ("device/sysfs_light") local ffiUtil = require("ffi/util") local RTC = require("ffi/rtc") -local batt_state_folder = - "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/" - -- Here, we only deal with the real hw intensity. -- Dealing with toggling and remembering/restoring -- previous intensity when toggling/untoggling is done @@ -17,8 +14,7 @@ local KoboPowerD = BasePowerD:new{ fl_min = 0, fl_max = 100, fl = nil, - batt_capacity_file = batt_state_folder .. "capacity", - is_charging_file = batt_state_folder .. "status", + battery_sysfs = nil, fl_warmth_min = 0, fl_warmth_max = 100, fl_warmth = nil, auto_warmth = false, @@ -108,6 +104,10 @@ function KoboPowerD:_syncKoboLightOnStart() end function KoboPowerD:init() + -- Setup the sysfs paths + self.batt_capacity_file = self.battery_sysfs .. "/capacity" + self.is_charging_file = self.battery_sysfs .. "/status" + -- Default values in case self:_syncKoboLightOnStart() does not find -- any previously saved setting (and for unit tests where it will -- not be called) diff --git a/platform/kobo/disable-wifi.sh b/platform/kobo/disable-wifi.sh index 32722c0de..6af2d5580 100755 --- a/platform/kobo/disable-wifi.sh +++ b/platform/kobo/disable-wifi.sh @@ -35,7 +35,7 @@ fi wpa_cli terminate -[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && [ "${WIFI_MODULE}" != "8821cs" ] && wlarm_le -i "${INTERFACE}" down +[ "${WIFI_MODULE}" = "dhd" ] && wlarm_le -i "${INTERFACE}" down ifconfig "${INTERFACE}" down # Some sleep in between may avoid system getting hung diff --git a/platform/kobo/enable-wifi.sh b/platform/kobo/enable-wifi.sh index 6c2d8aad8..f25457f7f 100755 --- a/platform/kobo/enable-wifi.sh +++ b/platform/kobo/enable-wifi.sh @@ -28,12 +28,19 @@ fi # Moar sleep! usleep 250000 # NOTE: Used to be exported in WIFI_MODULE_PATH before FW 4.23 -grep -q "${WIFI_MODULE}" "/proc/modules" || insmod "/drivers/${PLATFORM}/wifi/${WIFI_MODULE}.ko" +if ! grep -q "${WIFI_MODULE}" "/proc/modules"; then + if [ -e "/drivers/${PLATFORM}/wifi/${WIFI_MODULE}.ko" ]; then + insmod "/drivers/${PLATFORM}/wifi/${WIFI_MODULE}.ko" + elif [ -e "/drivers/${PLATFORM}/${WIFI_MODULE}.ko" ]; then + # NOTE: Modules are unsorted on Mk. 8 + insmod "/drivers/${PLATFORM}/${WIFI_MODULE}.ko" + fi +fi # Race-y as hell, don't try to optimize this! sleep 1 ifconfig "${INTERFACE}" up -[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && [ "${WIFI_MODULE}" != "8821cs" ] && wlarm_le -i "${INTERFACE}" up +[ "${WIFI_MODULE}" = "dhd" ] && wlarm_le -i "${INTERFACE}" up pkill -0 wpa_supplicant || env -u LD_LIBRARY_PATH \ diff --git a/platform/kobo/koreader.sh b/platform/kobo/koreader.sh index be92ac95b..60ef17b18 100755 --- a/platform/kobo/koreader.sh +++ b/platform/kobo/koreader.sh @@ -241,6 +241,36 @@ if [ -z "${INTERFACE}" ]; then export INTERFACE fi +# We'll enforce UR in ko_do_fbdepth, so make sure further FBInk usage (USBMS) +# will also enforce UR... (Only actually meaningful on sunxi). +if [ "${PLATFORM}" = "b300-ntx" ]; then + export FBINK_FORCE_ROTA=0 + # And we also cannot use batched updates for the crash screens, as buffers are private, + # so each invocation essentially draws in a different buffer... + FBINK_BATCH_FLAG="" + # Same idea for backgroundless... + FBINK_BGLESS_FLAG="-B GRAY9" + # It also means we need explicit background padding in the OT codepath... + FBINK_OT_PADDING=",padding=BOTH" + + # Make sure we poke the right input device + KOBO_TS_INPUT="/dev/input/by-path/platform-0-0010-event" +else + FBINK_BATCH_FLAG="-b" + FBINK_BGLESS_FLAG="-O" + FBINK_OT_PADDING="" + KOBO_TS_INPUT="/dev/input/event1" +fi + +# Make sure we only keep two cores online on the Elipsa. +# NOTE: That's a bit optimistic, we might actually need to tone that down to one, +# and just toggle the second one on demand (e.g., PDF). +if [ "${PRODUCT}" = "europa" ]; then + echo "1" >"/sys/devices/system/cpu/cpu1/online" + echo "0" >"/sys/devices/system/cpu/cpu2/online" + echo "0" >"/sys/devices/system/cpu/cpu3/online" +fi + # 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. IFS= read -r ORIG_FB_ROTA <"/sys/class/graphics/fb0/rotate" @@ -269,6 +299,15 @@ 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() { + # On sunxi, the fb state is meaningless, and the minimal disp fb doesn't actually support 8bpp anyway, + # so just make sure we're set @ UR. + if [ "${PLATFORM}" = "b300-ntx" ]; then + echo "Making sure that rotation is set to Portrait" >>crash.log 2>&1 + ./fbdepth -d 32 -R UR >>crash.log 2>&1 + + return + fi + # 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) @@ -280,14 +319,14 @@ ko_do_fbdepth() { ./fbdepth -d "${ORIG_FB_BPP}" -r "${ORIG_FB_ROTA}" >>crash.log 2>&1 else echo "Making sure we're using the original fb bitdepth @ ${ORIG_FB_BPP}bpp, and that rotation is set to Portrait" >>crash.log 2>&1 - ./fbdepth -d "${ORIG_FB_BPP}" -r -1 >>crash.log 2>&1 + ./fbdepth -d "${ORIG_FB_BPP}" -R UR >>crash.log 2>&1 fi fi else # Swap to 8bpp if things looke 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 + ./fbdepth -d 8 -R UR >>crash.log 2>&1 fi fi } @@ -363,21 +402,25 @@ while [ ${RETURN_VALUE} -ne 0 ]; do # Height @ ~56.7%, w/ a margin worth 1.5 lines bombHeight=$((viewHeight / 2 + viewHeight / 15)) bombMargin=$((FONTH + FONTH / 2)) + # Start with a big gray screen of death, and our friendly old school crash icon ;) + # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... + # shellcheck disable=SC2039,SC3003 + ./fbink -q ${FBINK_BATCH_FLAG} -c -B GRAY9 -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -W GL16 -- $'\xf0\x9f\x92\xa3' # 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})" + ./fbink -q ${FBINK_BATCH_FLAG} ${FBINK_BGLESS_FLAG} -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" -W GL16 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." + ./fbink -q ${FBINK_BATCH_FLAG} ${FBINK_BGLESS_FLAG} -m -y 2 "Tap the screen to continue." -W GL16 fi - # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... - # shellcheck disable=SC2039,SC3003 - ./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 + # shellcheck disable=SC2086 + ./fbink -q ${FBINK_BATCH_FLAG} ${FBINK_BGLESS_FLAG} -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64))${FBINK_OT_PADDING} -W GL16 -- "${crashLog}" + if [ "${PLATFORM}" != "b300-ntx" ]; then + # 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 + fi # Cue a lemming's faceplant sound effect! { @@ -395,7 +438,7 @@ while [ ${RETURN_VALUE} -ne 0 ]; do # 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,SC3045 - read -r -t 15 "/sys/devices/platform/mxc_dvfs_core.0/enable" - # Leave Nickel in its usual state, don't try to use conservative - echo "userspace" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" - cat "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed" + if grep -q "sdio_wifi_pwr" "/proc/modules"; then + if [ -n "${CPUFREQ_DVFS}" ]; then + echo "0" >"/sys/devices/platform/mxc_dvfs_core.0/enable" + # Leave Nickel in its usual state, don't try to use conservative + echo "userspace" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" + cat "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed" + fi + usleep 250000 + rmmod sdio_wifi_pwr fi - usleep 250000 - rmmod sdio_wifi_pwr fi unset CPUFREQ_DVFS CPUFREQ_CONSERVATIVE