Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Goodix Moc driver for libfprint | ||
3 | * Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd. | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | |||
21 | |||
22 | #define FP_COMPONENT "goodixmoc" | ||
23 | |||
24 | #include "drivers_api.h" | ||
25 | |||
26 | #include "goodix_proto.h" | ||
27 | #include "goodix.h" | ||
28 | |||
29 | |||
30 | /* Default enroll stages number */ | ||
31 | #define DEFAULT_ENROLL_SAMPLES 8 | ||
32 | /* Usb port setting */ | ||
33 | #define EP_IN (3 | FPI_USB_ENDPOINT_IN) | ||
34 | #define EP_OUT (1 | FPI_USB_ENDPOINT_OUT) | ||
35 | |||
36 | #define EP_IN_MAX_BUF_SIZE (2048) | ||
37 | |||
38 | #define MAX_USER_ID_LEN (64) | ||
39 | |||
40 | /* Command transfer timeout :ms*/ | ||
41 | #define CMD_TIMEOUT (1000) | ||
42 | #define ACK_TIMEOUT (2000) | ||
43 | #define DATA_TIMEOUT (5000) | ||
44 | |||
45 | |||
46 | struct _FpiDeviceGoodixMoc | ||
47 | { | ||
48 | FpDevice parent; | ||
49 | FpiSsm *task_ssm; | ||
50 | FpiSsm *cmd_ssm; | ||
51 | FpiUsbTransfer *cmd_transfer; | ||
52 | gboolean cmd_cancelable; | ||
53 | pgxfp_sensor_cfg_t sensorcfg; | ||
54 | gint enroll_stage; | ||
55 | gint max_enroll_stage; | ||
56 | gint max_stored_prints; | ||
57 | GPtrArray *list_result; | ||
58 | guint8 template_id[TEMPLATE_ID_SIZE]; | ||
59 | gboolean is_power_button_shield_on; | ||
60 | |||
61 | }; | ||
62 | |||
63 |
3/4✓ Branch 0 taken 121 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
387 | G_DEFINE_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FP_TYPE_DEVICE) |
64 | |||
65 | typedef void (*SynCmdMsgCallback) (FpiDeviceGoodixMoc *self, | ||
66 | gxfp_cmd_response_t *resp, | ||
67 | GError *error); | ||
68 | |||
69 | typedef struct | ||
70 | { | ||
71 | guint8 cmd; | ||
72 | SynCmdMsgCallback callback; | ||
73 | } CommandData; | ||
74 | |||
75 | static gboolean parse_print_data (GVariant *data, | ||
76 | guint8 *finger, | ||
77 | const guint8 **tid, | ||
78 | gsize *tid_len, | ||
79 | const guint8 **user_id, | ||
80 | gsize *user_id_len); | ||
81 | |||
82 | static FpPrint * | ||
83 | 3 | fp_print_from_template (FpiDeviceGoodixMoc *self, template_format_t *template) | |
84 | { | ||
85 | 3 | FpPrint *print; | |
86 | 3 | GVariant *data; | |
87 | 3 | GVariant *tid; | |
88 | 3 | GVariant *uid; | |
89 | 6 | g_autofree gchar *userid = NULL; | |
90 | |||
91 | 3 | userid = g_strndup ((gchar *) template->payload.data, template->payload.size); | |
92 | |||
93 | 3 | print = fp_print_new (FP_DEVICE (self)); | |
94 | |||
95 | 6 | tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
96 | 3 | template->tid, | |
97 | TEMPLATE_ID_SIZE, | ||
98 | 1); | ||
99 | |||
100 | 6 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
101 | template->payload.data, | ||
102 | 3 | template->payload.size, | |
103 | 1); | ||
104 | |||
105 | 6 | data = g_variant_new ("(y@ay@ay)", | |
106 | 3 | template->finger_index, | |
107 | tid, | ||
108 | uid); | ||
109 | |||
110 | 3 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
111 | 3 | fpi_print_set_device_stored (print, TRUE); | |
112 | 3 | g_object_set (print, "fpi-data", data, NULL); | |
113 | 3 | g_object_set (print, "description", userid, NULL); | |
114 | 3 | fpi_print_fill_from_user_id (print, userid); | |
115 | |||
116 | 3 | return print; | |
117 | } | ||
118 | |||
119 | /****************************************************************************** | ||
120 | * | ||
121 | * fp_cmd_xxx Function | ||
122 | * | ||
123 | *****************************************************************************/ | ||
124 | static void | ||
125 | 220 | fp_cmd_receive_cb (FpiUsbTransfer *transfer, | |
126 | FpDevice *device, | ||
127 | gpointer user_data, | ||
128 | GError *error) | ||
129 | { | ||
130 | 220 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
131 | 220 | FpiByteReader reader = {0}; | |
132 | 220 | CommandData *data = user_data; | |
133 | 220 | int ssm_state = 0; | |
134 | 220 | gxfp_cmd_response_t cmd_reponse = {0, }; | |
135 | 220 | pack_header header; | |
136 | 220 | guint32 crc32_calc = 0; | |
137 | 220 | guint32 crc32 = 0; | |
138 | 220 | guint16 cmd = 0; | |
139 | |||
140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (error) |
141 | { | ||
142 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
143 | 165 | return; | |
144 | } | ||
145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (data == NULL) |
146 | { | ||
147 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
148 | fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); | ||
149 | ✗ | return; | |
150 | } | ||
151 | 220 | ssm_state = fpi_ssm_get_cur_state (transfer->ssm); | |
152 | /* skip zero length package */ | ||
153 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 110 times.
|
220 | if (transfer->actual_length == 0) |
154 | { | ||
155 | 110 | fpi_ssm_jump_to_state (transfer->ssm, ssm_state); | |
156 | 110 | return; | |
157 | } | ||
158 | |||
159 | 110 | reader.data = transfer->buffer; | |
160 | 110 | reader.size = transfer->actual_length; | |
161 | |||
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (gx_proto_parse_header (&reader, &header) != 0) |
163 | { | ||
164 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
165 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
166 | "Corrupted message header received")); | ||
167 | ✗ | return; | |
168 | } | ||
169 | |||
170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len)) |
171 | { | ||
172 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
173 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
174 | "Package crc read failed")); | ||
175 | } | ||
176 | |||
177 | 110 | gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc); | |
178 | |||
179 |
1/2✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
|
110 | if (!fpi_byte_reader_get_uint32_le (&reader, &crc32) || |
180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | crc32_calc != crc32) |
181 | { | ||
182 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
183 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
184 | "Package crc check failed")); | ||
185 | ✗ | return; | |
186 | } | ||
187 | |||
188 | 110 | cmd = MAKE_CMD_EX (header.cmd0, header.cmd1); | |
189 | |||
190 | 110 | fpi_byte_reader_set_pos (&reader, 0); | |
191 | 110 | reader.data = &transfer->buffer[PACKAGE_HEADER_SIZE]; | |
192 | 110 | reader.size = header.len; | |
193 | |||
194 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (gx_proto_parse_body (cmd, &reader, &cmd_reponse) != 0) |
195 | { | ||
196 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
197 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
198 | "Corrupted message received")); | ||
199 | ✗ | return; | |
200 | } | ||
201 | /* ack */ | ||
202 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 55 times.
|
110 | if(header.cmd0 == RESPONSE_PACKAGE_CMD) |
203 | { | ||
204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (data->cmd != cmd_reponse.parse_msg.ack_cmd) |
205 | { | ||
206 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
207 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
208 | "Unexpected response, got 0x%x", | ||
209 | cmd_reponse.parse_msg.ack_cmd)); | ||
210 | |||
211 | ✗ | return; | |
212 | } | ||
213 | 55 | fpi_ssm_next_state (transfer->ssm); | |
214 | 55 | return; | |
215 | } | ||
216 | /* data */ | ||
217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (data->cmd != header.cmd0) |
218 | { | ||
219 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
220 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
221 | "Unexpected cmd, got 0x%x", | ||
222 | header.cmd0)); | ||
223 | ✗ | return; | |
224 | } | ||
225 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (data->callback) |
226 | 55 | data->callback (self, &cmd_reponse, NULL); | |
227 | |||
228 | 55 | fpi_ssm_mark_completed (transfer->ssm); | |
229 | } | ||
230 | |||
231 | |||
232 | static void | ||
233 | 275 | fp_cmd_run_state (FpiSsm *ssm, | |
234 | FpDevice *dev) | ||
235 | { | ||
236 | 275 | FpiUsbTransfer *transfer; | |
237 | 275 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
238 | |||
239 |
3/4✓ Branch 0 taken 55 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
|
275 | switch (fpi_ssm_get_cur_state (ssm)) |
240 | { | ||
241 | 55 | case FP_CMD_SEND: | |
242 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (self->cmd_transfer) |
243 | { | ||
244 | 55 | self->cmd_transfer->ssm = ssm; | |
245 | 55 | fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer), | |
246 | CMD_TIMEOUT, | ||
247 | NULL, | ||
248 | fpi_ssm_usb_transfer_cb, | ||
249 | NULL); | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | ✗ | fpi_ssm_next_state (ssm); | |
254 | } | ||
255 | break; | ||
256 | |||
257 | 110 | case FP_CMD_GET_ACK: | |
258 | 110 | transfer = fpi_usb_transfer_new (dev); | |
259 | 110 | transfer->ssm = ssm; | |
260 | 110 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); | |
261 | 110 | fpi_usb_transfer_submit (transfer, | |
262 | ACK_TIMEOUT, | ||
263 | NULL, | ||
264 | fp_cmd_receive_cb, | ||
265 | fpi_ssm_get_data (ssm)); | ||
266 | |||
267 | 110 | break; | |
268 | |||
269 | 110 | case FP_CMD_GET_DATA: | |
270 | 110 | transfer = fpi_usb_transfer_new (dev); | |
271 | 110 | transfer->ssm = ssm; | |
272 | 110 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); | |
273 | 110 | fpi_usb_transfer_submit (transfer, | |
274 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 50 times.
|
110 | self->cmd_cancelable ? 0 : DATA_TIMEOUT, |
275 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 60 times.
|
110 | self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL, |
276 | fp_cmd_receive_cb, | ||
277 | fpi_ssm_get_data (ssm)); | ||
278 | 110 | break; | |
279 | } | ||
280 | |||
281 | 275 | } | |
282 | |||
283 | |||
284 | static void | ||
285 | 55 | fp_cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
286 | { | ||
287 | 55 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
288 | 55 | CommandData *data = fpi_ssm_get_data (ssm); | |
289 | |||
290 | 55 | self->cmd_ssm = NULL; | |
291 | /* Notify about the SSM failure from here instead. */ | ||
292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (error) |
293 | { | ||
294 | ✗ | if (data->callback) | |
295 | ✗ | data->callback (self, NULL, error); | |
296 | else | ||
297 | ✗ | g_error_free (error); | |
298 | } | ||
299 | 55 | } | |
300 | |||
301 | static FpiUsbTransfer * | ||
302 | 55 | alloc_cmd_transfer (FpDevice *dev, | |
303 | guint8 cmd0, | ||
304 | guint8 cmd1, | ||
305 | const guint8 *data, | ||
306 | guint16 data_len) | ||
307 | { | ||
308 | 55 | gint ret = -1; | |
309 | |||
310 | 110 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
311 | |||
312 | 55 | guint32 total_len = data_len + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE; | |
313 | |||
314 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | g_return_val_if_fail (data || data_len == 0, NULL); |
315 | |||
316 | 55 | transfer = fpi_usb_transfer_new (dev); | |
317 | |||
318 | 55 | fpi_usb_transfer_fill_bulk (transfer, EP_OUT, total_len); | |
319 | |||
320 | 55 | ret = gx_proto_build_package (transfer->buffer, &total_len, MAKE_CMD_EX (cmd0, cmd1), data, data_len); | |
321 | |||
322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | g_return_val_if_fail (ret == 0, NULL); |
323 | |||
324 | return g_steal_pointer (&transfer); | ||
325 | } | ||
326 | |||
327 | static void | ||
328 | 55 | fp_cmd_ssm_done_data_free (CommandData *data) | |
329 | { | ||
330 | 55 | g_free (data); | |
331 | 55 | } | |
332 | |||
333 | static void | ||
334 | 55 | goodix_sensor_cmd (FpiDeviceGoodixMoc *self, | |
335 | guint8 cmd0, | ||
336 | guint8 cmd1, | ||
337 | gboolean bwait_data_delay, | ||
338 | const guint8 * payload, | ||
339 | gssize payload_len, | ||
340 | SynCmdMsgCallback callback) | ||
341 | { | ||
342 | |||
343 | 110 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
344 | |||
345 | 55 | CommandData *data = g_new0 (CommandData, 1); | |
346 | |||
347 | 55 | transfer = alloc_cmd_transfer (FP_DEVICE (self), cmd0, cmd1, payload, payload_len); | |
348 | |||
349 | 55 | data->cmd = cmd0; | |
350 | 55 | data->callback = callback; | |
351 | |||
352 | 55 | self->cmd_transfer = g_steal_pointer (&transfer); | |
353 | 55 | self->cmd_cancelable = bwait_data_delay; | |
354 | |||
355 | 55 | self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), | |
356 | fp_cmd_run_state, | ||
357 | FP_CMD_NUM_STATES); | ||
358 | |||
359 | 55 | fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free); | |
360 | |||
361 | 55 | fpi_ssm_start (self->cmd_ssm, fp_cmd_ssm_done); | |
362 | |||
363 | |||
364 | 55 | } | |
365 | |||
366 | /****************************************************************************** | ||
367 | * | ||
368 | * fp_pwr_btn_shield_cb Function | ||
369 | * | ||
370 | *****************************************************************************/ | ||
371 | static void | ||
372 | 6 | fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self, | |
373 | gxfp_cmd_response_t *resp, | ||
374 | GError *error) | ||
375 | { | ||
376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (error) |
377 | { | ||
378 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
379 | ✗ | return; | |
380 | } | ||
381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (resp->result >= GX_FAILED) |
382 | { | ||
383 | ✗ | fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); | |
384 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
385 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
386 | ✗ | return; | |
387 | } | ||
388 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (resp->power_button_shield_resp.resp_cmd1 == MOC_CMD1_PWR_BTN_SHIELD_ON) |
389 | 3 | self->is_power_button_shield_on = true; | |
390 | else | ||
391 | 3 | self->is_power_button_shield_on = false; | |
392 | 6 | fpi_ssm_next_state (self->task_ssm); | |
393 | } | ||
394 | /****************************************************************************** | ||
395 | * | ||
396 | * fp_verify_xxxx Function | ||
397 | * | ||
398 | *****************************************************************************/ | ||
399 | static void | ||
400 | 2 | fp_verify_capture_cb (FpiDeviceGoodixMoc *self, | |
401 | gxfp_cmd_response_t *resp, | ||
402 | GError *error) | ||
403 | { | ||
404 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
405 | { | ||
406 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
407 | ✗ | return; | |
408 | } | ||
409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (resp->result >= GX_FAILED) |
410 | { | ||
411 | ✗ | fp_dbg ("Capture sample failed, result: 0x%x", resp->result); | |
412 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
413 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
414 | ✗ | return; | |
415 | } | ||
416 | 2 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
417 | FP_FINGER_STATUS_PRESENT, | ||
418 | FP_FINGER_STATUS_NONE); | ||
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (resp->capture_data_resp.img_quality == 0) |
420 | { | ||
421 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
422 | fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); | ||
423 | ✗ | return; | |
424 | } | ||
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (resp->capture_data_resp.img_coverage < 35) |
426 | { | ||
427 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
428 | fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); | ||
429 | ✗ | return; | |
430 | } | ||
431 | 2 | fpi_ssm_next_state (self->task_ssm); | |
432 | } | ||
433 | |||
434 | static void | ||
435 | 2 | fp_verify_cb (FpiDeviceGoodixMoc *self, | |
436 | gxfp_cmd_response_t *resp, | ||
437 | GError *error) | ||
438 | { | ||
439 | 2 | FpDevice *device = FP_DEVICE (self); | |
440 | 2 | FpPrint *new_scan = NULL; | |
441 | 2 | FpPrint *matching = NULL; | |
442 | |||
443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
444 | { | ||
445 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
446 | ✗ | return; | |
447 | } | ||
448 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (resp->verify.match) |
449 | { | ||
450 | 2 | new_scan = fp_print_from_template (self, &resp->verify.template); | |
451 | |||
452 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) |
453 | { | ||
454 | 1 | fpi_device_get_verify_data (device, &matching); | |
455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!fp_print_equal (matching, new_scan)) |
456 | ✗ | matching = NULL; | |
457 | } | ||
458 | else | ||
459 | { | ||
460 | 1 | GPtrArray *templates = NULL; | |
461 | 1 | fpi_device_get_identify_data (device, &templates); | |
462 | |||
463 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (gint i = 0; i < templates->len; i++) |
464 | { | ||
465 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (fp_print_equal (g_ptr_array_index (templates, i), new_scan)) |
466 | { | ||
467 | 1 | matching = g_ptr_array_index (templates, i); | |
468 | 1 | break; | |
469 | } | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | |||
474 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) |
475 | 1 | fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error); | |
476 | else | ||
477 | 1 | fpi_device_identify_report (device, matching, new_scan, error); | |
478 | |||
479 | 2 | fpi_ssm_next_state (self->task_ssm); | |
480 | |||
481 | } | ||
482 | |||
483 | static void | ||
484 | 8 | fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
485 | { | ||
486 | 8 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
487 | 8 | guint8 param[3] = { 0 }; | |
488 | 8 | guint8 nonce[TEMPLATE_ID_SIZE] = { 0 }; | |
489 | |||
490 | 8 | param[0] = 0x01; | |
491 | 8 | param[1] = self->sensorcfg->config[10]; | |
492 | 8 | param[2] = self->sensorcfg->config[11]; | |
493 | |||
494 |
4/5✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
8 | switch (fpi_ssm_get_cur_state (ssm)) |
495 | { | ||
496 | 2 | case FP_VERIFY_PWR_BTN_SHIELD_ON: | |
497 | 2 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, | |
498 | false, | ||
499 | NULL, | ||
500 | 0, | ||
501 | fp_pwr_btn_shield_cb); | ||
502 | 2 | break; | |
503 | |||
504 | 2 | case FP_VERIFY_CAPTURE: | |
505 | 2 | fpi_device_report_finger_status_changes (device, | |
506 | FP_FINGER_STATUS_NEEDED, | ||
507 | FP_FINGER_STATUS_NONE); | ||
508 | 2 | goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT, | |
509 | true, | ||
510 | (const guint8 *) ¶m, | ||
511 | G_N_ELEMENTS (param), | ||
512 | fp_verify_capture_cb); | ||
513 | 2 | break; | |
514 | |||
515 | 2 | case FP_VERIFY_IDENTIFY: | |
516 | 2 | goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT, | |
517 | false, | ||
518 | (const guint8 *) nonce, | ||
519 | TEMPLATE_ID_SIZE, | ||
520 | fp_verify_cb); | ||
521 | 2 | break; | |
522 | |||
523 | 2 | case FP_VERIFY_PWR_BTN_SHIELD_OFF: | |
524 | 2 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, | |
525 | false, | ||
526 | NULL, | ||
527 | 0, | ||
528 | fp_pwr_btn_shield_cb); | ||
529 | 2 | break; | |
530 | } | ||
531 | |||
532 | 8 | } | |
533 | |||
534 | static void | ||
535 | 2 | fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
536 | { | ||
537 | 2 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
538 | |||
539 | 2 | fp_info ("Verify complete!"); | |
540 | |||
541 |
1/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (error && error->domain == FP_DEVICE_RETRY) |
542 | { | ||
543 | ✗ | if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) | |
544 | ✗ | fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error)); | |
545 | else | ||
546 | ✗ | fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error)); | |
547 | } | ||
548 | |||
549 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) |
550 | 1 | fpi_device_verify_complete (dev, error); | |
551 | |||
552 | else | ||
553 | 1 | fpi_device_identify_complete (dev, error); | |
554 | |||
555 | 2 | self->task_ssm = NULL; | |
556 | 2 | } | |
557 | |||
558 | |||
559 | /****************************************************************************** | ||
560 | * | ||
561 | * fp__xxxx Function | ||
562 | * | ||
563 | *****************************************************************************/ | ||
564 | static gboolean | ||
565 | 2 | encode_finger_id ( | |
566 | const guint8 * tid, | ||
567 | guint16 tid_len, | ||
568 | const guint8 * uid, | ||
569 | guint16 uid_len, | ||
570 | guint8 ** fid, | ||
571 | guint16 * fid_len | ||
572 | ) | ||
573 | { | ||
574 | 2 | guint8 * buffer = NULL; | |
575 | 2 | guint16 offset = 0; | |
576 | |||
577 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_return_val_if_fail (tid != NULL, FALSE); |
578 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (uid != NULL, FALSE); |
579 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (fid != NULL, FALSE); |
580 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (fid_len != NULL, FALSE); |
581 | |||
582 | 2 | *fid_len = (guint16) (70 + uid_len); // must include fingerid length | |
583 | |||
584 | 2 | *fid = (guint8 *) g_malloc0 (*fid_len + 2); | |
585 | |||
586 | 2 | buffer = *fid; | |
587 | 2 | offset = 0; | |
588 | 2 | buffer[offset++] = LOBYTE (*fid_len); | |
589 | 2 | buffer[offset++] = HIBYTE (*fid_len); | |
590 | |||
591 | 2 | buffer[offset++] = 67; | |
592 | 2 | buffer[offset++] = 1; | |
593 | 2 | buffer[offset++] = 1; // finger index | |
594 | 2 | buffer[offset++] = 0; // | |
595 | |||
596 | 2 | offset += 32; | |
597 | |||
598 | 2 | memcpy (&buffer[offset], tid, MIN (tid_len, TEMPLATE_ID_SIZE)); | |
599 | 2 | offset += 32; // offset == 68 | |
600 | |||
601 | 2 | buffer[offset++] = uid_len; | |
602 | 2 | memcpy (&buffer[offset], uid, uid_len); | |
603 | 2 | offset += (guint8) uid_len; | |
604 | |||
605 | 2 | buffer[offset++] = 0; | |
606 | |||
607 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (offset != (*fid_len + 2)) |
608 | { | ||
609 | ✗ | memset (buffer, 0, *fid_len); | |
610 | ✗ | *fid_len = 0; | |
611 | |||
612 | ✗ | fp_err ("offset != fid_len, %d != %d", offset, *fid_len); | |
613 | ✗ | return FALSE; | |
614 | } | ||
615 | 2 | *fid_len += 2; | |
616 | |||
617 | 2 | return TRUE; | |
618 | } | ||
619 | /****************************************************************************** | ||
620 | * | ||
621 | * fp_enroll_xxxx Function | ||
622 | * | ||
623 | *****************************************************************************/ | ||
624 | |||
625 | static void | ||
626 | 1 | fp_enroll_enum_cb (FpiDeviceGoodixMoc *self, | |
627 | gxfp_cmd_response_t *resp, | ||
628 | GError *error) | ||
629 | { | ||
630 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
631 | { | ||
632 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
633 | ✗ | return; | |
634 | } | ||
635 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result != GX_SUCCESS) |
636 | { | ||
637 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
638 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
639 | "Failed to enumerate fingers, result: 0x%x", | ||
640 | resp->result)); | ||
641 | ✗ | return; | |
642 | } | ||
643 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->finger_list_resp.finger_num >= self->max_stored_prints) |
644 | { | ||
645 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
646 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); | ||
647 | ✗ | return; | |
648 | } | ||
649 | |||
650 | 1 | fpi_ssm_next_state (self->task_ssm); | |
651 | } | ||
652 | |||
653 | static void | ||
654 | 1 | fp_enroll_create_cb (FpiDeviceGoodixMoc *self, | |
655 | gxfp_cmd_response_t *resp, | ||
656 | GError *error) | ||
657 | { | ||
658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
659 | { | ||
660 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
661 | ✗ | return; | |
662 | } | ||
663 | 1 | memcpy (self->template_id, resp->enroll_create.tid, TEMPLATE_ID_SIZE); | |
664 | 1 | fpi_ssm_next_state (self->task_ssm); | |
665 | } | ||
666 | |||
667 | static void | ||
668 | 12 | fp_enroll_capture_cb (FpiDeviceGoodixMoc *self, | |
669 | gxfp_cmd_response_t *resp, | ||
670 | GError *error) | ||
671 | { | ||
672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
673 | { | ||
674 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
675 | ✗ | return; | |
676 | } | ||
677 | /* */ | ||
678 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (resp->result >= GX_FAILED) |
679 | { | ||
680 | ✗ | fp_info ("Capture sample failed, result: 0x%x", resp->result); | |
681 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
682 | self->enroll_stage, | ||
683 | NULL, | ||
684 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
685 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
686 | ✗ | return; | |
687 | } | ||
688 | 12 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
689 | FP_FINGER_STATUS_PRESENT, | ||
690 | FP_FINGER_STATUS_NONE); | ||
691 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if ((resp->capture_data_resp.img_quality < self->sensorcfg->config[4]) || |
692 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | (resp->capture_data_resp.img_coverage < self->sensorcfg->config[5])) |
693 | { | ||
694 | ✗ | fp_info ("Capture sample poor quality(%d): %d or coverage(%d): %d", | |
695 | self->sensorcfg->config[4], | ||
696 | resp->capture_data_resp.img_quality, | ||
697 | self->sensorcfg->config[5], | ||
698 | resp->capture_data_resp.img_coverage); | ||
699 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
700 | self->enroll_stage, | ||
701 | NULL, | ||
702 | fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); | ||
703 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
704 | ✗ | return; | |
705 | } | ||
706 | else | ||
707 | { | ||
708 | 12 | fpi_ssm_next_state (self->task_ssm); | |
709 | } | ||
710 | |||
711 | } | ||
712 | static void | ||
713 | 12 | fp_enroll_update_cb (FpiDeviceGoodixMoc *self, | |
714 | gxfp_cmd_response_t *resp, | ||
715 | GError *error) | ||
716 | { | ||
717 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
718 | { | ||
719 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
720 | ✗ | return; | |
721 | } | ||
722 | |||
723 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (resp->enroll_update.img_preoverlay > self->sensorcfg->config[3]) |
724 | { | ||
725 | ✗ | fp_dbg ("Sample overlapping ratio is too High(%d): %d ", | |
726 | self->sensorcfg->config[3], | ||
727 | resp->enroll_update.img_preoverlay); | ||
728 | /* here should tips move finger and try again */ | ||
729 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
730 | self->enroll_stage, | ||
731 | NULL, | ||
732 | fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); | ||
733 | } | ||
734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | else if (resp->enroll_update.rollback) |
735 | { | ||
736 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
737 | self->enroll_stage, | ||
738 | NULL, | ||
739 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
740 | } | ||
741 | else | ||
742 | { | ||
743 | 12 | self->enroll_stage++; | |
744 | 12 | fpi_device_enroll_progress (FP_DEVICE (self), self->enroll_stage, NULL, NULL); | |
745 | } | ||
746 | /* if enroll complete, no need to wait finger up */ | ||
747 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
|
12 | if (self->enroll_stage >= self->max_enroll_stage) |
748 | { | ||
749 | 1 | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CHECK_DUPLICATE); | |
750 | 1 | return; | |
751 | } | ||
752 | |||
753 | 11 | fpi_ssm_next_state (self->task_ssm); | |
754 | } | ||
755 | |||
756 | static void | ||
757 | 1 | fp_enroll_check_duplicate_cb (FpiDeviceGoodixMoc *self, | |
758 | gxfp_cmd_response_t *resp, | ||
759 | GError *error) | ||
760 | { | ||
761 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
762 | { | ||
763 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
764 | ✗ | return; | |
765 | } | ||
766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->check_duplicate_resp.duplicate) |
767 | { | ||
768 | 1 | g_autoptr(FpPrint) print = NULL; | |
769 | |||
770 | ✗ | print = g_object_ref_sink (fp_print_from_template (self, &resp->check_duplicate_resp.template)); | |
771 | |||
772 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
773 | fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE, | ||
774 | "Finger was already enrolled as '%s'", | ||
775 | fp_print_get_description (print))); | ||
776 | ✗ | return; | |
777 | } | ||
778 | |||
779 | 1 | fpi_ssm_next_state (self->task_ssm); | |
780 | } | ||
781 | |||
782 | static void | ||
783 | 1 | fp_enroll_commit_cb (FpiDeviceGoodixMoc *self, | |
784 | gxfp_cmd_response_t *resp, | ||
785 | GError *error) | ||
786 | { | ||
787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
788 | { | ||
789 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
790 | ✗ | return; | |
791 | } | ||
792 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result >= GX_FAILED) |
793 | { | ||
794 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
795 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
796 | "Commit template failed with errcode: 0x%x", resp->result)); | ||
797 | ✗ | return; | |
798 | } | ||
799 | 1 | fpi_ssm_next_state (self->task_ssm); | |
800 | } | ||
801 | |||
802 | static void | ||
803 | 11 | fp_finger_mode_cb (FpiDeviceGoodixMoc *self, | |
804 | gxfp_cmd_response_t *resp, | ||
805 | GError *error) | ||
806 | { | ||
807 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (error) |
808 | { | ||
809 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
810 | ✗ | return; | |
811 | } | ||
812 | /* if reach max timeout(5sec) finger not up, switch to finger up again */ | ||
813 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT) |
814 | { | ||
815 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_WAIT_FINGER_UP); | |
816 | ✗ | return; | |
817 | } | ||
818 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | else if (resp->finger_status.status != GX_SUCCESS) |
819 | { | ||
820 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
821 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
822 | "Switch finger mode failed")); | ||
823 | ✗ | return; | |
824 | } | ||
825 | 11 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
826 | FP_FINGER_STATUS_NONE, | ||
827 | FP_FINGER_STATUS_PRESENT); | ||
828 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (self->enroll_stage < self->max_enroll_stage) |
829 | { | ||
830 | 11 | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
831 | 11 | return; | |
832 | } | ||
833 | ✗ | fpi_ssm_next_state (self->task_ssm); | |
834 | } | ||
835 | |||
836 | static void | ||
837 | 41 | fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
838 | { | ||
839 | 41 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
840 | 41 | FpPrint *print = NULL; | |
841 | 41 | GVariant *data = NULL; | |
842 | 41 | GVariant *uid = NULL; | |
843 | 41 | GVariant *tid = NULL; | |
844 | 41 | guint finger; | |
845 | 41 | guint16 user_id_len; | |
846 | 41 | guint16 payload_len = 0; | |
847 | 41 | g_autofree gchar *user_id = NULL; | |
848 | 41 | g_autofree guint8 *payload = NULL; | |
849 | 41 | guint8 dummy[3] = { 0 }; | |
850 | |||
851 | 41 | dummy[1] = self->sensorcfg->config[4]; | |
852 | 41 | dummy[2] = self->sensorcfg->config[5]; | |
853 | |||
854 |
9/10✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
|
41 | switch (fpi_ssm_get_cur_state (ssm)) |
855 | { | ||
856 | 1 | case FP_ENROLL_PWR_BTN_SHIELD_ON: | |
857 | { | ||
858 | 1 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, | |
859 | false, | ||
860 | NULL, | ||
861 | 0, | ||
862 | fp_pwr_btn_shield_cb); | ||
863 | } | ||
864 | 1 | break; | |
865 | |||
866 | 1 | case FP_ENROLL_ENUM: | |
867 | { | ||
868 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
869 | false, | ||
870 | (const guint8 *) &dummy, | ||
871 | 1, | ||
872 | fp_enroll_enum_cb); | ||
873 | } | ||
874 | 1 | break; | |
875 | |||
876 | 1 | case FP_ENROLL_CREATE: | |
877 | { | ||
878 | 1 | goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT, | |
879 | false, | ||
880 | (const guint8 *) &dummy, | ||
881 | 1, | ||
882 | fp_enroll_create_cb); | ||
883 | } | ||
884 | 1 | break; | |
885 | |||
886 | 12 | case FP_ENROLL_CAPTURE: | |
887 | 12 | fpi_device_report_finger_status_changes (device, | |
888 | FP_FINGER_STATUS_NEEDED, | ||
889 | FP_FINGER_STATUS_NONE); | ||
890 | 12 | goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT, | |
891 | true, | ||
892 | (const guint8 *) &dummy, | ||
893 | 3, | ||
894 | fp_enroll_capture_cb); | ||
895 | 12 | break; | |
896 | |||
897 | 12 | case FP_ENROLL_UPDATE: | |
898 | 12 | dummy[0] = 1; | |
899 | 12 | dummy[1] = self->sensorcfg->config[2]; | |
900 | 12 | dummy[2] = self->sensorcfg->config[3]; | |
901 | 12 | goodix_sensor_cmd (self, MOC_CMD0_ENROLL, MOC_CMD1_DEFAULT, | |
902 | false, | ||
903 | (const guint8 *) &dummy, | ||
904 | 3, | ||
905 | fp_enroll_update_cb); | ||
906 | 12 | break; | |
907 | |||
908 | 11 | case FP_ENROLL_WAIT_FINGER_UP: | |
909 | 11 | dummy[0] = 0; | |
910 | 11 | goodix_sensor_cmd (self, MOC_CMD0_FINGER_MODE, MOC_CMD1_SET_FINGER_UP, | |
911 | true, | ||
912 | (const guint8 *) &dummy, | ||
913 | 1, | ||
914 | fp_finger_mode_cb); | ||
915 | 11 | break; | |
916 | |||
917 | 1 | case FP_ENROLL_CHECK_DUPLICATE: | |
918 | 1 | goodix_sensor_cmd (self, MOC_CMD0_CHECK4DUPLICATE, MOC_CMD1_DEFAULT, | |
919 | false, | ||
920 | (const guint8 *) &dummy, | ||
921 | 3, | ||
922 | fp_enroll_check_duplicate_cb); | ||
923 | 1 | break; | |
924 | |||
925 | 1 | case FP_ENROLL_COMMIT: | |
926 | { | ||
927 | 1 | fpi_device_get_enroll_data (device, &print); | |
928 | 1 | user_id = fpi_print_generate_user_id (print); | |
929 | 1 | user_id_len = strlen (user_id); | |
930 | 1 | user_id_len = MIN (100, user_id_len); | |
931 | 1 | finger = 1; | |
932 | |||
933 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) |
934 | 1 | memset (self->template_id, 0, TEMPLATE_ID_SIZE); | |
935 | 1 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
936 | user_id, | ||
937 | user_id_len, | ||
938 | 1); | ||
939 | |||
940 | 2 | tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
941 | 1 | self->template_id, | |
942 | TEMPLATE_ID_SIZE, | ||
943 | 1); | ||
944 | |||
945 | 1 | data = g_variant_new ("(y@ay@ay)", | |
946 | finger, | ||
947 | tid, | ||
948 | uid); | ||
949 | |||
950 | 1 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
951 | 1 | fpi_print_set_device_stored (print, TRUE); | |
952 | 1 | g_object_set (print, "fpi-data", data, NULL); | |
953 | 1 | g_object_set (print, "description", user_id, NULL); | |
954 | |||
955 | 1 | g_debug ("user_id: %s, user_id_len: %d, finger: %d", user_id, user_id_len, finger); | |
956 | |||
957 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(!encode_finger_id (self->template_id, |
958 | TEMPLATE_ID_SIZE, | ||
959 | (guint8 *) user_id, | ||
960 | user_id_len, | ||
961 | &payload, | ||
962 | &payload_len)) | ||
963 | { | ||
964 | ✗ | fpi_ssm_mark_failed (ssm, | |
965 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
966 | "encode_finger_id failed")); | ||
967 | ✗ | return; | |
968 | } | ||
969 | 1 | goodix_sensor_cmd (self, MOC_CMD0_COMMITENROLLMENT, MOC_CMD1_DEFAULT, | |
970 | false, | ||
971 | (const guint8 *) payload, | ||
972 | payload_len, | ||
973 | fp_enroll_commit_cb); | ||
974 | |||
975 | } | ||
976 | 1 | break; | |
977 | |||
978 | 1 | case FP_ENROLL_PWR_BTN_SHIELD_OFF: | |
979 | { | ||
980 | 1 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, | |
981 | false, | ||
982 | NULL, | ||
983 | 0, | ||
984 | fp_pwr_btn_shield_cb); | ||
985 | } | ||
986 | 1 | break; | |
987 | } | ||
988 | } | ||
989 | |||
990 | static void | ||
991 | 1 | fp_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
992 | { | ||
993 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
994 | 1 | FpPrint *print = NULL; | |
995 | |||
996 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
997 | { | ||
998 | ✗ | fpi_device_enroll_complete (dev, NULL, error); | |
999 | ✗ | return; | |
1000 | } | ||
1001 | 1 | fp_info ("Enrollment complete!"); | |
1002 | |||
1003 | 1 | fpi_device_get_enroll_data (FP_DEVICE (self), &print); | |
1004 | |||
1005 | 1 | fpi_device_enroll_complete (FP_DEVICE (self), g_object_ref (print), NULL); | |
1006 | |||
1007 | 1 | self->task_ssm = NULL; | |
1008 | } | ||
1009 | /****************************************************************************** | ||
1010 | * | ||
1011 | * fp_init_xxxx Function | ||
1012 | * | ||
1013 | *****************************************************************************/ | ||
1014 | static void | ||
1015 | 1 | fp_init_version_cb (FpiDeviceGoodixMoc *self, | |
1016 | gxfp_cmd_response_t *resp, | ||
1017 | GError *error) | ||
1018 | { | ||
1019 | 1 | g_autofree gchar *fw_type = NULL; | |
1020 | 1 | g_autofree gchar *fw_version = NULL; | |
1021 | |||
1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1023 | { | ||
1024 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1025 | ✗ | return; | |
1026 | } | ||
1027 | |||
1028 | 1 | G_STATIC_ASSERT (sizeof (resp->version_info.fwtype) == 8); | |
1029 | 1 | G_STATIC_ASSERT (sizeof (resp->version_info.fwversion) == 8); | |
1030 | |||
1031 | 1 | fw_type = g_strndup ((const char *) resp->version_info.fwtype, sizeof (resp->version_info.fwtype)); | |
1032 | |||
1033 | 1 | fp_info ("Firmware type: %s", fw_type); | |
1034 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (g_strcmp0 (fw_type, "APP") != 0) |
1035 | { | ||
1036 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
1037 | fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, | ||
1038 | "Please update firmware using fwupd")); | ||
1039 | ✗ | return; | |
1040 | } | ||
1041 | 1 | fw_version = g_strndup ((const char *) resp->version_info.fwversion, sizeof (resp->version_info.fwversion)); | |
1042 | 1 | fp_info ("Firmware version: %s", fw_version); | |
1043 | 1 | fpi_ssm_next_state (self->task_ssm); | |
1044 | } | ||
1045 | |||
1046 | static void | ||
1047 | 1 | fp_init_config_cb (FpiDeviceGoodixMoc *self, | |
1048 | gxfp_cmd_response_t *resp, | ||
1049 | GError *error) | ||
1050 | { | ||
1051 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1052 | { | ||
1053 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1054 | ✗ | return; | |
1055 | } | ||
1056 | 1 | self->max_stored_prints = resp->finger_config.max_stored_prints; | |
1057 | 1 | fpi_ssm_next_state (self->task_ssm); | |
1058 | } | ||
1059 | |||
1060 | static void | ||
1061 | 1 | fp_init_cb_reset_or_complete (FpiDeviceGoodixMoc *self, | |
1062 | gxfp_cmd_response_t *resp, | ||
1063 | GError *error) | ||
1064 | { | ||
1065 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1066 | { | ||
1067 | ✗ | fp_warn ("Template storage appears to have been corrupted! Error was: %s", error->message); | |
1068 | ✗ | fp_warn ("A known reason for this to happen is a firmware bug triggered by another storage area being initialized."); | |
1069 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_INIT_RESET_DEVICE); | |
1070 | } | ||
1071 | else | ||
1072 | { | ||
1073 | 1 | fpi_ssm_mark_completed (self->task_ssm); | |
1074 | } | ||
1075 | 1 | } | |
1076 | |||
1077 | static void | ||
1078 | ✗ | fp_init_reset_device_cb (FpiDeviceGoodixMoc *self, | |
1079 | gxfp_cmd_response_t *resp, | ||
1080 | GError *error) | ||
1081 | { | ||
1082 | ✗ | if (error) | |
1083 | { | ||
1084 | ✗ | fp_warn ("Reset failed: %s", error->message); | |
1085 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1086 | ✗ | return; | |
1087 | } | ||
1088 | ✗ | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) | |
1089 | { | ||
1090 | ✗ | fp_warn ("Reset failed, device reported: 0x%x", resp->result); | |
1091 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
1092 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1093 | "Failed clear storage, result: 0x%x", | ||
1094 | ✗ | resp->result)); | |
1095 | ✗ | return; | |
1096 | } | ||
1097 | |||
1098 | ✗ | fp_warn ("Reset completed"); | |
1099 | ✗ | fpi_ssm_mark_completed (self->task_ssm); | |
1100 | } | ||
1101 | |||
1102 | static void | ||
1103 | 3 | fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
1104 | { | ||
1105 | 3 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1106 | 3 | guint8 dummy = 0; | |
1107 | |||
1108 |
3/5✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
3 | switch (fpi_ssm_get_cur_state (ssm)) |
1109 | { | ||
1110 | 1 | case FP_INIT_VERSION: | |
1111 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GET_VERSION, MOC_CMD1_DEFAULT, | |
1112 | false, | ||
1113 | &dummy, | ||
1114 | 1, | ||
1115 | fp_init_version_cb); | ||
1116 | 1 | break; | |
1117 | |||
1118 | 1 | case FP_INIT_CONFIG: | |
1119 | 1 | goodix_sensor_cmd (self, MOC_CMD0_UPDATE_CONFIG, MOC_CMD1_WRITE_CFG_TO_FLASH, | |
1120 | false, | ||
1121 | 1 | (guint8 *) self->sensorcfg, | |
1122 | sizeof (gxfp_sensor_cfg_t), | ||
1123 | fp_init_config_cb); | ||
1124 | 1 | break; | |
1125 | |||
1126 | 1 | case FP_INIT_TEMPLATE_LIST: | |
1127 | /* List prints to check whether the template DB was corrupted. | ||
1128 | * As of 2022-06-13 there is a known firmware issue that can cause the | ||
1129 | * stored templates for Linux to be corrupted when the Windows storage | ||
1130 | * area is initialized. | ||
1131 | * In that case, we'll get a protocol failure trying to retrieve the | ||
1132 | * list of prints. | ||
1133 | */ | ||
1134 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
1135 | FALSE, | ||
1136 | (const guint8 *) &dummy, | ||
1137 | 1, | ||
1138 | fp_init_cb_reset_or_complete); | ||
1139 | 1 | break; | |
1140 | |||
1141 | ✗ | case FP_INIT_RESET_DEVICE: | |
1142 | ✗ | fp_warn ("Resetting device storage, you will need to enroll all prints again!"); | |
1143 | ✗ | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL, | |
1144 | FALSE, | ||
1145 | NULL, | ||
1146 | 0, | ||
1147 | fp_init_reset_device_cb); | ||
1148 | ✗ | break; | |
1149 | } | ||
1150 | |||
1151 | |||
1152 | 3 | } | |
1153 | |||
1154 | static void | ||
1155 | 1 | fp_init_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
1156 | { | ||
1157 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
1158 | |||
1159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1160 | { | ||
1161 | ✗ | fpi_device_open_complete (dev, error); | |
1162 | ✗ | return; | |
1163 | } | ||
1164 | 1 | self->task_ssm = NULL; | |
1165 | 1 | fpi_device_open_complete (dev, NULL); | |
1166 | } | ||
1167 | /****************************************************************************** | ||
1168 | * | ||
1169 | * fp_template_delete Function | ||
1170 | * | ||
1171 | *****************************************************************************/ | ||
1172 | static gboolean | ||
1173 | 1 | parse_print_data (GVariant *data, | |
1174 | guint8 *finger, | ||
1175 | const guint8 **tid, | ||
1176 | gsize *tid_len, | ||
1177 | const guint8 **user_id, | ||
1178 | gsize *user_id_len) | ||
1179 | { | ||
1180 | 2 | g_autoptr(GVariant) user_id_var = NULL; | |
1181 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_autoptr(GVariant) tid_var = NULL; |
1182 | |||
1183 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_return_val_if_fail (data != NULL, FALSE); |
1184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (finger != NULL, FALSE); |
1185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (tid != NULL, FALSE); |
1186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (tid_len != NULL, FALSE); |
1187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (user_id != NULL, FALSE); |
1188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (user_id_len != NULL, FALSE); |
1189 | |||
1190 | 1 | *tid = NULL; | |
1191 | 1 | *tid_len = 0; | |
1192 | 1 | *user_id = NULL; | |
1193 | 1 | *user_id_len = 0; | |
1194 | |||
1195 | |||
1196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_variant_check_format_string (data, "(y@ay@ay)", FALSE)) |
1197 | return FALSE; | ||
1198 | |||
1199 | 1 | g_variant_get (data, | |
1200 | "(y@ay@ay)", | ||
1201 | finger, | ||
1202 | &tid_var, | ||
1203 | &user_id_var); | ||
1204 | |||
1205 | 1 | *tid = g_variant_get_fixed_array (tid_var, tid_len, 1); | |
1206 | 1 | *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); | |
1207 | |||
1208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*user_id_len == 0 || *user_id_len > 100) |
1209 | return FALSE; | ||
1210 | |||
1211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*user_id_len <= 0 || *user_id[0] == ' ') |
1212 | return FALSE; | ||
1213 | |||
1214 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(*tid_len != TEMPLATE_ID_SIZE) |
1215 | return FALSE; | ||
1216 | |||
1217 | return TRUE; | ||
1218 | } | ||
1219 | |||
1220 | static void | ||
1221 | 1 | fp_template_delete_cb (FpiDeviceGoodixMoc *self, | |
1222 | gxfp_cmd_response_t *resp, | ||
1223 | GError *error) | ||
1224 | { | ||
1225 | 1 | FpDevice *device = FP_DEVICE (self); | |
1226 | |||
1227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1228 | { | ||
1229 | ✗ | fpi_device_delete_complete (device, error); | |
1230 | ✗ | return; | |
1231 | } | ||
1232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) |
1233 | { | ||
1234 | ✗ | fpi_device_delete_complete (FP_DEVICE (self), | |
1235 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1236 | "Failed delete enrolled users, result: 0x%x", | ||
1237 | resp->result)); | ||
1238 | ✗ | return; | |
1239 | } | ||
1240 | |||
1241 | 1 | fp_info ("Successfully deleted enrolled user"); | |
1242 | 1 | fpi_device_delete_complete (device, NULL); | |
1243 | } | ||
1244 | |||
1245 | static void | ||
1246 | 1 | fp_template_delete_all_cb (FpiDeviceGoodixMoc *self, | |
1247 | gxfp_cmd_response_t *resp, | ||
1248 | GError *error) | ||
1249 | { | ||
1250 | 1 | FpDevice *device = FP_DEVICE (self); | |
1251 | |||
1252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1253 | { | ||
1254 | ✗ | fpi_device_clear_storage_complete (device, error); | |
1255 | ✗ | return; | |
1256 | } | ||
1257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) |
1258 | { | ||
1259 | ✗ | fpi_device_clear_storage_complete (FP_DEVICE (self), | |
1260 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1261 | "Failed clear storage, result: 0x%x", | ||
1262 | resp->result)); | ||
1263 | ✗ | return; | |
1264 | } | ||
1265 | |||
1266 | 1 | fp_info ("Successfully cleared storage"); | |
1267 | 1 | fpi_device_clear_storage_complete (device, NULL); | |
1268 | } | ||
1269 | |||
1270 | /****************************************************************************** | ||
1271 | * | ||
1272 | * fp_template_list Function | ||
1273 | * | ||
1274 | *****************************************************************************/ | ||
1275 | static void | ||
1276 | 1 | fp_template_list_cb (FpiDeviceGoodixMoc *self, | |
1277 | gxfp_cmd_response_t *resp, | ||
1278 | GError *error) | ||
1279 | { | ||
1280 | 1 | FpDevice *device = FP_DEVICE (self); | |
1281 | |||
1282 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1283 | { | ||
1284 | ✗ | fpi_device_list_complete (FP_DEVICE (self), NULL, error); | |
1285 | ✗ | return; | |
1286 | } | ||
1287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result != GX_SUCCESS) |
1288 | { | ||
1289 | ✗ | fp_info ("Failed to query enrolled users: %d", resp->result); | |
1290 | ✗ | fpi_device_list_complete (FP_DEVICE (self), | |
1291 | NULL, | ||
1292 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1293 | "Failed to query enrolled users, result: 0x%x", | ||
1294 | ✗ | resp->result)); | |
1295 | ✗ | return; | |
1296 | } | ||
1297 | |||
1298 | 1 | self->list_result = g_ptr_array_new_with_free_func (g_object_unref); | |
1299 | |||
1300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(resp->finger_list_resp.finger_num == 0) |
1301 | { | ||
1302 | ✗ | fp_info ("Database is empty"); | |
1303 | ✗ | fpi_device_list_complete (device, | |
1304 | ✗ | g_steal_pointer (&self->list_result), | |
1305 | NULL); | ||
1306 | ✗ | return; | |
1307 | } | ||
1308 | |||
1309 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int n = 0; n < resp->finger_list_resp.finger_num; n++) |
1310 | { | ||
1311 | 1 | FpPrint *print; | |
1312 | |||
1313 | 1 | print = fp_print_from_template (self, &resp->finger_list_resp.finger_list[n]); | |
1314 | |||
1315 | 1 | g_ptr_array_add (self->list_result, g_object_ref_sink (print)); | |
1316 | } | ||
1317 | |||
1318 | 1 | fp_info ("Query complete!"); | |
1319 | 1 | fpi_device_list_complete (device, | |
1320 | 1 | g_steal_pointer (&self->list_result), | |
1321 | NULL); | ||
1322 | |||
1323 | } | ||
1324 | |||
1325 | /****************************************************************************** | ||
1326 | * | ||
1327 | * Interface Function | ||
1328 | * | ||
1329 | *****************************************************************************/ | ||
1330 | static void | ||
1331 | 1 | gx_fp_probe (FpDevice *device) | |
1332 | { | ||
1333 | 1 | GUsbDevice *usb_dev; | |
1334 | 1 | GError *error = NULL; | |
1335 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1336 | 1 | g_autofree gchar *serial = NULL; | |
1337 | 1 | gint productid = 0; | |
1338 | |||
1339 | /* Claim usb interface */ | ||
1340 | 1 | usb_dev = fpi_device_get_usb_device (device); | |
1341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_usb_device_open (usb_dev, &error)) |
1342 | { | ||
1343 | ✗ | fpi_device_probe_complete (device, NULL, NULL, error); | |
1344 | ✗ | return; | |
1345 | } | ||
1346 | |||
1347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_usb_device_reset (usb_dev, &error)) |
1348 | ✗ | goto err_close; | |
1349 | |||
1350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error)) |
1351 | ✗ | goto err_close; | |
1352 | |||
1353 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) |
1354 | { | ||
1355 | |||
1356 | 1 | serial = g_strdup ("emulated-device"); | |
1357 | } | ||
1358 | else | ||
1359 | { | ||
1360 | ✗ | serial = g_usb_device_get_string_descriptor (usb_dev, | |
1361 | ✗ | g_usb_device_get_serial_number_index (usb_dev), | |
1362 | &error); | ||
1363 | |||
1364 | ✗ | if (serial && !g_str_has_suffix (serial, "B0")) | |
1365 | ✗ | fp_warn ("Device with serial %s not supported", serial); | |
1366 | ✗ | if (error) | |
1367 | { | ||
1368 | ✗ | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), | |
1369 | 0, 0, NULL); | ||
1370 | ✗ | goto err_close; | |
1371 | } | ||
1372 | } | ||
1373 | 1 | productid = g_usb_device_get_pid (usb_dev); | |
1374 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | switch (productid) |
1375 | { | ||
1376 | 1 | case 0x6496: | |
1377 | case 0x60A2: | ||
1378 | case 0x60A4: | ||
1379 | case 0x6014: | ||
1380 | case 0x6092: | ||
1381 | case 0x6094: | ||
1382 | case 0x609A: | ||
1383 | case 0x609C: | ||
1384 | case 0x60BC: | ||
1385 | case 0x60C2: | ||
1386 | case 0x6304: | ||
1387 | case 0x631C: | ||
1388 | case 0x633C: | ||
1389 | case 0x634C: | ||
1390 | case 0x6384: | ||
1391 | case 0x639C: | ||
1392 | case 0x63AC: | ||
1393 | case 0x63BC: | ||
1394 | case 0x63CC: | ||
1395 | case 0x650A: | ||
1396 | case 0x650C: | ||
1397 | case 0x6582: | ||
1398 | case 0x6A94: | ||
1399 | case 0x659A: | ||
1400 | 1 | self->max_enroll_stage = 12; | |
1401 | 1 | break; | |
1402 | |||
1403 | ✗ | default: | |
1404 | ✗ | self->max_enroll_stage = DEFAULT_ENROLL_SAMPLES; | |
1405 | ✗ | break; | |
1406 | } | ||
1407 | |||
1408 | 1 | fpi_device_set_nr_enroll_stages (device, self->max_enroll_stage); | |
1409 | |||
1410 | 1 | g_usb_device_close (usb_dev, NULL); | |
1411 | 1 | fpi_device_probe_complete (device, serial, NULL, error); | |
1412 | 1 | return; | |
1413 | ✗ | err_close: | |
1414 | |||
1415 | ✗ | g_usb_device_close (usb_dev, NULL); | |
1416 | ✗ | fpi_device_probe_complete (device, NULL, NULL, error); | |
1417 | |||
1418 | } | ||
1419 | |||
1420 | static void | ||
1421 | 1 | gx_fp_init (FpDevice *device) | |
1422 | { | ||
1423 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1424 | 1 | GError *error = NULL; | |
1425 | 1 | int ret = 0; | |
1426 | |||
1427 | 1 | self->max_stored_prints = FP_MAX_FINGERNUM; | |
1428 | 1 | self->is_power_button_shield_on = false; | |
1429 | |||
1430 | 1 | self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1); | |
1431 | |||
1432 | 1 | ret = gx_proto_init_sensor_config (self->sensorcfg); | |
1433 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret != 0) |
1434 | { | ||
1435 | ✗ | error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "Init sensor failed"); | |
1436 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1437 | ✗ | return; | |
1438 | } | ||
1439 | 1 | self->sensorcfg->config[6] = self->max_enroll_stage; | |
1440 | |||
1441 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) |
1442 | { | ||
1443 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1444 | ✗ | return; | |
1445 | } | ||
1446 | |||
1447 | /* Claim usb interface */ | ||
1448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) |
1449 | { | ||
1450 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1451 | ✗ | return; | |
1452 | } | ||
1453 | |||
1454 | 1 | self->task_ssm = fpi_ssm_new (device, fp_init_sm_run_state, | |
1455 | FP_INIT_NUM_STATES); | ||
1456 | |||
1457 | 1 | fpi_ssm_start (self->task_ssm, fp_init_ssm_done); | |
1458 | |||
1459 | } | ||
1460 | |||
1461 | static void | ||
1462 | 1 | gx_fp_release_interface (FpiDeviceGoodixMoc *self, | |
1463 | GError *error) | ||
1464 | { | ||
1465 | 2 | g_autoptr(GError) release_error = NULL; | |
1466 | |||
1467 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_clear_pointer (&self->sensorcfg, g_free); |
1468 | |||
1469 | /* Release usb interface */ | ||
1470 | 1 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), | |
1471 | 0, 0, &release_error); | ||
1472 | /* Retain passed error if set, otherwise propagate error from release. */ | ||
1473 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (error == NULL) |
1474 | 1 | error = g_steal_pointer (&release_error); | |
1475 | |||
1476 | /* Notify close complete */ | ||
1477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | fpi_device_close_complete (FP_DEVICE (self), error); |
1478 | |||
1479 | 1 | } | |
1480 | |||
1481 | static void | ||
1482 | ✗ | gx_fp_exit_cb (FpiDeviceGoodixMoc *self, | |
1483 | gxfp_cmd_response_t *resp, | ||
1484 | GError *error) | ||
1485 | { | ||
1486 | |||
1487 | |||
1488 | ✗ | if (resp->result >= GX_FAILED) | |
1489 | ✗ | fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); | |
1490 | ✗ | self->is_power_button_shield_on = false; | |
1491 | ✗ | gx_fp_release_interface (self, error); | |
1492 | ✗ | } | |
1493 | |||
1494 | static void | ||
1495 | 1 | gx_fp_exit (FpDevice *device) | |
1496 | { | ||
1497 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1498 | |||
1499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (self->is_power_button_shield_on) |
1500 | { | ||
1501 | ✗ | goodix_sensor_cmd (self, | |
1502 | MOC_CMD0_PWR_BTN_SHIELD, | ||
1503 | MOC_CMD1_PWR_BTN_SHIELD_OFF, | ||
1504 | false, | ||
1505 | NULL, | ||
1506 | 0, | ||
1507 | gx_fp_exit_cb); | ||
1508 | } | ||
1509 | else | ||
1510 | { | ||
1511 | 1 | gx_fp_release_interface (self, NULL); | |
1512 | } | ||
1513 | |||
1514 | 1 | } | |
1515 | |||
1516 | |||
1517 | static void | ||
1518 | 2 | gx_fp_verify_identify (FpDevice *device) | |
1519 | { | ||
1520 | 2 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1521 | |||
1522 | 2 | self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state, | |
1523 | FP_VERIFY_NUM_STATES, | ||
1524 | FP_VERIFY_PWR_BTN_SHIELD_OFF, | ||
1525 | "verify"); | ||
1526 | |||
1527 | 2 | fpi_ssm_start (self->task_ssm, fp_verify_ssm_done); | |
1528 | |||
1529 | 2 | } | |
1530 | |||
1531 | static void | ||
1532 | 1 | gx_fp_enroll (FpDevice *device) | |
1533 | { | ||
1534 | |||
1535 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1536 | |||
1537 | 1 | self->enroll_stage = 0; | |
1538 | |||
1539 | 1 | self->task_ssm = fpi_ssm_new_full (device, fp_enroll_sm_run_state, | |
1540 | FP_ENROLL_NUM_STATES, | ||
1541 | FP_ENROLL_PWR_BTN_SHIELD_OFF, | ||
1542 | "enroll"); | ||
1543 | |||
1544 | 1 | fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done); | |
1545 | |||
1546 | 1 | } | |
1547 | |||
1548 | |||
1549 | static void | ||
1550 | 1 | gx_fp_template_list (FpDevice *device) | |
1551 | { | ||
1552 | |||
1553 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1554 | 1 | guint8 dummy[1] = { 0 }; | |
1555 | |||
1556 | 1 | G_DEBUG_HERE (); | |
1557 | |||
1558 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
1559 | false, | ||
1560 | (const guint8 *) &dummy, | ||
1561 | 1, | ||
1562 | fp_template_list_cb); | ||
1563 | 1 | } | |
1564 | |||
1565 | |||
1566 | |||
1567 | static void | ||
1568 | 1 | gx_fp_template_delete (FpDevice *device) | |
1569 | { | ||
1570 | |||
1571 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1572 | 1 | FpPrint *print = NULL; | |
1573 | |||
1574 | 1 | g_autoptr(GVariant) data = NULL; | |
1575 | 1 | guint8 finger; | |
1576 | 1 | const guint8 *user_id; | |
1577 | 1 | gsize user_id_len = 0; | |
1578 | 1 | const guint8 *tid; | |
1579 | 1 | gsize tid_len = 0; | |
1580 | 1 | gsize payload_len = 0; | |
1581 |
1/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | g_autofree guint8 *payload = NULL; |
1582 | |||
1583 | 1 | fpi_device_get_delete_data (device, &print); | |
1584 | |||
1585 | 1 | g_object_get (print, "fpi-data", &data, NULL); | |
1586 | |||
1587 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!parse_print_data (data, &finger, &tid, &tid_len, &user_id, &user_id_len)) |
1588 | { | ||
1589 | ✗ | fpi_device_delete_complete (device, | |
1590 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); | ||
1591 | ✗ | return; | |
1592 | } | ||
1593 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, (guint16 *) &payload_len)) |
1594 | { | ||
1595 | ✗ | fpi_device_delete_complete (device, | |
1596 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
1597 | "encode_finger_id failed")); | ||
1598 | ✗ | return; | |
1599 | } | ||
1600 | |||
1601 | 1 | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DEFAULT, | |
1602 | false, | ||
1603 | (const guint8 *) payload, | ||
1604 | payload_len, | ||
1605 | fp_template_delete_cb); | ||
1606 | |||
1607 | } | ||
1608 | |||
1609 | static void | ||
1610 | 1 | gx_fp_template_delete_all (FpDevice *device) | |
1611 | { | ||
1612 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1613 | |||
1614 | 1 | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL, | |
1615 | false, | ||
1616 | NULL, | ||
1617 | 0, | ||
1618 | fp_template_delete_all_cb); | ||
1619 | |||
1620 | 1 | } | |
1621 | |||
1622 | static void | ||
1623 | 1 | fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) | |
1624 | { | ||
1625 | |||
1626 | 1 | } | |
1627 | |||
1628 | static const FpIdEntry id_table[] = { | ||
1629 | { .vid = 0x27c6, .pid = 0x5840, }, | ||
1630 | { .vid = 0x27c6, .pid = 0x6014, }, | ||
1631 | { .vid = 0x27c6, .pid = 0x6092, }, | ||
1632 | { .vid = 0x27c6, .pid = 0x6094, }, | ||
1633 | { .vid = 0x27c6, .pid = 0x609A, }, | ||
1634 | { .vid = 0x27c6, .pid = 0x609C, }, | ||
1635 | { .vid = 0x27c6, .pid = 0x60A2, }, | ||
1636 | { .vid = 0x27c6, .pid = 0x60A4, }, | ||
1637 | { .vid = 0x27c6, .pid = 0x60BC, }, | ||
1638 | { .vid = 0x27c6, .pid = 0x60C2, }, | ||
1639 | { .vid = 0x27c6, .pid = 0x6304, }, | ||
1640 | { .vid = 0x27c6, .pid = 0x631C, }, | ||
1641 | { .vid = 0x27c6, .pid = 0x633C, }, | ||
1642 | { .vid = 0x27c6, .pid = 0x634C, }, | ||
1643 | { .vid = 0x27c6, .pid = 0x6384, }, | ||
1644 | { .vid = 0x27c6, .pid = 0x639C, }, | ||
1645 | { .vid = 0x27c6, .pid = 0x63AC, }, | ||
1646 | { .vid = 0x27c6, .pid = 0x63BC, }, | ||
1647 | { .vid = 0x27c6, .pid = 0x63CC, }, | ||
1648 | { .vid = 0x27c6, .pid = 0x6496, }, | ||
1649 | { .vid = 0x27c6, .pid = 0x650A, }, | ||
1650 | { .vid = 0x27c6, .pid = 0x650C, }, | ||
1651 | { .vid = 0x27c6, .pid = 0x6582, }, | ||
1652 | { .vid = 0x27c6, .pid = 0x6584, }, | ||
1653 | { .vid = 0x27c6, .pid = 0x658C, }, | ||
1654 | { .vid = 0x27c6, .pid = 0x6592, }, | ||
1655 | { .vid = 0x27c6, .pid = 0x6594, }, | ||
1656 | { .vid = 0x27c6, .pid = 0x659A, }, | ||
1657 | { .vid = 0x27c6, .pid = 0x659C, }, | ||
1658 | { .vid = 0x27c6, .pid = 0x6A94, }, | ||
1659 | { .vid = 0x27c6, .pid = 0x6512, }, | ||
1660 | { .vid = 0x27c6, .pid = 0x689A, }, | ||
1661 | { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ | ||
1662 | }; | ||
1663 | |||
1664 | |||
1665 | static void | ||
1666 | 121 | fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass) | |
1667 | { | ||
1668 | 121 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
1669 | |||
1670 | 121 | dev_class->id = "goodixmoc"; | |
1671 | 121 | dev_class->full_name = "Goodix MOC Fingerprint Sensor"; | |
1672 | 121 | dev_class->type = FP_DEVICE_TYPE_USB; | |
1673 | 121 | dev_class->scan_type = FP_SCAN_TYPE_PRESS; | |
1674 | 121 | dev_class->id_table = id_table; | |
1675 | 121 | dev_class->nr_enroll_stages = DEFAULT_ENROLL_SAMPLES; | |
1676 | 121 | dev_class->temp_hot_seconds = -1; | |
1677 | |||
1678 | 121 | dev_class->open = gx_fp_init; | |
1679 | 121 | dev_class->close = gx_fp_exit; | |
1680 | 121 | dev_class->probe = gx_fp_probe; | |
1681 | 121 | dev_class->enroll = gx_fp_enroll; | |
1682 | 121 | dev_class->delete = gx_fp_template_delete; | |
1683 | 121 | dev_class->clear_storage = gx_fp_template_delete_all; | |
1684 | 121 | dev_class->list = gx_fp_template_list; | |
1685 | 121 | dev_class->verify = gx_fp_verify_identify; | |
1686 | 121 | dev_class->identify = gx_fp_verify_identify; | |
1687 | |||
1688 | 121 | fpi_device_class_auto_initialize_features (dev_class); | |
1689 | 121 | dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK; | |
1690 | 121 | } | |
1691 |