GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/goodixmoc/goodix.c
Date: 2025-03-01 04:11:53
Exec Total Coverage
Lines: 511 676 75.6%
Functions: 45 47 95.7%
Branches: 133 254 52.4%

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