GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/goodixmoc/goodix.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 504 668 75.4%
Functions: 45 47 95.7%
Branches: 132 251 52.6%

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