From 4d9c6523ad874628d14ae1c3ffb31480ef2c5aa7 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sun, 19 May 2024 22:53:14 +0200 Subject: [PATCH] Input: Some more followups to the input device auto-detection stuff (#11855) Switch to a new `input.fdopen` API & wrapper so we can keep the fds opened by `fbink_input_scan` instead of closing them to re-open them right after that... This should hopefully help on racy zForce devices that attempt to handle power management when opening/closing the device. We know this sometimes horribly fail to re-activate the IR grid (c.f., our manual activation on resume), but this apparently could also happen here (re: #11844) because of the quick succession of open->close->open. --- base | 2 +- frontend/device/input.lua | 23 ++++++++++++++++++++++ frontend/device/kindle/device.lua | 8 ++++---- frontend/device/kobo/device.lua | 6 +++--- plugins/externalkeyboard.koplugin/main.lua | 14 +++++++------ 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/base b/base index f9c931670..61c05b668 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit f9c9316709a9683406a759888090ea04098cf46b +Subproject commit 61c05b668f0764988cc857f3a59024e35fded62b diff --git a/frontend/device/input.lua b/frontend/device/input.lua index c8b7ac43f..be906ac20 100644 --- a/frontend/device/input.lua +++ b/frontend/device/input.lua @@ -323,6 +323,29 @@ function Input.open(path, name) end end +--[[-- +Wrapper for our Lua/C input module's fdopen. + +Note that we adhere to the "." syntax here for compatibility. + +The `name` argument is optional, and used for logging purposes only. +`path` is mandatory, though! +--]] +function Input.fdopen(fd, path, name) + -- Make sure we don't open the same device twice. + if not Input.opened_devices[path] then + input.fdopen(fd) + -- As with input.open, it will throw on error (closing the fd first) + Input.opened_devices[path] = fd + if name then + logger.dbg("Kept fd", fd, "open for input device", name, "@", path) + else + logger.dbg("Kept fd", fd, "open for input device @", path) + end + return fd + end +end + --[[-- Wrapper for our Lua/C input module's close. diff --git a/frontend/device/kindle/device.lua b/frontend/device/kindle/device.lua index b4dde41b3..6fd9933b8 100644 --- a/frontend/device/kindle/device.lua +++ b/frontend/device/kindle/device.lua @@ -216,12 +216,12 @@ function Kindle:openInputDevices() 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, C.SCAN_ONLY, dev_count) + 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.open(ffi.string(dev.path), ffi.string(dev.name)) + self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name)) end end C.free(devices) @@ -243,12 +243,12 @@ function Kindle:openInputDevices() 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), bit.bor(C.SCAN_ONLY, C.NO_RECAP), dev_count) + 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.open(ffi.string(dev.path), ffi.string(dev.name)) + self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name)) end end C.free(devices) diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index b9ce0a4ae..db19477f2 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -867,7 +867,7 @@ function Kobo:init() -- (and technically rotation events, but we'll get it with the device that provides the buttons on NTX). -- We exclude keyboards to play nice with the ExternalKeyboard plugin, which will handle potential keyboards on its own. local match_mask = bit.bor(C.INPUT_TOUCHSCREEN, C.INPUT_TABLET, C.INPUT_POWER_BUTTON, C.INPUT_SLEEP_COVER, C.INPUT_PAGINATION_BUTTONS) - local devices = FBInkInput.fbink_input_scan(match_mask, C.INPUT_KEYBOARD, C.SCAN_ONLY, dev_count) + local devices = FBInkInput.fbink_input_scan(match_mask, C.INPUT_KEYBOARD, 0, dev_count) if devices ~= nil then for i = 0, tonumber(dev_count[0]) - 1 do local dev = devices[i] @@ -875,9 +875,9 @@ function Kobo:init() -- We need to single out whichever device provides pagination buttons or sleep cover events, as we'll want to tweak key repeat there... -- The first one will do, as it's extremely likely to be event0, and that's pretty fairly set in stone on NTX boards. if (bit.band(dev.type, C.INPUT_PAGINATION_BUTTONS) ~= 0 or bit.band(dev.type, C.INPUT_SLEEP_COVER) ~= 0) and not self.ntx_fd then - self.ntx_fd = self.input.open(ffi.string(dev.path), ffi.string(dev.name)) + self.ntx_fd = self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name)) else - self.input.open(ffi.string(dev.path), ffi.string(dev.name)) + self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name)) end end end diff --git a/plugins/externalkeyboard.koplugin/main.lua b/plugins/externalkeyboard.koplugin/main.lua index 7a43f2130..899a3bba5 100644 --- a/plugins/externalkeyboard.koplugin/main.lua +++ b/plugins/externalkeyboard.koplugin/main.lua @@ -294,14 +294,14 @@ local function findKeyboards() local FBInkInput = ffi.load("fbink_input") local dev_count = ffi.new("size_t[1]") - local devices = FBInkInput.fbink_input_scan(C.INPUT_KEYBOARD, 0, C.SCAN_ONLY, dev_count) + local devices = FBInkInput.fbink_input_scan(C.INPUT_KEYBOARD, 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 -- Check if it provides a DPad, too. local has_dpad = bit.band(dev.type, C.INPUT_DPAD) ~= 0 - table.insert(keyboards, { event_path = ffi.string(dev.path), has_dpad = has_dpad }) + table.insert(keyboards, { event_fd = tonumber(dev.fd), event_path = ffi.string(dev.path), name = ffi.string(dev.name), has_dpad = has_dpad }) end end C.free(devices) @@ -314,11 +314,13 @@ local function checkKeyboard(path) local keyboard local FBInkInput = ffi.load("fbink_input") - local dev = FBInkInput.fbink_input_check(path, C.INPUT_KEYBOARD, 0, C.SCAN_ONLY) + local dev = FBInkInput.fbink_input_check(path, C.INPUT_KEYBOARD, 0, 0) if dev ~= nil then if dev.matched then keyboard = { + event_fd = tonumber(dev.fd), event_path = ffi.string(dev.path), + name = ffi.string(dev.name), has_dpad = bit.band(dev.type, C.INPUT_DPAD) ~= 0 } end @@ -359,10 +361,10 @@ function ExternalKeyboard:setupKeyboard(data) local has_dpad_func = Device.hasDPad - logger.dbg("ExternalKeyboard:setupKeyboard", keyboard_info.event_path, "has_dpad", keyboard_info.has_dpad) + logger.dbg("ExternalKeyboard:setupKeyboard", keyboard_info.name, "@", keyboard_info.event_path, "- has_dpad:", keyboard_info.has_dpad) -- Check if we already know about this event file. if ExternalKeyboard.keyboard_fds[keyboard_info.event_path] == nil then - local ok, fd = pcall(Device.input.open, keyboard_info.event_path) + local ok, fd = pcall(Device.input.fdopen, keyboard_info.event_fd, keyboard_info.event_path, keyboard_info.name) if not ok then UIManager:show(InfoMessage:new{ text = "Error opening keyboard:\n" .. tostring(fd), @@ -373,7 +375,7 @@ function ExternalKeyboard:setupKeyboard(data) ExternalKeyboard.keyboard_fds[keyboard_info.event_path] = fd ExternalKeyboard.connected_keyboards = ExternalKeyboard.connected_keyboards + 1 - logger.dbg("ExternalKeyboard: USB keyboard", keyboard_info.event_path, "was connected; total:", ExternalKeyboard.connected_keyboards) + logger.dbg("ExternalKeyboard: USB keyboard", keyboard_info.name, "@", keyboard_info.event_path, "was connected; total:", ExternalKeyboard.connected_keyboards) if keyboard_info.has_dpad then has_dpad_func = yes