GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 75.6% 524 / 0 / 693
Functions: 95.8% 46 / 0 / 48
Branches: 52.5% 139 / 0 / 265

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