GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.1% 747 / 0 / 848
Functions: 100.0% 53 / 0 / 53
Branches: 60.8% 169 / 0 / 278

libfprint/drivers/focaltech_moc/focaltech_moc.c
Line Branch Exec Source
1 /*
2 * Copyright (C) 2022 FocalTech Electronics Inc
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "focaltech_moc.h"
20
21 #include <ctype.h>
22
23 #define FP_COMPONENT "focaltech_moc"
24
25 #define FOCALTECH_QUIRK_SINGLE_SLOT 1
26 #define FOCALTECH_MOC_STATIC_USER_ID "focaltech_moc_static_id"
27
28 #include "drivers_api.h"
29
30
4/6
fpi_device_focaltech_moc_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 127 times.
fpi_device_focaltech_moc_get_type:
✓ Branch 2 → 3 taken 127 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 127 times.
✗ Branch 4 → 7 not taken.
405 G_DEFINE_TYPE (FpiDeviceFocaltechMoc, fpi_device_focaltech_moc, FP_TYPE_DEVICE)
31
32 static const FpIdEntry id_table[] = {
33 { .vid = 0x2808, .pid = 0x9e48, },
34 { .vid = 0x2808, .pid = 0xd979, },
35 { .vid = 0x2808, .pid = 0xa27a, },
36 { .vid = 0x2808, .pid = 0xa959, },
37 { .vid = 0x2808, .pid = 0xa99a, },
38 { .vid = 0x2808, .pid = 0xa57a, },
39 { .vid = 0x2808, .pid = 0xa78a, },
40 { .vid = 0x2808, .pid = 0xa97a, },
41 { .vid = 0x2808, .pid = 0x1579, },
42 { .vid = 0x2808, .pid = 0x077A, },
43 { .vid = 0x2808, .pid = 0x079A, },
44 { .vid = 0x2808, .pid = 0x5158, },
45 { .vid = 0x2808, .pid = 0x6553, .driver_data = FOCALTECH_QUIRK_SINGLE_SLOT, },
46 { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
47 };
48
49 typedef void (*SynCmdMsgCallback) (FpiDeviceFocaltechMoc *self,
50 uint8_t *buffer_in,
51 gsize length_in,
52 GError *error);
53
54 typedef struct
55 {
56 SynCmdMsgCallback callback;
57 } CommandData;
58
59 typedef struct
60 {
61 uint8_t h;
62 uint8_t l;
63 } FpCmdLen;
64
65 typedef struct
66 {
67 uint8_t magic;
68 FpCmdLen len;
69 } FpCmdHeader;
70
71 typedef struct
72 {
73 FpCmdHeader header;
74 uint8_t code;
75 uint8_t payload[0];
76 } FpCmd;
77
78 typedef struct
79 {
80 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
81 uint8_t b0;
82 uint8_t b1;
83 #else
84 uint8_t b1;
85 uint8_t b0;
86 #endif
87 } u16_bytes_t;
88
89 typedef union
90 {
91 u16_bytes_t s;
92 uint16_t v;
93 } u_u16_bytes_t;
94
95 static inline uint16_t
96 480 get_u16_from_u8_lh (uint8_t l, uint8_t h)
97 {
98 480 u_u16_bytes_t u_u16_bytes;
99
100 480 u_u16_bytes.v = 0;
101 480 u_u16_bytes.s.b0 = l;
102 480 u_u16_bytes.s.b1 = h;
103
104 480 return u_u16_bytes.v;
105 }
106
107 static inline uint8_t
108 480 get_u8_l_from_u16 (uint16_t v)
109 {
110 480 u_u16_bytes_t u_u16_bytes;
111
112 480 u_u16_bytes.v = v;
113
114 480 return u_u16_bytes.s.b0;
115 }
116
117 static inline uint8_t
118 480 get_u8_h_from_u16 (uint16_t v)
119 {
120 480 u_u16_bytes_t u_u16_bytes;
121
122 480 u_u16_bytes.v = v;
123
124 480 return u_u16_bytes.s.b1;
125 }
126
127 static uint8_t
128 960 fp_cmd_bcc (uint8_t *data, uint16_t len)
129 {
130 960 int i;
131 960 uint8_t bcc = 0;
132
133
4/4
✓ Branch 7 → 6 taken 4120 times.
✓ Branch 7 → 8 taken 480 times.
✓ Branch 8 → 7 taken 6253 times.
✓ Branch 8 → 9 taken 480 times.
11333 for (i = 0; i < len; i++)
134 10373 bcc ^= data[i];
135
136 960 return bcc;
137 }
138
139 static uint8_t *
140 480 focaltech_moc_compose_cmd (uint8_t cmd, const uint8_t *data, uint16_t len)
141 {
142 960 g_autofree uint8_t *cmd_buf = NULL;
143 480 FpCmd *fp_cmd = NULL;
144 480 uint8_t *bcc = NULL;
145 480 uint16_t header_len = len + sizeof (*bcc);
146
147 480 cmd_buf = g_new0 (uint8_t, sizeof (FpCmd) + header_len);
148
149 480 fp_cmd = (FpCmd *) cmd_buf;
150
151 480 fp_cmd->header.magic = 0x02;
152 480 fp_cmd->header.len.l = get_u8_l_from_u16 (header_len);
153 480 fp_cmd->header.len.h = get_u8_h_from_u16 (header_len);
154 480 fp_cmd->code = cmd;
155
156
2/2
✓ Branch 3 → 4 taken 427 times.
✓ Branch 3 → 5 taken 53 times.
480 if (data != NULL)
157 427 memcpy (fp_cmd->payload, data, len);
158
159 480 bcc = fp_cmd->payload + len;
160 480 *bcc = fp_cmd_bcc ((uint8_t *) &fp_cmd->header.len, bcc - (uint8_t *) &fp_cmd->header.len);
161
162 480 return g_steal_pointer (&cmd_buf);
163 }
164
165 static int
166 480 focaltech_moc_check_cmd (uint8_t *response_buf, uint16_t len)
167 {
168 480 int ret = -1;
169 480 FpCmd *fp_cmd = NULL;
170 480 uint8_t *bcc = NULL;
171 480 uint16_t header_len;
172 480 uint16_t data_len;
173
174 480 fp_cmd = (FpCmd *) response_buf;
175
176
1/2
✓ Branch 2 → 3 taken 480 times.
✗ Branch 2 → 11 not taken.
480 if (len < sizeof (FpCmd) + sizeof (*bcc))
177 return ret;
178
179
1/2
✓ Branch 3 → 4 taken 480 times.
✗ Branch 3 → 11 not taken.
480 if (fp_cmd->header.magic != 0x02)
180 return ret;
181
182 480 header_len = get_u16_from_u8_lh (fp_cmd->header.len.l, fp_cmd->header.len.h);
183
184
1/2
✓ Branch 4 → 5 taken 480 times.
✗ Branch 4 → 11 not taken.
480 if (header_len < sizeof (*bcc))
185 return ret;
186
187
1/2
✓ Branch 5 → 6 taken 480 times.
✗ Branch 5 → 11 not taken.
480 if ((sizeof (FpCmd) + header_len) > len)
188 return ret;
189
190 480 data_len = header_len - sizeof (*bcc);
191
192 480 bcc = fp_cmd->payload + data_len;
193
194 480 if (fp_cmd_bcc ((uint8_t *) &fp_cmd->header.len,
195
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 480 times.
480 bcc - (uint8_t *) &fp_cmd->header.len) != *bcc)
196 return ret;
197
198 480 ret = 0;
199 return ret;
200 }
201
202 static gboolean
203 30 focaltech_moc_require_response_len (FpiDeviceFocaltechMoc *self,
204 gsize length_in,
205 gsize minimum_length,
206 const char *context)
207 {
208
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 30 times.
30 if (length_in >= minimum_length)
209 return TRUE;
210
211 fpi_ssm_mark_failed (self->task_ssm,
212 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
213 "%s: short response (%zu < %zu)",
214 context, length_in, minimum_length));
215 return FALSE;
216 }
217
218 static void
219 480 fp_cmd_receive_cb (FpiUsbTransfer *transfer,
220 FpDevice *device,
221 gpointer userdata,
222 GError *error)
223 {
224 480 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
225 480 CommandData *data = userdata;
226 480 int ssm_state = 0;
227
228
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 480 times.
480 if (error)
229 {
230 fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
231 return;
232 }
233
234
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 9 taken 480 times.
480 if (data == NULL)
235 {
236 fpi_ssm_mark_failed (transfer->ssm,
237 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
238 return;
239 }
240
241 480 ssm_state = fpi_ssm_get_cur_state (transfer->ssm);
242
243 /* skip zero length package */
244
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 480 times.
480 if (transfer->actual_length == 0)
245 {
246 fpi_ssm_jump_to_state (transfer->ssm, ssm_state);
247 return;
248 }
249
250
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 17 taken 480 times.
480 if (focaltech_moc_check_cmd (transfer->buffer, transfer->actual_length) != 0)
251 {
252 fpi_ssm_mark_failed (transfer->ssm,
253 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
254 return;
255 }
256
257
1/2
✓ Branch 17 → 18 taken 480 times.
✗ Branch 17 → 19 not taken.
480 if (data->callback)
258 480 data->callback (self, transfer->buffer, transfer->actual_length, NULL);
259
260 480 fpi_ssm_mark_completed (transfer->ssm);
261 }
262
263 typedef enum {
264 FOCALTECH_CMD_SEND = 0,
265 FOCALTECH_CMD_GET,
266 FOCALTECH_CMD_NUM_STATES,
267 } FocaltechCmdState;
268
269 static void
270 960 fp_cmd_run_state (FpiSsm *ssm,
271 FpDevice *device)
272 {
273 960 FpiUsbTransfer *transfer;
274 960 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
275
276
2/3
✓ Branch 3 → 4 taken 480 times.
✓ Branch 3 → 7 taken 480 times.
✗ Branch 3 → 22 not taken.
960 switch (fpi_ssm_get_cur_state (ssm))
277 {
278 480 case FOCALTECH_CMD_SEND:
279
1/2
✓ Branch 4 → 5 taken 480 times.
✗ Branch 4 → 6 not taken.
480 if (self->cmd_transfer)
280 {
281 480 self->cmd_transfer->ssm = ssm;
282 480 fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer),
283 FOCALTECH_MOC_CMD_TIMEOUT,
284 NULL,
285 fpi_ssm_usb_transfer_cb,
286 NULL);
287 }
288 else
289 {
290 fpi_ssm_next_state (ssm);
291 }
292
293 break;
294
295 480 case FOCALTECH_CMD_GET:
296
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 13 taken 480 times.
480 if (self->cmd_len_in == 0)
297 {
298 CommandData *data = fpi_ssm_get_data (ssm);
299
300 if (data->callback)
301 data->callback (self, NULL, 0, 0);
302
303 fpi_ssm_mark_completed (ssm);
304 return;
305 }
306
307 480 transfer = fpi_usb_transfer_new (device);
308 480 transfer->ssm = ssm;
309 480 fpi_usb_transfer_fill_bulk (transfer, self->bulk_in_ep, self->cmd_len_in);
310 480 fpi_usb_transfer_submit (transfer,
311
2/2
✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 20 taken 477 times.
480 self->cmd_cancelable ? 0 : FOCALTECH_MOC_CMD_TIMEOUT,
312
2/2
✓ Branch 16 → 17 taken 477 times.
✓ Branch 16 → 18 taken 3 times.
480 self->cmd_cancelable ? fpi_device_get_cancellable (device) : NULL,
313 fp_cmd_receive_cb,
314 fpi_ssm_get_data (ssm));
315 480 break;
316
317 }
318
319 }
320
321 static void
322 480 fp_cmd_ssm_done (FpiSsm *ssm, FpDevice *device, GError *error)
323 {
324 960 g_autoptr(GError) local_error = error;
325 480 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
326 480 CommandData *data = fpi_ssm_get_data (ssm);
327
328 480 self->cmd_ssm = NULL;
329
330
1/4
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 480 times.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
480 if (local_error && data->callback)
331 data->callback (self, NULL, 0, g_steal_pointer (&local_error));
332 480 }
333
334 static void
335 480 fp_cmd_ssm_done_data_free (CommandData *data)
336 {
337 480 g_free (data);
338 480 }
339
340 static void
341 480 focaltech_moc_get_cmd (FpDevice *device, guint8 *buffer_out,
342 gsize length_out, gsize length_in,
343 gboolean can_be_cancelled,
344 SynCmdMsgCallback callback)
345 {
346 480 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
347
348 960 g_autoptr(FpiUsbTransfer) transfer = NULL;
349 480 CommandData *data = g_new0 (CommandData, 1);
350
351 480 transfer = fpi_usb_transfer_new (device);
352 480 transfer->short_is_error = TRUE;
353 480 fpi_usb_transfer_fill_bulk_full (transfer, self->bulk_out_ep, buffer_out,
354 length_out, g_free);
355 480 data->callback = callback;
356
357 480 self->cmd_transfer = g_steal_pointer (&transfer);
358 480 self->cmd_len_in = length_in + 1;
359 480 self->cmd_cancelable = can_be_cancelled;
360
361 480 self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
362 fp_cmd_run_state,
363 FOCALTECH_CMD_NUM_STATES);
364
365 480 fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free);
366
367 480 fpi_ssm_start (self->cmd_ssm, fp_cmd_ssm_done);
368 480 }
369
370 struct UserId
371 {
372 uint8_t uid[32];
373 };
374
375 static void
376 9 fprint_set_uid (FpPrint *print, uint8_t *uid, size_t size)
377 {
378 9 GVariant *var_uid;
379 9 GVariant *var_data;
380
381 9 var_uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, uid, size, 1);
382 9 var_data = g_variant_new ("(@ay)", var_uid);
383 9 fpi_print_set_type (print, FPI_PRINT_RAW);
384 9 fpi_print_set_device_stored (print, TRUE);
385 9 g_object_set (print, "fpi-data", var_data, NULL);
386 9 }
387
388 enum enroll_states {
389 ENROLL_RSP_RETRY,
390 ENROLL_RSP_ENROLL_REPORT,
391 ENROLL_RSP_ENROLL_OK,
392 ENROLL_RSP_ENROLL_CANCEL_REPORT,
393 };
394
395 static void
396 34 enroll_status_report (FpiDeviceFocaltechMoc *self, int enroll_status_id,
397 int data, GError *error)
398 {
399 34 FpDevice *device = FP_DEVICE (self);
400
401
3/5
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 6 taken 28 times.
✓ Branch 2 → 8 taken 2 times.
✗ Branch 2 → 13 not taken.
✗ Branch 2 → 15 not taken.
34 switch (enroll_status_id)
402 {
403 4 case ENROLL_RSP_RETRY:
404 {
405 4 fpi_device_enroll_progress (device, self->num_frames, NULL,
406 fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER));
407 4 break;
408 }
409
410 28 case ENROLL_RSP_ENROLL_REPORT:
411 {
412 28 fpi_device_enroll_progress (device, self->num_frames, NULL, NULL);
413 28 break;
414 }
415
416 2 case ENROLL_RSP_ENROLL_OK:
417 {
418 2 FpPrint *print = NULL;
419 2 fp_info ("Enrollment was successful!");
420 2 fpi_device_get_enroll_data (device, &print);
421 2 fpi_device_enroll_complete (device, g_object_ref (print), NULL);
422 2 break;
423 }
424
425 case ENROLL_RSP_ENROLL_CANCEL_REPORT:
426 {
427 fpi_device_enroll_complete (device, NULL,
428 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
429 "Enrollment failed (%d) (ENROLL_RSP_ENROLL_CANCEL_REPORT)",
430 data));
431 }
432 }
433 34 }
434
435 static void
436 13 task_ssm_done (FpiSsm *ssm, FpDevice *device, GError *error)
437 {
438 13 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
439
440 13 self->num_frames = 0;
441 13 self->task_ssm = NULL;
442
443
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 13 times.
13 if (error)
444 fpi_device_action_error (device, g_steal_pointer (&error));
445 13 }
446
447 static const char *
448 4 get_g_usb_device_direction_des (GUsbDeviceDirection dir)
449 {
450 4 switch (dir)
451 {
452 case G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST:
453 return "G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST";
454
455 2 case G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE:
456 2 return "G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE";
457
458 default:
459 return "unknown";
460 }
461 }
462
463 static gboolean
464 4 usb_claim_interface_probe (FpDevice *device, gboolean claim, GError **error)
465 {
466 8 g_autoptr(GPtrArray) interfaces = NULL;
467 4 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
468 4 int i;
469
470 4 interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (device), error);
471
1/2
✓ Branch 4 → 47 taken 4 times.
✗ Branch 4 → 49 not taken.
4 if (interfaces == NULL)
472 return FALSE;
473
474
2/2
✓ Branch 47 → 5 taken 4 times.
✓ Branch 47 → 48 taken 4 times.
8 for (i = 0; i < interfaces->len; i++)
475 {
476 4 GUsbInterface *cur_iface = g_ptr_array_index (interfaces, i);
477 12 g_autoptr(GPtrArray) endpoints = g_usb_interface_get_endpoints (cur_iface);
478
479 4 fp_dbg ("class:%x, subclass:%x, protocol:%x",
480 g_usb_interface_get_class (cur_iface),
481 g_usb_interface_get_subclass (cur_iface),
482 g_usb_interface_get_protocol (cur_iface));
483
484
2/2
✓ Branch 10 → 33 taken 2 times.
✓ Branch 10 → 38 taken 2 times.
4 if (claim)
485 {
486
2/2
✓ Branch 33 → 11 taken 4 times.
✓ Branch 33 → 34 taken 2 times.
6 for (int j = 0; j < endpoints->len; j++)
487 {
488 4 GUsbEndpoint *endpoint = g_ptr_array_index (endpoints, j);
489 4 GBytes *bytes = g_usb_endpoint_get_extra (endpoint);
490
491 4 fp_dbg ("bytes size:%ld", g_bytes_get_size (bytes));
492
493
2/3
✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 17 not taken.
✓ Branch 15 → 18 taken 2 times.
6 fp_dbg ("kind:%x, max packet size:%d, poll interval:%d, refresh:%x, "
494 "sync address:%x, address:%x, number:%d, direction:%s",
495 g_usb_endpoint_get_kind (endpoint),
496 g_usb_endpoint_get_maximum_packet_size (endpoint),
497 g_usb_endpoint_get_polling_interval (endpoint),
498 g_usb_endpoint_get_refresh (endpoint),
499 g_usb_endpoint_get_synch_address (endpoint),
500 g_usb_endpoint_get_address (endpoint),
501 g_usb_endpoint_get_number (endpoint),
502 get_g_usb_device_direction_des (g_usb_endpoint_get_direction (endpoint)));
503
504
2/2
✓ Branch 27 → 28 taken 2 times.
✓ Branch 27 → 30 taken 2 times.
4 if (g_usb_endpoint_get_direction (endpoint) == G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST)
505 2 self->bulk_in_ep = g_usb_endpoint_get_address (endpoint);
506 else
507 2 self->bulk_out_ep = g_usb_endpoint_get_address (endpoint);
508 }
509
510
1/2
✓ Branch 37 → 42 taken 2 times.
✗ Branch 37 → 45 not taken.
2 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device),
511 2 g_usb_interface_get_number (cur_iface),
512 0, error))
513 return FALSE;
514 }
515
1/2
✓ Branch 41 → 42 taken 2 times.
✗ Branch 41 → 45 not taken.
2 else if (!g_usb_device_release_interface (fpi_device_get_usb_device (device),
516 2 g_usb_interface_get_number (cur_iface),
517 0, error))
518 {
519 return FALSE;
520 }
521 }
522
523 return TRUE;
524 }
525
526 static void
527 2 task_ssm_init_done (FpiSsm *ssm, FpDevice *device, GError *error)
528 {
529 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
530
531
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 if (error)
532 usb_claim_interface_probe (device, FALSE, NULL);
533
534 2 fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
535 2 }
536
537 struct EnrollTimes
538 {
539 uint8_t enroll_times;
540 };
541
542 static void
543 2 focaltech_moc_get_enroll_times (FpiDeviceFocaltechMoc *self,
544 uint8_t *buffer_in,
545 gsize length_in,
546 GError *error)
547 {
548 2 FpCmd *fp_cmd = NULL;
549 2 struct EnrollTimes *enroll_times = NULL;
550
551
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 2 times.
2 if (error)
552 {
553 fpi_ssm_mark_failed (self->task_ssm, error);
554 return;
555 }
556
557 2 fp_cmd = (FpCmd *) buffer_in;
558 2 enroll_times = (struct EnrollTimes *) (fp_cmd + 1);
559
560
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 2 times.
2 if (fp_cmd->code != 0x04)
561 {
562 fpi_ssm_mark_failed (self->task_ssm,
563 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
564 "Can't get response!!"));
565 }
566 else
567 {
568 2 fp_dbg ("focaltechmoc enroll_times: %d", enroll_times->enroll_times + 1);
569 2 fpi_device_set_nr_enroll_stages (FP_DEVICE (self), enroll_times->enroll_times + 1);
570 2 fpi_ssm_next_state (self->task_ssm);
571 }
572 }
573
574 static void
575 8 focaltech_moc_release_finger (FpiDeviceFocaltechMoc *self,
576 uint8_t *buffer_in,
577 gsize length_in,
578 GError *error)
579 {
580 8 FpCmd *fp_cmd = NULL;
581
582
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 8 times.
8 if (error)
583 {
584 fpi_ssm_mark_failed (self->task_ssm, error);
585 return;
586 }
587
588 8 fp_cmd = (FpCmd *) buffer_in;
589
590
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 8 times.
8 if (fp_cmd->code != 0x04)
591 {
592 fpi_ssm_mark_failed (self->task_ssm,
593 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
594 "Can't get response!!"));
595 }
596 else
597 {
598 8 fpi_ssm_next_state (self->task_ssm);
599 }
600 }
601
602 enum dev_init_states {
603 DEV_INIT_GET_ENROLL_TIMES,
604 DEV_INIT_RELEASE_FINGER,
605 DEV_INIT_STATES,
606 };
607
608 static void
609 4 dev_init_handler (FpiSsm *ssm, FpDevice *device)
610 {
611 4 guint8 *cmd_buf = NULL;
612 4 uint16_t cmd_len = 0;
613 4 uint16_t resp_len = 0;
614
615
2/3
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 7 taken 2 times.
✗ Branch 3 → 10 not taken.
4 switch (fpi_ssm_get_cur_state (ssm))
616 {
617 2 case DEV_INIT_GET_ENROLL_TIMES:
618 2 cmd_len = 0;
619 2 resp_len = sizeof (struct EnrollTimes);
620 2 cmd_buf = focaltech_moc_compose_cmd (0xa5, NULL, cmd_len);
621 2 focaltech_moc_get_cmd (device, cmd_buf,
622 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
623 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
624 1,
625 focaltech_moc_get_enroll_times);
626 2 break;
627
628 2 case DEV_INIT_RELEASE_FINGER:
629 {
630 2 uint8_t d1 = 0x78;
631 2 cmd_len = sizeof (d1);
632 2 resp_len = 0;
633 2 cmd_buf = focaltech_moc_compose_cmd (0x82, &d1, cmd_len);
634 2 focaltech_moc_get_cmd (device, cmd_buf,
635 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
636 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
637 1,
638 focaltech_moc_release_finger);
639 2 break;
640 }
641 }
642 4 }
643
644 static void
645 2 focaltech_moc_open (FpDevice *device)
646 {
647 2 g_autoptr(GError) error = NULL;
648 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
649
650
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
651 {
652 fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
653 return;
654 }
655
656
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 2 times.
2 if (!usb_claim_interface_probe (device, TRUE, &error))
657 {
658 fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
659 return;
660 }
661
662 2 self->task_ssm = fpi_ssm_new (FP_DEVICE (self), dev_init_handler, DEV_INIT_STATES);
663
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 2 times.
2 fpi_ssm_start (self->task_ssm, task_ssm_init_done);
664 }
665
666 static void
667 2 task_ssm_exit_done (FpiSsm *ssm, FpDevice *device, GError *error)
668 {
669 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
670
671
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2 if (!error)
672 2 usb_claim_interface_probe (device, FALSE, &error);
673
674 2 fpi_device_close_complete (FP_DEVICE (self), error);
675 2 self->task_ssm = NULL;
676 2 }
677
678 enum dev_exit_states {
679 DEV_EXIT_START,
680 DEV_EXIT_STATES,
681 };
682
683 static void
684 2 dev_exit_handler (FpiSsm *ssm, FpDevice *device)
685 {
686 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
687
688
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
2 switch (fpi_ssm_get_cur_state (ssm))
689 {
690 2 case DEV_EXIT_START:
691 2 fpi_ssm_next_state (self->task_ssm);
692 2 break;
693
694 default:
695 2 g_assert_not_reached ();
696 }
697 2 }
698
699 static void
700 2 focaltech_moc_close (FpDevice *device)
701 {
702 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
703
704 2 fp_info ("Focaltechmoc dev_exit");
705 2 self->task_ssm = fpi_ssm_new (FP_DEVICE (self), dev_exit_handler, DEV_EXIT_STATES);
706 2 fpi_ssm_start (self->task_ssm, task_ssm_exit_done);
707 2 }
708
709 enum identify_states {
710 MOC_IDENTIFY_RELEASE_FINGER,
711 MOC_IDENTIFY_WAIT_FINGER,
712 MOC_IDENTIFY_WAIT_FINGER_DELAY,
713 MOC_IDENTIFY_CAPTURE,
714 MOC_IDENTIFY_MATCH,
715 MOC_IDENTIFY_NUM_STATES,
716 };
717
718 static void
719 106 focaltech_moc_identify_wait_finger_cb (FpiDeviceFocaltechMoc *self,
720 uint8_t *buffer_in,
721 gsize length_in,
722 GError *error)
723 {
724 106 FpCmd *fp_cmd = NULL;
725 106 uint8_t *finger_status = NULL;
726
727
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 106 times.
106 if (error)
728 {
729 fpi_ssm_mark_failed (self->task_ssm, error);
730 return;
731 }
732
733 106 fp_cmd = (FpCmd *) buffer_in;
734 106 finger_status = (uint8_t *) (fp_cmd + 1);
735
736
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 106 times.
106 if (fp_cmd->code != 0x04)
737 {
738 fpi_ssm_mark_failed (self->task_ssm,
739 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
740 "Can't get response!!"));
741 }
742 else
743 {
744
745
2/2
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 10 taken 102 times.
106 if (*finger_status == 0x01)
746 4 fpi_ssm_jump_to_state (self->task_ssm, MOC_IDENTIFY_CAPTURE);
747 else
748 102 fpi_ssm_jump_to_state (self->task_ssm, MOC_IDENTIFY_WAIT_FINGER_DELAY);
749 }
750 }
751
752 static void
753 102 focaltech_moc_identify_wait_finger_delay (FpDevice *device,
754 void *user_data)
755 {
756 102 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
757
758 102 fpi_ssm_jump_to_state (self->task_ssm, MOC_IDENTIFY_WAIT_FINGER);
759 102 }
760
761 enum FprintError {
762 ERROR_NONE,
763 ERROR_QUALITY,
764 ERROR_SHORT,
765 ERROR_LEFT,
766 ERROR_RIGHT,
767 ERROR_NONFINGER,
768 ERROR_NOMOVE,
769 ERROR_OTHER,
770 };
771
772 struct CaptureResult
773 {
774 uint8_t error;
775 uint8_t remain;
776 };
777
778 static void
779 4 focaltech_moc_identify_capture_cb (FpiDeviceFocaltechMoc *self,
780 uint8_t *buffer_in,
781 gsize length_in,
782 GError *error)
783 {
784 4 FpCmd *fp_cmd = NULL;
785 4 struct CaptureResult *capture_result = NULL;
786
787
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 4 times.
4 if (error)
788 {
789 fpi_ssm_mark_failed (self->task_ssm, error);
790 return;
791 }
792
793 4 fp_cmd = (FpCmd *) buffer_in;
794 4 capture_result = (struct CaptureResult *) (fp_cmd + 1);
795
796
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 4 times.
4 if (fp_cmd->code != 0x04)
797 {
798 fpi_ssm_mark_failed (self->task_ssm,
799 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
800 "Can't get response!!"));
801 }
802 else
803 {
804
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 10 not taken.
4 if (capture_result->error == ERROR_NONE)
805 {
806 4 fpi_ssm_next_state (self->task_ssm);
807 }
808 else
809 {
810 fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
811 fpi_device_identify_complete (FP_DEVICE (self), NULL);
812
813 fpi_ssm_mark_failed (self->task_ssm, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
814 }
815 }
816 }
817
818 static void
819 4 identify_status_report (FpiDeviceFocaltechMoc *self, FpPrint *print, GError *error)
820 {
821 4 FpDevice *device = FP_DEVICE (self);
822
823
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 4 times.
4 if (print == NULL)
824 {
825 fpi_device_identify_report (device, NULL, NULL, NULL);
826 fpi_device_identify_complete (device, NULL);
827 }
828 else
829 {
830 4 GPtrArray *prints;
831 4 gboolean found = FALSE;
832 4 guint index;
833
834 4 fpi_device_get_identify_data (device, &prints);
835 4 found = g_ptr_array_find_with_equal_func (prints,
836 print,
837 (GEqualFunc) fp_print_equal,
838 &index);
839
840
1/2
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 9 not taken.
4 if (found)
841 4 fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
842 else
843 fpi_device_identify_report (device, NULL, print, NULL);
844
845 4 fpi_device_identify_complete (device, NULL);
846 }
847 4 }
848
849 static void
850 4 focaltech_moc_identify_match_cb (FpiDeviceFocaltechMoc *self,
851 uint8_t *buffer_in,
852 gsize length_in,
853 GError *error)
854 {
855 4 FpCmd *fp_cmd = NULL;
856 4 struct UserId *user_id = NULL;
857 4 FpPrint *print = NULL;
858
859 4 fp_cmd = (FpCmd *) buffer_in;
860 4 user_id = (struct UserId *) (fp_cmd + 1);
861
862
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 4 times.
4 if (error)
863 {
864 fpi_ssm_mark_failed (self->task_ssm, error);
865 return;
866 }
867
868
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 8 not taken.
4 if (fp_cmd->code == 0x04)
869 {
870 4 print = fp_print_new (FP_DEVICE (self));
871 4 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
872 }
873
874 4 identify_status_report (self, print, error);
875
876 4 fpi_ssm_next_state (self->task_ssm);
877 }
878
879 static void
880 220 focaltech_identify_run_state (FpiSsm *ssm, FpDevice *device)
881 {
882 220 guint8 *cmd_buf = NULL;
883 220 uint16_t cmd_len = 0;
884 220 uint16_t resp_len = 0;
885
886
5/6
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 106 times.
✓ Branch 3 → 10 taken 102 times.
✓ Branch 3 → 12 taken 4 times.
✓ Branch 3 → 15 taken 4 times.
✗ Branch 3 → 18 not taken.
220 switch (fpi_ssm_get_cur_state (ssm))
887 {
888 4 case MOC_IDENTIFY_RELEASE_FINGER:
889 {
890 4 uint8_t d1 = 0x78;
891 4 cmd_len = sizeof (d1);
892 4 resp_len = 0;
893 4 cmd_buf = focaltech_moc_compose_cmd (0x82, &d1, cmd_len);
894 4 focaltech_moc_get_cmd (device, cmd_buf,
895 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
896 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
897 1,
898 focaltech_moc_release_finger);
899 4 break;
900 }
901
902 106 case MOC_IDENTIFY_WAIT_FINGER:
903 {
904 106 uint8_t data = 0x02;
905 106 cmd_len = sizeof (uint8_t);
906 106 resp_len = sizeof (uint8_t);
907 106 cmd_buf = focaltech_moc_compose_cmd (0x80, &data, cmd_len);
908 106 focaltech_moc_get_cmd (device, cmd_buf,
909 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
910 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
911 1,
912 focaltech_moc_identify_wait_finger_cb);
913 106 break;
914 }
915
916 102 case MOC_IDENTIFY_WAIT_FINGER_DELAY:
917 102 fpi_device_add_timeout (device, 50,
918 focaltech_moc_identify_wait_finger_delay,
919 NULL, NULL);
920 102 break;
921
922 4 case MOC_IDENTIFY_CAPTURE:
923 4 cmd_len = 0;
924 4 resp_len = sizeof (struct CaptureResult);
925 4 cmd_buf = focaltech_moc_compose_cmd (0xa6, NULL, cmd_len);
926 4 focaltech_moc_get_cmd (device, cmd_buf,
927 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
928 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
929 1,
930 focaltech_moc_identify_capture_cb);
931 4 break;
932
933 4 case MOC_IDENTIFY_MATCH:
934 4 cmd_len = 0;
935 4 resp_len = sizeof (struct UserId);
936 4 cmd_buf = focaltech_moc_compose_cmd (0xaa, NULL, cmd_len);
937 4 focaltech_moc_get_cmd (device, cmd_buf,
938 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
939 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
940 1,
941 focaltech_moc_identify_match_cb);
942 4 break;
943 }
944 220 }
945
946 static void
947 4 focaltech_moc_identify (FpDevice *device)
948 {
949 4 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
950
951 4 self->task_ssm = fpi_ssm_new (device,
952 focaltech_identify_run_state,
953 MOC_IDENTIFY_NUM_STATES);
954 4 fpi_ssm_start (self->task_ssm, task_ssm_done);
955 4 }
956
957 enum moc_enroll_states {
958 MOC_ENROLL_GET_ENROLLED_INFO,
959 MOC_ENROLL_GET_ENROLLED_LIST,
960 MOC_ENROLL_RELEASE_FINGER,
961 MOC_ENROLL_START_ENROLL,
962 MOC_ENROLL_WAIT_FINGER,
963 MOC_ENROLL_WAIT_FINGER_DELAY,
964 MOC_ENROLL_ENROLL_CAPTURE,
965 MOC_ENROLL_SET_ENROLLED_INFO,
966 MOC_ENROLL_COMMIT_RESULT,
967 MOC_ENROLL_NUM_STATES,
968 };
969
970 struct EnrolledInfoItem
971 {
972 uint8_t uid[FOCALTECH_MOC_UID_PREFIX_LENGTH];
973 uint8_t user_id[FOCALTECH_MOC_USER_ID_LENGTH];
974 };
975
976 struct UserDes
977 {
978 uint8_t finger;
979 char username[FOCALTECH_MOC_USER_ID_LENGTH];
980 };
981
982 struct EnrolledInfo
983 {
984 uint8_t actived[FOCALTECH_MOC_MAX_FINGERS];
985 struct EnrolledInfoItem items[FOCALTECH_MOC_MAX_FINGERS];
986 struct UserId user_id[FOCALTECH_MOC_MAX_FINGERS];
987 struct UserDes user_des[FOCALTECH_MOC_MAX_FINGERS];
988 };
989
990 typedef struct
991 {
992 GPtrArray *list_result;
993 struct EnrolledInfo *enrolled_info;
994 } FpActionData;
995
996 struct EnrolledInfoSetData
997 {
998 uint8_t data;
999 struct EnrolledInfoItem items[FOCALTECH_MOC_MAX_FINGERS];
1000 };
1001
1002 static void
1003 6 fp_action_ssm_done_data_free (FpActionData *data)
1004 {
1005
2/2
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 3 times.
6 g_clear_pointer (&data->list_result, g_ptr_array_unref);
1006
1/2
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 6 not taken.
6 g_clear_pointer (&data->enrolled_info, g_free);
1007 6 g_free (data);
1008 6 }
1009
1010 static void
1011 6 focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
1012 uint8_t *buffer_in,
1013 gsize length_in,
1014 GError *error)
1015 {
1016 6 FpCmd *fp_cmd = NULL;
1017 6 struct EnrolledInfoItem *items = NULL;
1018 6 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1019
1020
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 6 times.
6 if (error)
1021 {
1022 fpi_ssm_mark_failed (self->task_ssm, error);
1023 return;
1024 }
1025
1026
1/2
✓ Branch 7 → 8 taken 6 times.
✗ Branch 7 → 17 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1027 sizeof (FpCmd) + sizeof (uint8_t),
1028 "get enrolled info"))
1029 return;
1030
1031 6 fp_cmd = (FpCmd *) buffer_in;
1032 6 items = (struct EnrolledInfoItem *) (fp_cmd + 1);
1033
1034
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 6 times.
6 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1035 {
1036 fpi_ssm_mark_failed (self->task_ssm,
1037 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1038 "Can't get response!!"));
1039 }
1040 else
1041 {
1042
2/2
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 15 taken 3 times.
6 if (fp_cmd->code == 0x04)
1043 {
1044
1/2
✓ Branch 13 → 14 taken 3 times.
✗ Branch 13 → 17 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1045 sizeof (FpCmd) +
1046 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem) +
1047 sizeof (uint8_t),
1048 "get enrolled info"))
1049 return;
1050 3 memcpy (&data->enrolled_info->items[0], items,
1051 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1052
1053 }
1054 3 else if (fp_cmd->code == 0x09)
1055 {
1056 3 memset (data->enrolled_info->actived, 0, FOCALTECH_MOC_MAX_FINGERS);
1057 3 memset (&data->enrolled_info->items[0], 0,
1058 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1059 }
1060
1061 6 fpi_ssm_next_state (self->task_ssm);
1062 }
1063 }
1064
1065 struct UidList
1066 {
1067 uint8_t actived[FOCALTECH_MOC_MAX_FINGERS];
1068 struct UserId uid[FOCALTECH_MOC_MAX_FINGERS];
1069 };
1070
1071 static int
1072 7 focaltech_moc_get_enrolled_info_item (FpiDeviceFocaltechMoc *self,
1073 uint8_t *uid,
1074 struct EnrolledInfoItem **pitem, int *index)
1075 {
1076 7 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1077 7 int ret = -1;
1078 7 int i;
1079
1080
2/2
✓ Branch 7 → 4 taken 43 times.
✓ Branch 7 → 8 taken 4 times.
54 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1081 {
1082 43 struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
1083
1084
2/2
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 6 taken 40 times.
43 if (memcmp (item->uid, uid, FOCALTECH_MOC_UID_PREFIX_LENGTH) == 0)
1085 {
1086 3 data->enrolled_info->actived[i] = 1;
1087 3 *pitem = item;
1088 3 *index = i;
1089 3 ret = 0;
1090 3 break;
1091 }
1092 }
1093
1094 7 return ret;
1095 }
1096
1097 static void
1098 6 focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
1099 uint8_t *buffer_in,
1100 gsize length_in,
1101 GError *error)
1102 {
1103 6 FpCmd *fp_cmd = NULL;
1104 6 struct UidList *uid_list = NULL;
1105
1106
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 6 times.
6 if (error)
1107 {
1108 fpi_ssm_mark_failed (self->task_ssm, error);
1109 return;
1110 }
1111
1112
1/2
✓ Branch 6 → 7 taken 6 times.
✗ Branch 6 → 38 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1113 sizeof (FpCmd) + sizeof (uint8_t),
1114 "get enrolled list"))
1115 return;
1116
1117 6 fp_cmd = (FpCmd *) buffer_in;
1118 6 uid_list = (struct UidList *) (fp_cmd + 1);
1119
1120
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 6 times.
6 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1121 {
1122 fpi_ssm_mark_failed (self->task_ssm,
1123 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1124 "Can't get response!!"));
1125 }
1126 else
1127 {
1128 6 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1129
1130
1/2
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 37 not taken.
6 if (fp_cmd->code == 0x04)
1131 {
1132
1/2
✓ Branch 13 → 32 taken 6 times.
✗ Branch 13 → 38 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1133 sizeof (FpCmd) +
1134 sizeof (struct UidList) +
1135 sizeof (uint8_t),
1136 "get enrolled list"))
1137 return;
1138
2/2
✓ Branch 32 → 14 taken 60 times.
✓ Branch 32 → 36 taken 6 times.
66 for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1139 {
1140
2/2
✓ Branch 14 → 15 taken 3 times.
✓ Branch 14 → 31 taken 57 times.
60 if (uid_list->actived[i] != 0)
1141 {
1142 3 struct UserId *user_id = &uid_list->uid[i];
1143 3 FpPrint *print = fp_print_new (FP_DEVICE (self));
1144 3 struct EnrolledInfoItem *item = NULL;
1145 3 int index;
1146
1147 3 fp_info ("focaltechmoc add slot: %zu", i);
1148
1149 3 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
1150
1151
2/2
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 28 taken 1 time.
3 if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
1152 {
1153 2 g_autofree gchar *userid_safe = NULL;
1154 2 const gchar *username;
1155
1156 2 userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
1157 2 fp_dbg ("%s", userid_safe);
1158 2 fpi_print_fill_from_user_id (print, userid_safe);
1159 2 memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
1160 2 data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
1161 2 username = fp_print_get_username (print);
1162
1163
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 2 times.
2 if (username != NULL)
1164 g_strlcpy (data->enrolled_info->user_des[index].username,
1165 username,
1166 sizeof (data->enrolled_info->user_des[index].username));
1167 }
1168
1169 3 g_ptr_array_add (data->list_result, g_object_ref_sink (print));
1170 }
1171 }
1172
1173
2/2
✓ Branch 36 → 33 taken 60 times.
✓ Branch 36 → 37 taken 6 times.
66 for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1174 {
1175 60 struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
1176
1177
2/2
✓ Branch 33 → 34 taken 58 times.
✓ Branch 33 → 35 taken 2 times.
60 if (data->enrolled_info->actived[i] == 0)
1178 58 memset (item, 0, sizeof (struct EnrolledInfoItem));
1179 }
1180 }
1181
1182 6 fpi_ssm_next_state (self->task_ssm);
1183 }
1184 }
1185
1186 static void
1187 301 focaltech_moc_enroll_wait_finger_cb (FpiDeviceFocaltechMoc *self,
1188 uint8_t *buffer_in,
1189 gsize length_in,
1190 GError *error)
1191 {
1192 301 FpCmd *fp_cmd = NULL;
1193 301 uint8_t *finger_status = NULL;
1194
1195
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 301 times.
301 if (error)
1196 {
1197 fpi_ssm_mark_failed (self->task_ssm, error);
1198 return;
1199 }
1200
1201 301 fp_cmd = (FpCmd *) buffer_in;
1202 301 finger_status = (uint8_t *) (fp_cmd + 1);
1203
1204
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 301 times.
301 if (fp_cmd->code != 0x04)
1205 {
1206 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER_DELAY);
1207 }
1208 else
1209 {
1210
1211
2/2
✓ Branch 7 → 8 taken 32 times.
✓ Branch 7 → 9 taken 269 times.
301 if (*finger_status == 0x01)
1212 32 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_ENROLL_CAPTURE);
1213 else
1214 269 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER_DELAY);
1215 }
1216 }
1217
1218 static void
1219 269 focaltech_moc_enroll_wait_finger_delay (FpDevice *device,
1220 void *user_data
1221 )
1222 {
1223 269 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1224
1225 269 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
1226 269 }
1227
1228 static void
1229 2 focaltech_moc_start_enroll_cb (FpiDeviceFocaltechMoc *self,
1230 uint8_t *buffer_in,
1231 gsize length_in,
1232 GError *error)
1233 {
1234 2 FpCmd *fp_cmd = NULL;
1235 2 struct UserId *user_id = NULL;
1236 2 FpPrint *print = NULL;
1237 2 struct EnrolledInfoItem *item = NULL;
1238 2 int index;
1239
1240
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 if (error)
1241 {
1242 fpi_ssm_mark_failed (self->task_ssm, error);
1243 return;
1244 }
1245
1246 2 fp_cmd = (FpCmd *) buffer_in;
1247 2 user_id = (struct UserId *) (fp_cmd + 1);
1248
1249
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 2 times.
2 if (fp_cmd->code != 0x04)
1250 {
1251 if (fp_cmd->code == 0x05)
1252 {
1253 fpi_ssm_mark_failed (self->task_ssm,
1254 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_FULL,
1255 "device data full!!"));
1256 }
1257 else
1258 {
1259 fpi_ssm_mark_failed (self->task_ssm,
1260 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1261 "Can't get response!!"));
1262 }
1263 return;
1264 }
1265
1266
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 14 taken 2 times.
2 if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
1267 {
1268 fpi_ssm_mark_failed (self->task_ssm,
1269 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1270 "uid error!!"));
1271 }
1272 else
1273 {
1274 2 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1275 2 g_autofree gchar *userid_safe = NULL;
1276 2 gsize userid_len;
1277 2 uint8_t found = 0;
1278 2 int i;
1279 2 struct EnrolledInfoItem *free_item = NULL;
1280
1281
1/2
✓ Branch 18 → 16 taken 2 times.
✗ Branch 18 → 19 not taken.
4 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1282 {
1283 2 item = &data->enrolled_info->items[i];
1284
1285
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 21 taken 2 times.
2 if (data->enrolled_info->actived[i] == 0)
1286 {
1287 2 found = 1;
1288 2 free_item = item;
1289 2 break;
1290 }
1291 }
1292
1293 2 if (found == 0)
1294 {
1295 fpi_ssm_mark_failed (self->task_ssm,
1296 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1297 "no uid slot!!"));
1298 }
1299 else
1300 {
1301 2 guint64 quirk = fpi_device_get_driver_data (FP_DEVICE (self));
1302
1303 2 fpi_device_get_enroll_data (FP_DEVICE (self), &print);
1304 2 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
1305
1306
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 28 taken 1 time.
2 if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
1307 {
1308 1 fp_info ("Applying SINGLE_SLOT quirk: Forcing static User ID");
1309 1 userid_safe = g_strdup (FOCALTECH_MOC_STATIC_USER_ID);
1310 }
1311 else
1312 {
1313 1 userid_safe = fpi_print_generate_user_id (print);
1314 }
1315
1316 2 userid_len = strlen (userid_safe);
1317 2 userid_len = MIN (FOCALTECH_MOC_USER_ID_LENGTH, userid_len);
1318 2 fp_info ("focaltechmoc user id: %s", userid_safe);
1319 2 memcpy (free_item->uid, user_id->uid, FOCALTECH_MOC_UID_PREFIX_LENGTH);
1320 2 memcpy (free_item->user_id, userid_safe, userid_len);
1321 2 fpi_ssm_next_state (self->task_ssm);
1322 }
1323 }
1324 }
1325
1326 static void
1327 32 focaltech_moc_enroll_capture_cb (FpiDeviceFocaltechMoc *self,
1328 uint8_t *buffer_in,
1329 gsize length_in,
1330 GError *error)
1331 {
1332 32 FpCmd *fp_cmd = NULL;
1333 32 struct CaptureResult *capture_result = NULL;
1334
1335
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 32 times.
32 if (error)
1336 {
1337 fpi_ssm_mark_failed (self->task_ssm, error);
1338 return;
1339 }
1340
1341 32 fp_cmd = (FpCmd *) buffer_in;
1342 32 capture_result = (struct CaptureResult *) (fp_cmd + 1);
1343
1344
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 32 times.
32 if (fp_cmd->code != 0x04)
1345 {
1346 fpi_ssm_mark_failed (self->task_ssm,
1347 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1348 "Can't get response!!"));
1349 }
1350 else
1351 {
1352
2/2
✓ Branch 8 → 9 taken 28 times.
✓ Branch 8 → 11 taken 4 times.
32 if (capture_result->error == ERROR_NONE)
1353 {
1354 28 self->num_frames += 1;
1355 28 enroll_status_report (self, ENROLL_RSP_ENROLL_REPORT, self->num_frames, NULL);
1356 28 fp_info ("focaltechmoc remain: %d", capture_result->remain);
1357 }
1358 else
1359 {
1360 4 enroll_status_report (self, ENROLL_RSP_RETRY, self->num_frames, NULL);
1361 }
1362
1363
2/2
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 30 times.
32 if (self->num_frames == fp_device_get_nr_enroll_stages (FP_DEVICE (self)))
1364 2 fpi_ssm_next_state (self->task_ssm);
1365 else
1366 30 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
1367 }
1368 }
1369
1370 static void
1371 3 focaltech_moc_set_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
1372 uint8_t *buffer_in,
1373 gsize length_in,
1374 GError *error)
1375 {
1376 3 FpCmd *fp_cmd = NULL;
1377
1378
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 3 times.
3 if (error)
1379 {
1380 fpi_ssm_mark_failed (self->task_ssm, error);
1381 return;
1382 }
1383
1384
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 12 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1385 sizeof (FpCmd) + sizeof (uint8_t),
1386 "set enrolled info"))
1387 return;
1388
1389 3 fp_cmd = (FpCmd *) buffer_in;
1390
1391
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 11 taken 3 times.
3 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1392 {
1393 fpi_ssm_mark_failed (self->task_ssm,
1394 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1395 "Can't get response!!"));
1396 return;
1397 }
1398
1399 3 fpi_ssm_next_state (self->task_ssm);
1400 }
1401
1402 static void
1403 2 focaltech_moc_commit_cb (FpiDeviceFocaltechMoc *self,
1404 uint8_t *buffer_in,
1405 gsize length_in,
1406 GError *error)
1407 {
1408 2 FpCmd *fp_cmd = NULL;
1409
1410
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 2 times.
2 if (error)
1411 {
1412 fpi_ssm_mark_failed (self->task_ssm, error);
1413 return;
1414 }
1415
1416
1/2
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 13 not taken.
2 if (!focaltech_moc_require_response_len (self, length_in,
1417 sizeof (FpCmd) + sizeof (uint8_t),
1418 "commit"))
1419 return;
1420
1421 2 fp_cmd = (FpCmd *) buffer_in;
1422
1423
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 2 times.
2 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1424 {
1425 fpi_ssm_mark_failed (self->task_ssm,
1426 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1427 "Can't get response!!"));
1428 }
1429 else
1430 {
1431 2 fp_info ("focaltech_moc_commit_cb success");
1432 2 enroll_status_report (self, ENROLL_RSP_ENROLL_OK, self->num_frames, NULL);
1433 2 fpi_ssm_next_state (self->task_ssm);
1434 }
1435 }
1436
1437 static void
1438 614 focaltech_enroll_run_state (FpiSsm *ssm, FpDevice *device)
1439 {
1440 614 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1441 614 guint8 *cmd_buf = NULL;
1442 614 uint16_t cmd_len = 0;
1443 614 uint16_t resp_len = 0;
1444
1445
9/10
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 7 taken 2 times.
✓ Branch 3 → 10 taken 2 times.
✓ Branch 3 → 13 taken 2 times.
✓ Branch 3 → 16 taken 301 times.
✓ Branch 3 → 19 taken 269 times.
✓ Branch 3 → 21 taken 32 times.
✓ Branch 3 → 24 taken 2 times.
✓ Branch 3 → 29 taken 2 times.
✗ Branch 3 → 49 not taken.
614 switch (fpi_ssm_get_cur_state (ssm))
1446 {
1447 2 case MOC_ENROLL_GET_ENROLLED_INFO:
1448 {
1449 2 uint8_t data = 0x00;
1450 2 cmd_len = sizeof (uint8_t);
1451 2 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1452 2 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1453 2 focaltech_moc_get_cmd (device, cmd_buf,
1454 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1455 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1456 1,
1457 focaltech_moc_get_enrolled_info_cb);
1458 2 break;
1459 }
1460
1461 2 case MOC_ENROLL_GET_ENROLLED_LIST:
1462 {
1463 2 cmd_len = 0;
1464 2 resp_len = sizeof (struct UidList);
1465 2 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1466 2 focaltech_moc_get_cmd (device, cmd_buf,
1467 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1468 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1469 1,
1470 focaltech_moc_get_enrolled_list_cb);
1471 2 break;
1472 }
1473
1474 2 case MOC_ENROLL_RELEASE_FINGER:
1475 {
1476 2 uint8_t d1 = 0x78;
1477 2 cmd_len = sizeof (d1);
1478 2 resp_len = 0;
1479 2 cmd_buf = focaltech_moc_compose_cmd (0x82, &d1, cmd_len);
1480 2 focaltech_moc_get_cmd (device, cmd_buf,
1481 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1482 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1483 1,
1484 focaltech_moc_release_finger);
1485 2 break;
1486 }
1487
1488 2 case MOC_ENROLL_START_ENROLL:
1489 2 cmd_len = 0;
1490 2 resp_len = sizeof (struct UserId);
1491 2 cmd_buf = focaltech_moc_compose_cmd (0xa9, NULL, cmd_len);
1492 2 focaltech_moc_get_cmd (device, cmd_buf,
1493 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1494 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1495 1,
1496 focaltech_moc_start_enroll_cb);
1497 2 break;
1498
1499
1500 301 case MOC_ENROLL_WAIT_FINGER:
1501 {
1502 301 uint8_t data = 0x02;
1503 301 cmd_len = sizeof (uint8_t);
1504 301 resp_len = sizeof (uint8_t);
1505 301 cmd_buf = focaltech_moc_compose_cmd (0x80, &data, cmd_len);
1506 301 focaltech_moc_get_cmd (device, cmd_buf,
1507 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1508 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1509 1,
1510 focaltech_moc_enroll_wait_finger_cb);
1511 301 break;
1512 }
1513
1514 269 case MOC_ENROLL_WAIT_FINGER_DELAY:
1515 269 fpi_device_add_timeout (device, 50,
1516 focaltech_moc_enroll_wait_finger_delay,
1517 NULL, NULL);
1518 269 break;
1519
1520 32 case MOC_ENROLL_ENROLL_CAPTURE:
1521 32 cmd_len = 0;
1522 32 resp_len = sizeof (struct CaptureResult);
1523 32 cmd_buf = focaltech_moc_compose_cmd (0xa6, NULL, cmd_len);
1524 32 focaltech_moc_get_cmd (device, cmd_buf,
1525 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1526 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1527 1,
1528 focaltech_moc_enroll_capture_cb);
1529 32 break;
1530
1531 2 case MOC_ENROLL_SET_ENROLLED_INFO:
1532 {
1533 2 g_autofree struct EnrolledInfoSetData *set_data = NULL;
1534 2 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1535
1536 2 cmd_len = sizeof (struct EnrolledInfoSetData);
1537 2 resp_len = 0;
1538 2 set_data = (struct EnrolledInfoSetData *) g_malloc0 (cmd_len);
1539 2 set_data->data = 0x01;
1540 2 memcpy (&set_data->items[0], &data->enrolled_info->items[0],
1541 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1542 2 cmd_buf = focaltech_moc_compose_cmd (0xaf, (const uint8_t *) set_data, cmd_len);
1543 2 focaltech_moc_get_cmd (device, cmd_buf,
1544 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1545 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1546 1,
1547 focaltech_moc_set_enrolled_info_cb);
1548 2 break;
1549 }
1550
1551 2 case MOC_ENROLL_COMMIT_RESULT:
1552 {
1553 2 FpPrint *print = NULL;
1554 2 g_autoptr(GVariant) data = NULL;
1555
1/4
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
✓ Branch 46 → 47 taken 2 times.
✗ Branch 46 → 48 not taken.
2 g_autoptr(GVariant) user_id_var = NULL;
1556 2 const guint8 *user_id;
1557 2 gsize user_id_len = 0;
1558
1559 2 fpi_device_get_enroll_data (FP_DEVICE (self), &print);
1560 2 g_object_get (print, "fpi-data", &data, NULL);
1561
1562
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 40 taken 2 times.
2 if (!g_variant_check_format_string (data, "(@ay)", FALSE))
1563 {
1564 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
1565 return;
1566 }
1567
1568 2 g_variant_get (data,
1569 "(@ay)",
1570 &user_id_var);
1571 2 user_id = g_variant_get_fixed_array (user_id_var, &user_id_len, 1);
1572
1573 2 cmd_len = user_id_len;
1574 2 resp_len = 0;
1575 2 cmd_buf = focaltech_moc_compose_cmd (0xa3, user_id, cmd_len);
1576 2 focaltech_moc_get_cmd (device, cmd_buf,
1577 2 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1578 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1579 1,
1580 focaltech_moc_commit_cb);
1581
1/2
✓ Branch 44 → 45 taken 2 times.
✗ Branch 44 → 46 not taken.
2 break;
1582 }
1583 }
1584 }
1585
1586 static void
1587 2 focaltech_moc_enroll (FpDevice *device)
1588 {
1589 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1590 2 FpActionData *data = g_new0 (FpActionData, 1);
1591
1592 2 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
1593 2 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
1594
1595 2 self->task_ssm = fpi_ssm_new (FP_DEVICE (self),
1596 focaltech_enroll_run_state,
1597 MOC_ENROLL_NUM_STATES);
1598 2 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
1599 2 fpi_ssm_start (self->task_ssm, task_ssm_done);
1600 2 }
1601
1602 static void
1603 1 focaltech_moc_delete_cb (FpiDeviceFocaltechMoc *self,
1604 uint8_t *buffer_in,
1605 gsize length_in,
1606 GError *error)
1607 {
1608 1 FpCmd *fp_cmd = NULL;
1609
1610
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 1 time.
1 if (error)
1611 {
1612 fpi_ssm_mark_failed (self->task_ssm, error);
1613 return;
1614 }
1615
1616
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 16 not taken.
1 if (!focaltech_moc_require_response_len (self, length_in,
1617 sizeof (FpCmd) + sizeof (uint8_t),
1618 "delete"))
1619 return;
1620
1621 1 fp_cmd = (FpCmd *) buffer_in;
1622
1623
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 1 time.
1 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1624 {
1625 fpi_ssm_mark_failed (self->task_ssm,
1626 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1627 "Can't get response!!"));
1628 }
1629 else
1630 {
1631 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1632 1 int ssm_state;
1633
1634
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 14 not taken.
1 if (self->delete_slot != -1)
1635 {
1636 1 fp_dbg ("delete slot %d", self->delete_slot);
1637 1 data->enrolled_info->actived[self->delete_slot] = 0;
1638 1 memset (&data->enrolled_info->items[self->delete_slot], 0, sizeof (struct EnrolledInfoItem));
1639 1 memset (&data->enrolled_info->user_id[self->delete_slot], 0, sizeof (struct UserId));
1640 1 memset (&data->enrolled_info->user_des[self->delete_slot], 0, sizeof (struct UserDes));
1641 }
1642
1643 1 ssm_state = fpi_ssm_get_cur_state (self->task_ssm);
1644 1 fpi_ssm_jump_to_state (self->task_ssm, ssm_state);
1645 }
1646 }
1647
1648 enum delete_states {
1649 MOC_DELETE_GET_ENROLLED_INFO,
1650 MOC_DELETE_GET_ENROLLED_LIST,
1651 MOC_DELETE_SET_ENROLLED_INFO,
1652 MOC_DELETE_BY_UID,
1653 MOC_DELETE_BY_USER_INFO,
1654 MOC_DELETE_NUM_STATES,
1655 };
1656
1657 static void
1658 6 focaltech_delete_run_state (FpiSsm *ssm, FpDevice *device)
1659 {
1660 6 guint8 *cmd_buf = NULL;
1661 6 uint16_t cmd_len = 0;
1662 6 uint16_t resp_len = 0;
1663
1664
5/6
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 3 → 10 taken 1 time.
✓ Branch 3 → 15 taken 2 times.
✓ Branch 3 → 40 taken 1 time.
✗ Branch 3 → 60 not taken.
6 switch (fpi_ssm_get_cur_state (ssm))
1665 {
1666 1 case MOC_DELETE_GET_ENROLLED_INFO:
1667 {
1668 1 uint8_t data = 0x00;
1669 1 cmd_len = sizeof (uint8_t);
1670 1 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1671 1 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1672 1 focaltech_moc_get_cmd (device, cmd_buf,
1673 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1674 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1675 1,
1676 focaltech_moc_get_enrolled_info_cb);
1677 1 break;
1678 }
1679
1680 1 case MOC_DELETE_GET_ENROLLED_LIST:
1681 {
1682 1 cmd_len = 0;
1683 1 resp_len = sizeof (struct UidList) + sizeof (struct UserId) * FOCALTECH_MOC_MAX_FINGERS;
1684 1 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1685 1 focaltech_moc_get_cmd (device, cmd_buf,
1686 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1687 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1688 1,
1689 focaltech_moc_get_enrolled_list_cb);
1690 1 break;
1691 }
1692
1693 case MOC_DELETE_SET_ENROLLED_INFO:
1694 {
1695 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1696 1 g_autofree struct EnrolledInfoSetData *set_data = NULL;
1697 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1698
1699 1 cmd_len = sizeof (struct EnrolledInfoSetData);
1700 1 resp_len = 0;
1701 1 set_data = (struct EnrolledInfoSetData *) g_malloc0 (cmd_len);
1702 1 set_data->data = 0x01;
1703 1 memcpy (&set_data->items[0], &data->enrolled_info->items[0], FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1704 1 cmd_buf = focaltech_moc_compose_cmd (0xaf, (const uint8_t *) set_data, cmd_len);
1705 1 focaltech_moc_get_cmd (device, cmd_buf,
1706 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1707 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1708 1,
1709 focaltech_moc_set_enrolled_info_cb);
1710 1 break;
1711 }
1712
1713 case MOC_DELETE_BY_UID:
1714 {
1715 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1716 2 FpPrint *print = NULL;
1717 2 g_autoptr(GVariant) data = NULL;
1718
1/4
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 25 not taken.
✓ Branch 37 → 38 taken 2 times.
✗ Branch 37 → 39 not taken.
2 g_autoptr(GVariant) user_id_var = NULL;
1719 2 const guint8 *user_id;
1720 2 gsize user_id_len = 0;
1721 2 struct EnrolledInfoItem *item = NULL;
1722 2 int index;
1723
1724 2 self->delete_slot = -1;
1725 2 fpi_device_get_delete_data (device, &print);
1726 2 g_object_get (print, "fpi-data", &data, NULL);
1727
1728
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 26 taken 2 times.
2 if (!g_variant_check_format_string (data, "(@ay)", FALSE))
1729 {
1730 fpi_device_delete_complete (device,
1731 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
1732 return;
1733 }
1734
1735 2 g_variant_get (data, "(@ay)", &user_id_var);
1736 2 user_id = g_variant_get_fixed_array (user_id_var, &user_id_len, 1);
1737
1738
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 1 time.
2 if (focaltech_moc_get_enrolled_info_item (self, (uint8_t *) user_id, &item, &index) == 0)
1739 1 self->delete_slot = index;
1740
1741
2/2
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 34 taken 1 time.
2 if (self->delete_slot != -1)
1742 {
1743 1 cmd_len = sizeof (struct UserId);
1744 1 resp_len = 0;
1745 1 cmd_buf = focaltech_moc_compose_cmd (0xa8, user_id, cmd_len);
1746 1 focaltech_moc_get_cmd (device, cmd_buf,
1747 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1748 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1749 1,
1750 focaltech_moc_delete_cb);
1751 }
1752 else
1753 {
1754 1 fpi_ssm_next_state (self->task_ssm);
1755 }
1756
1757
1/2
✓ Branch 35 → 36 taken 2 times.
✗ Branch 35 → 37 not taken.
2 break;
1758 }
1759
1760 case MOC_DELETE_BY_USER_INFO:
1761 {
1762 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1763 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1764 1 FpPrint *print = NULL;
1765 1 const guint8 *user_id;
1766 1 const gchar *username;
1767 1 uint8_t finger;
1768 1 int i;
1769
1770 1 self->delete_slot = -1;
1771 1 fpi_device_get_delete_data (device, &print);
1772 1 username = fp_print_get_username (print);
1773 1 finger = fp_print_get_finger (print);
1774
1775
2/2
✓ Branch 53 → 45 taken 10 times.
✓ Branch 53 → 54 taken 1 time.
11 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1776 {
1777 10 struct UserDes *user_des = &data->enrolled_info->user_des[i];
1778
1779
1/2
✓ Branch 45 → 46 taken 10 times.
✗ Branch 45 → 47 not taken.
10 if (username == NULL)
1780 10 continue;
1781
1782 if (strncmp (user_des->username, username, FOCALTECH_MOC_USER_ID_LENGTH) != 0)
1783 continue;
1784
1785 if (finger != user_des->finger)
1786 continue;
1787
1788 self->delete_slot = i;
1789 }
1790
1791
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 57 taken 1 time.
1 if (self->delete_slot != -1)
1792 {
1793 user_id = (const guint8 *) &data->enrolled_info->user_id[self->delete_slot].uid[0];
1794 cmd_len = sizeof (struct UserId);
1795 resp_len = 0;
1796 cmd_buf = focaltech_moc_compose_cmd (0xa8, user_id, cmd_len);
1797 focaltech_moc_get_cmd (device, cmd_buf,
1798 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1799 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1800 1,
1801 focaltech_moc_delete_cb);
1802 }
1803 else
1804 {
1805 1 fpi_device_delete_complete (FP_DEVICE (self), NULL);
1806 1 fpi_ssm_next_state (self->task_ssm);
1807 }
1808
1809 1 break;
1810 }
1811 }
1812 }
1813
1814 static void
1815 1 focaltech_moc_delete_print (FpDevice *device)
1816 {
1817 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1818 1 FpActionData *data = NULL;
1819
1820 1 data = g_new0 (FpActionData, 1);
1821 1 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
1822 1 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
1823
1824 1 self->task_ssm = fpi_ssm_new (device,
1825 focaltech_delete_run_state,
1826 MOC_DELETE_NUM_STATES);
1827 1 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
1828 1 fpi_ssm_start (self->task_ssm, task_ssm_done);
1829 1 }
1830
1831 enum moc_clear_storage_states {
1832 MOC_CLEAR_STORAGE_SEND,
1833 MOC_CLEAR_STORAGE_NUM_STATES,
1834 };
1835
1836 static void
1837 3 focaltech_moc_clear_storage_cb (FpiDeviceFocaltechMoc *self,
1838 uint8_t *buffer_in,
1839 gsize length_in,
1840 GError *error)
1841 {
1842 3 FpCmd *fp_cmd = NULL;
1843
1844
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 3 times.
3 if (error)
1845 {
1846 fp_warn ("Mass erase command completed with warning: %s", error->message);
1847 fpi_ssm_mark_failed (self->task_ssm, error);
1848 return;
1849 }
1850
1851
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 10 taken 3 times.
3 if (length_in == 0)
1852 {
1853 fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
1854 fpi_ssm_next_state (self->task_ssm);
1855 return;
1856 }
1857
1858
1/2
✓ Branch 11 → 12 taken 3 times.
✗ Branch 11 → 18 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1859 sizeof (FpCmd) + sizeof (uint8_t),
1860 "clear storage"))
1861 return;
1862
1863 3 fp_cmd = (FpCmd *) buffer_in;
1864
1865
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 16 taken 3 times.
3 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1866 {
1867 fpi_ssm_mark_failed (self->task_ssm,
1868 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1869 "Clear storage failed: unexpected response code 0x%02x",
1870 fp_cmd->code));
1871 return;
1872 }
1873
1874 3 fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
1875 3 fpi_ssm_next_state (self->task_ssm);
1876 }
1877
1878 static void
1879 3 focaltech_clear_storage_run_state (FpiSsm *ssm, FpDevice *device)
1880 {
1881 3 guint64 quirk = fpi_device_get_driver_data (device);
1882 3 guint8 *cmd_buf = NULL;
1883 3 uint16_t cmd_len = 0;
1884 3 uint16_t resp_len = 0;
1885
1886
1/2
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 8 not taken.
3 switch (fpi_ssm_get_cur_state (ssm))
1887 {
1888 3 case MOC_CLEAR_STORAGE_SEND:
1889 3 resp_len = quirk == FOCALTECH_QUIRK_SINGLE_SLOT ? 0 : sizeof (uint8_t);
1890 3 cmd_buf = focaltech_moc_compose_cmd (0xac, NULL, cmd_len);
1891
1892 3 focaltech_moc_get_cmd (device, cmd_buf,
1893 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1894 3 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1895 FALSE,
1896 focaltech_moc_clear_storage_cb);
1897 3 break;
1898 }
1899 3 }
1900
1901 static void
1902 3 focaltech_moc_clear_storage (FpDevice *device)
1903 {
1904 3 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1905
1906 3 self->task_ssm = fpi_ssm_new (device,
1907 focaltech_clear_storage_run_state,
1908 MOC_CLEAR_STORAGE_NUM_STATES);
1909 3 fpi_ssm_start (self->task_ssm, task_ssm_done);
1910 3 }
1911
1912 enum moc_list_states {
1913 MOC_LIST_GET_ENROLLED_INFO,
1914 MOC_LIST_GET_ENROLLED_LIST,
1915 MOC_LIST_REPORT,
1916 MOC_LIST_NUM_STATES,
1917 };
1918
1919 static void
1920 9 focaltech_list_run_state (FpiSsm *ssm, FpDevice *device)
1921 {
1922 9 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1923 9 guint8 *cmd_buf = NULL;
1924 9 uint16_t cmd_len = 0;
1925 9 uint16_t resp_len = 0;
1926
1927
3/4
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 3 times.
✓ Branch 3 → 10 taken 3 times.
✗ Branch 3 → 14 not taken.
9 switch (fpi_ssm_get_cur_state (ssm))
1928 {
1929 3 case MOC_LIST_GET_ENROLLED_INFO:
1930 {
1931 3 uint8_t data = 0x00;
1932 3 cmd_len = sizeof (uint8_t);
1933 3 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1934 3 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1935 3 focaltech_moc_get_cmd (device, cmd_buf,
1936 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1937 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1938 1,
1939 focaltech_moc_get_enrolled_info_cb);
1940 3 break;
1941 }
1942
1943 3 case MOC_LIST_GET_ENROLLED_LIST:
1944 {
1945 3 cmd_len = 0;
1946 3 resp_len = sizeof (struct UidList) + sizeof (struct UserId) * FOCALTECH_MOC_MAX_FINGERS;
1947 3 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1948 3 focaltech_moc_get_cmd (device, cmd_buf,
1949 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1950 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1951 1,
1952 focaltech_moc_get_enrolled_list_cb);
1953 3 break;
1954 }
1955
1956 3 case MOC_LIST_REPORT:
1957 {
1958 3 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1959 3 fpi_device_list_complete (FP_DEVICE (self), g_steal_pointer (&data->list_result), NULL);
1960 3 fpi_ssm_next_state (self->task_ssm);
1961 3 break;
1962 }
1963 }
1964 9 }
1965
1966 static void
1967 3 focaltech_moc_list (FpDevice *device)
1968 {
1969 3 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1970 3 FpActionData *data = g_new0 (FpActionData, 1);
1971
1972 3 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
1973 3 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
1974 3 self->task_ssm = fpi_ssm_new (device,
1975 focaltech_list_run_state,
1976 MOC_LIST_NUM_STATES);
1977 3 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
1978 3 fpi_ssm_start (self->task_ssm, task_ssm_done);
1979 3 }
1980
1981 static void
1982 2 fpi_device_focaltech_moc_init (FpiDeviceFocaltechMoc *self)
1983 {
1984 2 G_DEBUG_HERE ();
1985 2 }
1986
1987 static void
1988 2 focaltech_moc_probe (FpDevice *device)
1989 {
1990 2 guint64 quirk = fpi_device_get_driver_data (device);
1991
1992
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
2 if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
1993 1 fpi_device_update_features (device, FP_DEVICE_FEATURE_STORAGE_DELETE, 0);
1994
1995 2 fpi_device_probe_complete (device, NULL, NULL, NULL);
1996 2 }
1997
1998 static void
1999 127 fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
2000 {
2001 127 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
2002
2003 127 dev_class->id = FP_COMPONENT;
2004 127 dev_class->full_name = FOCALTECH_MOC_DRIVER_FULLNAME;
2005
2006 127 dev_class->type = FP_DEVICE_TYPE_USB;
2007 127 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
2008 127 dev_class->id_table = id_table;
2009 127 dev_class->nr_enroll_stages = FOCALTECH_MOC_MAX_FINGERS;
2010 127 dev_class->temp_hot_seconds = -1;
2011
2012 127 dev_class->probe = focaltech_moc_probe;
2013 127 dev_class->open = focaltech_moc_open;
2014 127 dev_class->close = focaltech_moc_close;
2015 127 dev_class->enroll = focaltech_moc_enroll;
2016 127 dev_class->identify = focaltech_moc_identify;
2017 127 dev_class->delete = focaltech_moc_delete_print;
2018 127 dev_class->clear_storage = focaltech_moc_clear_storage;
2019 127 dev_class->list = focaltech_moc_list;
2020
2021 127 fpi_device_class_auto_initialize_features (dev_class);
2022 127 }
2023