-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathUdfpsHandler.cpp
253 lines (204 loc) · 7.55 KB
/
UdfpsHandler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Copyright (C) 2022 The LineageOS Project
* 2023 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "UdfpsHandler.xiaomi13"
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <fstream>
#include <thread>
#include "mi_disp.h"
#include "UdfpsHandler.h"
#include "xiaomi_touch.h"
#define COMMAND_NIT 10
#define TARGET_BRIGHTNESS_OFF 0
#define TARGET_BRIGHTNESS_1000NIT 1
#define TARGET_BRIGHTNESS_110NIT 6
#define LOW_BRIGHTNESS_THRESHHOLD 100
#define COMMAND_FOD_PRESS_STATUS 1
#define COMMAND_FOD_PRESS_X 2
#define COMMAND_FOD_PRESS_Y 3
#define PARAM_FOD_PRESSED 1
#define PARAM_FOD_RELEASED 0
#define TOUCH_DEV_PATH "/dev/xiaomi-touch"
#define TOUCH_MAGIC 'T'
#define TOUCH_IOC_SET_CUR_VALUE _IO(TOUCH_MAGIC, SET_CUR_VALUE)
#define TOUCH_IOC_GET_CUR_VALUE _IO(TOUCH_MAGIC, GET_CUR_VALUE)
#define DISP_FEATURE_PATH "/dev/mi_display/disp_feature"
#define FOD_PRESS_STATUS_PATH "/sys/class/touch/touch_dev/fod_press_status"
namespace {
static bool readBool(int fd) {
char c;
int rc;
rc = lseek(fd, 0, SEEK_SET);
if (rc) {
LOG(ERROR) << "failed to seek fd, err: " << rc;
return false;
}
rc = read(fd, &c, sizeof(char));
if (rc != 1) {
LOG(ERROR) << "failed to read bool from fd, err: " << rc;
return false;
}
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);
if (dataLength < 0) {
LOG(ERROR) << "invalid data length: " << response->base.length;
return nullptr;
}
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 XiaomiSm8550UdfpsHander : public UdfpsHandler {
public:
void init(fingerprint_device_t* device) {
mDevice = device;
touch_fd_ = android::base::unique_fd(open(TOUCH_DEV_PATH, O_RDWR));
disp_fd_ = android::base::unique_fd(open(DISP_FEATURE_PATH, O_RDWR));
// Thread to notify fingeprint hwmodule about fod presses
std::thread([this]() {
int fd = open(FOD_PRESS_STATUS_PATH, O_RDONLY);
if (fd < 0) {
LOG(ERROR) << "failed to open " << FOD_PRESS_STATUS_PATH << " , err: " << fd;
return;
}
struct pollfd fodPressStatusPoll = {
.fd = fd,
.events = POLLERR | POLLPRI,
.revents = 0,
};
while (true) {
int rc = poll(&fodPressStatusPoll, 1, -1);
if (rc < 0) {
LOG(ERROR) << "failed to poll " << FOD_PRESS_STATUS_PATH << ", err: " << rc;
continue;
}
bool pressed = readBool(fd);
mDevice->extCmd(mDevice, COMMAND_FOD_PRESS_X, pressed ? lastPressX : 0);
mDevice->extCmd(mDevice, COMMAND_FOD_PRESS_Y, pressed ? lastPressY : 0);
mDevice->extCmd(mDevice, COMMAND_FOD_PRESS_STATUS,
pressed ? PARAM_FOD_PRESSED : PARAM_FOD_RELEASED);
// Request HBM
disp_local_hbm_req req;
req.base.flag = 0;
req.base.disp_id = MI_DISP_PRIMARY;
req.local_hbm_value = pressed ? LHBM_TARGET_BRIGHTNESS_WHITE_1000NIT
: LHBM_TARGET_BRIGHTNESS_OFF_FINGER_UP;
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 " << DISP_FEATURE_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;
bool requestLowBrightnessCapture = value & FOD_LOW_BRIGHTNESS_CAPTURE;
mDevice->extCmd(mDevice, COMMAND_NIT,
localHbmUiReady
? (requestLowBrightnessCapture ? TARGET_BRIGHTNESS_110NIT
: TARGET_BRIGHTNESS_1000NIT)
: TARGET_BRIGHTNESS_OFF);
}
}).detach();
}
void onFingerDown(uint32_t x, uint32_t y, float /*minor*/, float /*major*/) {
LOG(DEBUG) << __func__ << "x: " << x << ", y: " << y;
// Track x and y coordinates
lastPressX = x;
lastPressY = y;
// Notify touchscreen about press status
setFingerDown(true);
}
void onFingerUp() {
LOG(DEBUG) << __func__;
// Notify touchscreen about press status
setFingerDown(false);
}
void onAcquired(int32_t result, int32_t vendorCode) {
LOG(DEBUG) << __func__ << " result: " << result << " vendorCode: " << vendorCode;
if (result == FINGERPRINT_ACQUIRED_GOOD) {
setFingerDown(false);
}
}
void cancel() {
LOG(DEBUG) << __func__;
}
void preEnroll() {
LOG(DEBUG) << __func__;
}
void enroll() {
LOG(DEBUG) << __func__;
}
void postEnroll() {
LOG(DEBUG) << __func__;
}
private:
fingerprint_device_t* mDevice;
android::base::unique_fd touch_fd_;
android::base::unique_fd disp_fd_;
uint32_t lastPressX, lastPressY;
void setFingerDown(bool pressed) {
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);
}
};
static UdfpsHandler* create() {
return new XiaomiSm8550UdfpsHander();
}
static void destroy(UdfpsHandler* handler) {
delete handler;
}
extern "C" UdfpsHandlerFactory UDFPS_HANDLER_FACTORY = {
.create = create,
.destroy = destroy,
};