GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 75.5% 514 / 0 / 681
Functions: 95.8% 46 / 0 / 48
Branches: 51.8% 133 / 0 / 257

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