From 1198676effe7d9d3832a6ce84208326f90715947 Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 14 Mar 2024 13:56:37 +0100 Subject: [PATCH] sm8450-common: udfps: Defer extCmd until fod ui is ready This does not work with xiaomi's original display driver, since partial reads from it are broken and it rejects all reads whose size is insufficient to get the whole response. However, the size is not known in prior, so we actually want to read the header first to determine the actual size and continue reading then. This requires a kernel side fix like [1]. To make this work with the stock kernel driver instead, adjust the parseDispEvent method to read with a larger buffer directly and decrease the size of the data according to the header later. [1]: https://github.com/cupid-development/android_kernel_xiaomi_sm8450-modules/commit/b80cb5a0289b3f37217939123087d7d45354bed4 Change-Id: Id8f9ac8ef32462dd00832af12ff60a3610103e2a --- udfps/UdfpsHandler.cpp | 71 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/udfps/UdfpsHandler.cpp b/udfps/UdfpsHandler.cpp index 57e9faf..37fe3cc 100644 --- a/udfps/UdfpsHandler.cpp +++ b/udfps/UdfpsHandler.cpp @@ -60,6 +60,27 @@ static bool readBool(int fd) { return c != '0'; } +static disp_event_resp* parseDispEvent(int fd) { + disp_event header; + ssize_t headerSize = read(fd, &header, sizeof(header)); + if (headerSize < sizeof(header)) { + LOG(ERROR) << "unexpected display event header size: " << headerSize; + return nullptr; + } + + struct disp_event_resp* response = + reinterpret_cast(malloc(header.length)); + response->base = header; + int dataLength = response->base.length - sizeof(response->base); + ssize_t dataSize = read(fd, &response->data, dataLength); + if (dataSize < dataLength) { + LOG(ERROR) << "unexpected display event data size: " << dataSize; + return nullptr; + } + + return response; +} + } // anonymous namespace class XiaomiSm8450UdfpsHander : public UdfpsHandler { @@ -103,6 +124,54 @@ class XiaomiSm8450UdfpsHander : public UdfpsHandler { ioctl(disp_fd_.get(), MI_DISP_IOCTL_SET_LOCAL_HBM, &req); } }).detach(); + + // Thread to listen for fod ui changes + std::thread([this]() { + int fd = open(DISP_FEATURE_PATH, O_RDWR); + if (fd < 0) { + LOG(ERROR) << "failed to open " << DISP_FEATURE_PATH << " , err: " << fd; + return; + } + + // Register for FOD events + disp_event_req req; + req.base.flag = 0; + req.base.disp_id = MI_DISP_PRIMARY; + req.type = MI_DISP_EVENT_FOD; + ioctl(fd, MI_DISP_IOCTL_REGISTER_EVENT, &req); + + struct pollfd dispEventPoll = { + .fd = fd, + .events = POLLIN, + .revents = 0, + }; + + while (true) { + int rc = poll(&dispEventPoll, 1, -1); + if (rc < 0) { + LOG(ERROR) << "failed to poll " << FOD_PRESS_STATUS_PATH << ", err: " << rc; + continue; + } + + struct disp_event_resp* response = parseDispEvent(fd); + if (response == nullptr) { + continue; + } + + if (response->base.type != MI_DISP_EVENT_FOD) { + LOG(ERROR) << "unexpected display event: " << response->base.type; + continue; + } + + int value = response->data[0]; + LOG(DEBUG) << "received data: " << std::bitset<8>(value); + + bool localHbmUiReady = value & LOCAL_HBM_UI_READY; + + mDevice->extCmd(mDevice, COMMAND_NIT, + localHbmUiReady ? PARAM_NIT_FOD : PARAM_NIT_NONE); + } + }).detach(); } void onFingerDown(uint32_t /*x*/, uint32_t /*y*/, float /*minor*/, float /*major*/) { @@ -171,8 +240,6 @@ class XiaomiSm8450UdfpsHander : public UdfpsHandler { } void setFingerDown(bool pressed) { - mDevice->extCmd(mDevice, COMMAND_NIT, pressed ? PARAM_NIT_FOD : PARAM_NIT_NONE); - int buf[MAX_BUF_SIZE] = {MI_DISP_PRIMARY, THP_FOD_DOWNUP_CTL, pressed ? 1 : 0}; ioctl(touch_fd_.get(), TOUCH_IOC_SET_CUR_VALUE, &buf); }