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]: b80cb5a028

Change-Id: Id8f9ac8ef32462dd00832af12ff60a3610103e2a
This commit is contained in:
Arian 2024-03-14 13:56:37 +01:00
parent abee51ea08
commit 1198676eff

View file

@ -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<struct disp_event_resp*>(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);
}