GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.5% 754 / 0 / 862
Functions: 100.0% 53 / 0 / 53
Branches: 60.1% 172 / 0 / 286

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 125 times.
fpi_device_focaltech_moc_get_type:
✓ Branch 2 → 3 taken 125 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 125 times.
✗ Branch 4 → 7 not taken.
399 G_DEFINE_TYPE (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 if (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_VERIFY)
811 {
812 fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
813 fpi_device_verify_complete (FP_DEVICE (self), NULL);
814 }
815 else
816 {
817 fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
818 fpi_device_identify_complete (FP_DEVICE (self), NULL);
819 }
820
821 fpi_ssm_mark_failed (self->task_ssm, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
822 }
823 }
824 }
825
826 static void
827 4 identify_status_report (FpiDeviceFocaltechMoc *self, FpPrint *print, GError *error)
828 {
829 4 FpDevice *device = FP_DEVICE (self);
830
831
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 9 taken 4 times.
4 if (print == NULL)
832 {
833 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
834 {
835 fpi_device_identify_report (device, NULL, NULL, NULL);
836 fpi_device_identify_complete (device, NULL);
837 }
838 else
839 {
840 fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
841 fpi_device_verify_complete (device, NULL);
842 }
843 }
844 else
845 {
846
2/2
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 18 taken 2 times.
4 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
847 {
848 2 GPtrArray *prints;
849 2 gboolean found = FALSE;
850 2 guint index;
851
852 2 fpi_device_get_identify_data (device, &prints);
853 2 found = g_ptr_array_find_with_equal_func (prints,
854 print,
855 (GEqualFunc) fp_print_equal,
856 &index);
857
858
1/2
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 15 not taken.
2 if (found)
859 2 fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
860 else
861 fpi_device_identify_report (device, NULL, print, NULL);
862
863 2 fpi_device_identify_complete (device, NULL);
864 }
865 else
866 {
867 2 FpPrint *verify_print = NULL;
868 2 fpi_device_get_verify_data (device, &verify_print);
869
870
1/2
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 22 not taken.
2 if (fp_print_equal (verify_print, print))
871 2 fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
872 else
873 fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
874
875 2 fpi_device_verify_complete (device, NULL);
876 }
877 }
878 4 }
879
880 static void
881 4 focaltech_moc_identify_match_cb (FpiDeviceFocaltechMoc *self,
882 uint8_t *buffer_in,
883 gsize length_in,
884 GError *error)
885 {
886 4 FpCmd *fp_cmd = NULL;
887 4 struct UserId *user_id = NULL;
888 4 FpPrint *print = NULL;
889
890 4 fp_cmd = (FpCmd *) buffer_in;
891 4 user_id = (struct UserId *) (fp_cmd + 1);
892
893
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 4 times.
4 if (error)
894 {
895 fpi_ssm_mark_failed (self->task_ssm, error);
896 return;
897 }
898
899
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 8 not taken.
4 if (fp_cmd->code == 0x04)
900 {
901 4 print = fp_print_new (FP_DEVICE (self));
902 4 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
903 }
904
905 4 identify_status_report (self, print, error);
906
907 4 fpi_ssm_next_state (self->task_ssm);
908 }
909
910 static void
911 220 focaltech_identify_run_state (FpiSsm *ssm, FpDevice *device)
912 {
913 220 guint8 *cmd_buf = NULL;
914 220 uint16_t cmd_len = 0;
915 220 uint16_t resp_len = 0;
916
917
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))
918 {
919 4 case MOC_IDENTIFY_RELEASE_FINGER:
920 {
921 4 uint8_t d1 = 0x78;
922 4 cmd_len = sizeof (d1);
923 4 resp_len = 0;
924 4 cmd_buf = focaltech_moc_compose_cmd (0x82, &d1, cmd_len);
925 4 focaltech_moc_get_cmd (device, cmd_buf,
926 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
927 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
928 1,
929 focaltech_moc_release_finger);
930 4 break;
931 }
932
933 106 case MOC_IDENTIFY_WAIT_FINGER:
934 {
935 106 uint8_t data = 0x02;
936 106 cmd_len = sizeof (uint8_t);
937 106 resp_len = sizeof (uint8_t);
938 106 cmd_buf = focaltech_moc_compose_cmd (0x80, &data, cmd_len);
939 106 focaltech_moc_get_cmd (device, cmd_buf,
940 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
941 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
942 1,
943 focaltech_moc_identify_wait_finger_cb);
944 106 break;
945 }
946
947 102 case MOC_IDENTIFY_WAIT_FINGER_DELAY:
948 102 fpi_device_add_timeout (device, 50,
949 focaltech_moc_identify_wait_finger_delay,
950 NULL, NULL);
951 102 break;
952
953 4 case MOC_IDENTIFY_CAPTURE:
954 4 cmd_len = 0;
955 4 resp_len = sizeof (struct CaptureResult);
956 4 cmd_buf = focaltech_moc_compose_cmd (0xa6, NULL, cmd_len);
957 4 focaltech_moc_get_cmd (device, cmd_buf,
958 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
959 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
960 1,
961 focaltech_moc_identify_capture_cb);
962 4 break;
963
964 4 case MOC_IDENTIFY_MATCH:
965 4 cmd_len = 0;
966 4 resp_len = sizeof (struct UserId);
967 4 cmd_buf = focaltech_moc_compose_cmd (0xaa, NULL, cmd_len);
968 4 focaltech_moc_get_cmd (device, cmd_buf,
969 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
970 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
971 1,
972 focaltech_moc_identify_match_cb);
973 4 break;
974 }
975 220 }
976
977 static void
978 4 focaltech_moc_identify (FpDevice *device)
979 {
980 4 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
981
982 4 self->task_ssm = fpi_ssm_new (device,
983 focaltech_identify_run_state,
984 MOC_IDENTIFY_NUM_STATES);
985 4 fpi_ssm_start (self->task_ssm, task_ssm_done);
986 4 }
987
988 enum moc_enroll_states {
989 MOC_ENROLL_GET_ENROLLED_INFO,
990 MOC_ENROLL_GET_ENROLLED_LIST,
991 MOC_ENROLL_RELEASE_FINGER,
992 MOC_ENROLL_START_ENROLL,
993 MOC_ENROLL_WAIT_FINGER,
994 MOC_ENROLL_WAIT_FINGER_DELAY,
995 MOC_ENROLL_ENROLL_CAPTURE,
996 MOC_ENROLL_SET_ENROLLED_INFO,
997 MOC_ENROLL_COMMIT_RESULT,
998 MOC_ENROLL_NUM_STATES,
999 };
1000
1001 struct EnrolledInfoItem
1002 {
1003 uint8_t uid[FOCALTECH_MOC_UID_PREFIX_LENGTH];
1004 uint8_t user_id[FOCALTECH_MOC_USER_ID_LENGTH];
1005 };
1006
1007 struct UserDes
1008 {
1009 uint8_t finger;
1010 char username[FOCALTECH_MOC_USER_ID_LENGTH];
1011 };
1012
1013 struct EnrolledInfo
1014 {
1015 uint8_t actived[FOCALTECH_MOC_MAX_FINGERS];
1016 struct EnrolledInfoItem items[FOCALTECH_MOC_MAX_FINGERS];
1017 struct UserId user_id[FOCALTECH_MOC_MAX_FINGERS];
1018 struct UserDes user_des[FOCALTECH_MOC_MAX_FINGERS];
1019 };
1020
1021 typedef struct
1022 {
1023 GPtrArray *list_result;
1024 struct EnrolledInfo *enrolled_info;
1025 } FpActionData;
1026
1027 struct EnrolledInfoSetData
1028 {
1029 uint8_t data;
1030 struct EnrolledInfoItem items[FOCALTECH_MOC_MAX_FINGERS];
1031 };
1032
1033 static void
1034 6 fp_action_ssm_done_data_free (FpActionData *data)
1035 {
1036
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);
1037
1/2
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 6 not taken.
6 g_clear_pointer (&data->enrolled_info, g_free);
1038 6 g_free (data);
1039 6 }
1040
1041 static void
1042 6 focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
1043 uint8_t *buffer_in,
1044 gsize length_in,
1045 GError *error)
1046 {
1047 6 FpCmd *fp_cmd = NULL;
1048 6 struct EnrolledInfoItem *items = NULL;
1049 6 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1050
1051
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 6 times.
6 if (error)
1052 {
1053 fpi_ssm_mark_failed (self->task_ssm, error);
1054 return;
1055 }
1056
1057
1/2
✓ Branch 7 → 8 taken 6 times.
✗ Branch 7 → 17 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1058 sizeof (FpCmd) + sizeof (uint8_t),
1059 "get enrolled info"))
1060 return;
1061
1062 6 fp_cmd = (FpCmd *) buffer_in;
1063 6 items = (struct EnrolledInfoItem *) (fp_cmd + 1);
1064
1065
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 6 times.
6 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1066 {
1067 fpi_ssm_mark_failed (self->task_ssm,
1068 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1069 "Can't get response!!"));
1070 }
1071 else
1072 {
1073
2/2
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 15 taken 3 times.
6 if (fp_cmd->code == 0x04)
1074 {
1075
1/2
✓ Branch 13 → 14 taken 3 times.
✗ Branch 13 → 17 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1076 sizeof (FpCmd) +
1077 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem) +
1078 sizeof (uint8_t),
1079 "get enrolled info"))
1080 return;
1081 3 memcpy (&data->enrolled_info->items[0], items,
1082 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1083
1084 }
1085 3 else if (fp_cmd->code == 0x09)
1086 {
1087 3 memset (data->enrolled_info->actived, 0, FOCALTECH_MOC_MAX_FINGERS);
1088 3 memset (&data->enrolled_info->items[0], 0,
1089 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1090 }
1091
1092 6 fpi_ssm_next_state (self->task_ssm);
1093 }
1094 }
1095
1096 struct UidList
1097 {
1098 uint8_t actived[FOCALTECH_MOC_MAX_FINGERS];
1099 struct UserId uid[FOCALTECH_MOC_MAX_FINGERS];
1100 };
1101
1102 static int
1103 7 focaltech_moc_get_enrolled_info_item (FpiDeviceFocaltechMoc *self,
1104 uint8_t *uid,
1105 struct EnrolledInfoItem **pitem, int *index)
1106 {
1107 7 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1108 7 int ret = -1;
1109 7 int i;
1110
1111
2/2
✓ Branch 7 → 4 taken 43 times.
✓ Branch 7 → 8 taken 4 times.
54 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1112 {
1113 43 struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
1114
1115
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)
1116 {
1117 3 data->enrolled_info->actived[i] = 1;
1118 3 *pitem = item;
1119 3 *index = i;
1120 3 ret = 0;
1121 3 break;
1122 }
1123 }
1124
1125 7 return ret;
1126 }
1127
1128 static void
1129 6 focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
1130 uint8_t *buffer_in,
1131 gsize length_in,
1132 GError *error)
1133 {
1134 6 FpCmd *fp_cmd = NULL;
1135 6 struct UidList *uid_list = NULL;
1136
1137
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 6 times.
6 if (error)
1138 {
1139 fpi_ssm_mark_failed (self->task_ssm, error);
1140 return;
1141 }
1142
1143
1/2
✓ Branch 6 → 7 taken 6 times.
✗ Branch 6 → 38 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1144 sizeof (FpCmd) + sizeof (uint8_t),
1145 "get enrolled list"))
1146 return;
1147
1148 6 fp_cmd = (FpCmd *) buffer_in;
1149 6 uid_list = (struct UidList *) (fp_cmd + 1);
1150
1151
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 6 times.
6 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1152 {
1153 fpi_ssm_mark_failed (self->task_ssm,
1154 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1155 "Can't get response!!"));
1156 }
1157 else
1158 {
1159 6 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1160
1161
1/2
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 37 not taken.
6 if (fp_cmd->code == 0x04)
1162 {
1163
1/2
✓ Branch 13 → 32 taken 6 times.
✗ Branch 13 → 38 not taken.
6 if (!focaltech_moc_require_response_len (self, length_in,
1164 sizeof (FpCmd) +
1165 sizeof (struct UidList) +
1166 sizeof (uint8_t),
1167 "get enrolled list"))
1168 return;
1169
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++)
1170 {
1171
2/2
✓ Branch 14 → 15 taken 3 times.
✓ Branch 14 → 31 taken 57 times.
60 if (uid_list->actived[i] != 0)
1172 {
1173 3 struct UserId *user_id = &uid_list->uid[i];
1174 3 FpPrint *print = fp_print_new (FP_DEVICE (self));
1175 3 struct EnrolledInfoItem *item = NULL;
1176 3 int index;
1177
1178 3 fp_info ("focaltechmoc add slot: %zu", i);
1179
1180 3 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
1181
1182
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)
1183 {
1184 2 g_autofree gchar *userid_safe = NULL;
1185 2 const gchar *username;
1186
1187 2 userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
1188 2 fp_dbg ("%s", userid_safe);
1189 2 fpi_print_fill_from_user_id (print, userid_safe);
1190 2 memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
1191 2 data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
1192 2 username = fp_print_get_username (print);
1193
1194
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 2 times.
2 if (username != NULL)
1195 g_strlcpy (data->enrolled_info->user_des[index].username,
1196 username,
1197 sizeof (data->enrolled_info->user_des[index].username));
1198 }
1199
1200 3 g_ptr_array_add (data->list_result, g_object_ref_sink (print));
1201 }
1202 }
1203
1204
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++)
1205 {
1206 60 struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
1207
1208
2/2
✓ Branch 33 → 34 taken 58 times.
✓ Branch 33 → 35 taken 2 times.
60 if (data->enrolled_info->actived[i] == 0)
1209 58 memset (item, 0, sizeof (struct EnrolledInfoItem));
1210 }
1211 }
1212
1213 6 fpi_ssm_next_state (self->task_ssm);
1214 }
1215 }
1216
1217 static void
1218 301 focaltech_moc_enroll_wait_finger_cb (FpiDeviceFocaltechMoc *self,
1219 uint8_t *buffer_in,
1220 gsize length_in,
1221 GError *error)
1222 {
1223 301 FpCmd *fp_cmd = NULL;
1224 301 uint8_t *finger_status = NULL;
1225
1226
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 301 times.
301 if (error)
1227 {
1228 fpi_ssm_mark_failed (self->task_ssm, error);
1229 return;
1230 }
1231
1232 301 fp_cmd = (FpCmd *) buffer_in;
1233 301 finger_status = (uint8_t *) (fp_cmd + 1);
1234
1235
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 301 times.
301 if (fp_cmd->code != 0x04)
1236 {
1237 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER_DELAY);
1238 }
1239 else
1240 {
1241
1242
2/2
✓ Branch 7 → 8 taken 32 times.
✓ Branch 7 → 9 taken 269 times.
301 if (*finger_status == 0x01)
1243 32 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_ENROLL_CAPTURE);
1244 else
1245 269 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER_DELAY);
1246 }
1247 }
1248
1249 static void
1250 269 focaltech_moc_enroll_wait_finger_delay (FpDevice *device,
1251 void *user_data
1252 )
1253 {
1254 269 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1255
1256 269 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
1257 269 }
1258
1259 static void
1260 2 focaltech_moc_start_enroll_cb (FpiDeviceFocaltechMoc *self,
1261 uint8_t *buffer_in,
1262 gsize length_in,
1263 GError *error)
1264 {
1265 2 FpCmd *fp_cmd = NULL;
1266 2 struct UserId *user_id = NULL;
1267 2 FpPrint *print = NULL;
1268 2 struct EnrolledInfoItem *item = NULL;
1269 2 int index;
1270
1271
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 if (error)
1272 {
1273 fpi_ssm_mark_failed (self->task_ssm, error);
1274 return;
1275 }
1276
1277 2 fp_cmd = (FpCmd *) buffer_in;
1278 2 user_id = (struct UserId *) (fp_cmd + 1);
1279
1280
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 2 times.
2 if (fp_cmd->code != 0x04)
1281 {
1282 if (fp_cmd->code == 0x05)
1283 {
1284 fpi_ssm_mark_failed (self->task_ssm,
1285 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_FULL,
1286 "device data full!!"));
1287 }
1288 else
1289 {
1290 fpi_ssm_mark_failed (self->task_ssm,
1291 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1292 "Can't get response!!"));
1293 }
1294 return;
1295 }
1296
1297
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)
1298 {
1299 fpi_ssm_mark_failed (self->task_ssm,
1300 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1301 "uid error!!"));
1302 }
1303 else
1304 {
1305 2 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1306 2 g_autofree gchar *userid_safe = NULL;
1307 2 gsize userid_len;
1308 2 uint8_t found = 0;
1309 2 int i;
1310 2 struct EnrolledInfoItem *free_item = NULL;
1311
1312
1/2
✓ Branch 18 → 16 taken 2 times.
✗ Branch 18 → 19 not taken.
4 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1313 {
1314 2 item = &data->enrolled_info->items[i];
1315
1316
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 21 taken 2 times.
2 if (data->enrolled_info->actived[i] == 0)
1317 {
1318 2 found = 1;
1319 2 free_item = item;
1320 2 break;
1321 }
1322 }
1323
1324 2 if (found == 0)
1325 {
1326 fpi_ssm_mark_failed (self->task_ssm,
1327 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1328 "no uid slot!!"));
1329 }
1330 else
1331 {
1332 2 guint64 quirk = fpi_device_get_driver_data (FP_DEVICE (self));
1333
1334 2 fpi_device_get_enroll_data (FP_DEVICE (self), &print);
1335 2 fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
1336
1337
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 28 taken 1 time.
2 if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
1338 {
1339 1 fp_info ("Applying SINGLE_SLOT quirk: Forcing static User ID");
1340 1 userid_safe = g_strdup (FOCALTECH_MOC_STATIC_USER_ID);
1341 }
1342 else
1343 {
1344 1 userid_safe = fpi_print_generate_user_id (print);
1345 }
1346
1347 2 userid_len = strlen (userid_safe);
1348 2 userid_len = MIN (FOCALTECH_MOC_USER_ID_LENGTH, userid_len);
1349 2 fp_info ("focaltechmoc user id: %s", userid_safe);
1350 2 memcpy (free_item->uid, user_id->uid, FOCALTECH_MOC_UID_PREFIX_LENGTH);
1351 2 memcpy (free_item->user_id, userid_safe, userid_len);
1352 2 fpi_ssm_next_state (self->task_ssm);
1353 }
1354 }
1355 }
1356
1357 static void
1358 32 focaltech_moc_enroll_capture_cb (FpiDeviceFocaltechMoc *self,
1359 uint8_t *buffer_in,
1360 gsize length_in,
1361 GError *error)
1362 {
1363 32 FpCmd *fp_cmd = NULL;
1364 32 struct CaptureResult *capture_result = NULL;
1365
1366
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 32 times.
32 if (error)
1367 {
1368 fpi_ssm_mark_failed (self->task_ssm, error);
1369 return;
1370 }
1371
1372 32 fp_cmd = (FpCmd *) buffer_in;
1373 32 capture_result = (struct CaptureResult *) (fp_cmd + 1);
1374
1375
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 32 times.
32 if (fp_cmd->code != 0x04)
1376 {
1377 fpi_ssm_mark_failed (self->task_ssm,
1378 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1379 "Can't get response!!"));
1380 }
1381 else
1382 {
1383
2/2
✓ Branch 8 → 9 taken 28 times.
✓ Branch 8 → 11 taken 4 times.
32 if (capture_result->error == ERROR_NONE)
1384 {
1385 28 self->num_frames += 1;
1386 28 enroll_status_report (self, ENROLL_RSP_ENROLL_REPORT, self->num_frames, NULL);
1387 28 fp_info ("focaltechmoc remain: %d", capture_result->remain);
1388 }
1389 else
1390 {
1391 4 enroll_status_report (self, ENROLL_RSP_RETRY, self->num_frames, NULL);
1392 }
1393
1394
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)))
1395 2 fpi_ssm_next_state (self->task_ssm);
1396 else
1397 30 fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
1398 }
1399 }
1400
1401 static void
1402 3 focaltech_moc_set_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
1403 uint8_t *buffer_in,
1404 gsize length_in,
1405 GError *error)
1406 {
1407 3 FpCmd *fp_cmd = NULL;
1408
1409
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 3 times.
3 if (error)
1410 {
1411 fpi_ssm_mark_failed (self->task_ssm, error);
1412 return;
1413 }
1414
1415
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 12 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1416 sizeof (FpCmd) + sizeof (uint8_t),
1417 "set enrolled info"))
1418 return;
1419
1420 3 fp_cmd = (FpCmd *) buffer_in;
1421
1422
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 11 taken 3 times.
3 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1423 {
1424 fpi_ssm_mark_failed (self->task_ssm,
1425 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1426 "Can't get response!!"));
1427 return;
1428 }
1429
1430 3 fpi_ssm_next_state (self->task_ssm);
1431 }
1432
1433 static void
1434 2 focaltech_moc_commit_cb (FpiDeviceFocaltechMoc *self,
1435 uint8_t *buffer_in,
1436 gsize length_in,
1437 GError *error)
1438 {
1439 2 FpCmd *fp_cmd = NULL;
1440
1441
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 2 times.
2 if (error)
1442 {
1443 fpi_ssm_mark_failed (self->task_ssm, error);
1444 return;
1445 }
1446
1447
1/2
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 13 not taken.
2 if (!focaltech_moc_require_response_len (self, length_in,
1448 sizeof (FpCmd) + sizeof (uint8_t),
1449 "commit"))
1450 return;
1451
1452 2 fp_cmd = (FpCmd *) buffer_in;
1453
1454
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 2 times.
2 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1455 {
1456 fpi_ssm_mark_failed (self->task_ssm,
1457 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1458 "Can't get response!!"));
1459 }
1460 else
1461 {
1462 2 fp_info ("focaltech_moc_commit_cb success");
1463 2 enroll_status_report (self, ENROLL_RSP_ENROLL_OK, self->num_frames, NULL);
1464 2 fpi_ssm_next_state (self->task_ssm);
1465 }
1466 }
1467
1468 static void
1469 614 focaltech_enroll_run_state (FpiSsm *ssm, FpDevice *device)
1470 {
1471 614 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1472 614 guint8 *cmd_buf = NULL;
1473 614 uint16_t cmd_len = 0;
1474 614 uint16_t resp_len = 0;
1475
1476
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))
1477 {
1478 2 case MOC_ENROLL_GET_ENROLLED_INFO:
1479 {
1480 2 uint8_t data = 0x00;
1481 2 cmd_len = sizeof (uint8_t);
1482 2 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1483 2 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1484 2 focaltech_moc_get_cmd (device, cmd_buf,
1485 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1486 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1487 1,
1488 focaltech_moc_get_enrolled_info_cb);
1489 2 break;
1490 }
1491
1492 2 case MOC_ENROLL_GET_ENROLLED_LIST:
1493 {
1494 2 cmd_len = 0;
1495 2 resp_len = sizeof (struct UidList);
1496 2 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1497 2 focaltech_moc_get_cmd (device, cmd_buf,
1498 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1499 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1500 1,
1501 focaltech_moc_get_enrolled_list_cb);
1502 2 break;
1503 }
1504
1505 2 case MOC_ENROLL_RELEASE_FINGER:
1506 {
1507 2 uint8_t d1 = 0x78;
1508 2 cmd_len = sizeof (d1);
1509 2 resp_len = 0;
1510 2 cmd_buf = focaltech_moc_compose_cmd (0x82, &d1, cmd_len);
1511 2 focaltech_moc_get_cmd (device, cmd_buf,
1512 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1513 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1514 1,
1515 focaltech_moc_release_finger);
1516 2 break;
1517 }
1518
1519 2 case MOC_ENROLL_START_ENROLL:
1520 2 cmd_len = 0;
1521 2 resp_len = sizeof (struct UserId);
1522 2 cmd_buf = focaltech_moc_compose_cmd (0xa9, NULL, cmd_len);
1523 2 focaltech_moc_get_cmd (device, cmd_buf,
1524 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1525 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1526 1,
1527 focaltech_moc_start_enroll_cb);
1528 2 break;
1529
1530
1531 301 case MOC_ENROLL_WAIT_FINGER:
1532 {
1533 301 uint8_t data = 0x02;
1534 301 cmd_len = sizeof (uint8_t);
1535 301 resp_len = sizeof (uint8_t);
1536 301 cmd_buf = focaltech_moc_compose_cmd (0x80, &data, cmd_len);
1537 301 focaltech_moc_get_cmd (device, cmd_buf,
1538 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1539 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1540 1,
1541 focaltech_moc_enroll_wait_finger_cb);
1542 301 break;
1543 }
1544
1545 269 case MOC_ENROLL_WAIT_FINGER_DELAY:
1546 269 fpi_device_add_timeout (device, 50,
1547 focaltech_moc_enroll_wait_finger_delay,
1548 NULL, NULL);
1549 269 break;
1550
1551 32 case MOC_ENROLL_ENROLL_CAPTURE:
1552 32 cmd_len = 0;
1553 32 resp_len = sizeof (struct CaptureResult);
1554 32 cmd_buf = focaltech_moc_compose_cmd (0xa6, NULL, cmd_len);
1555 32 focaltech_moc_get_cmd (device, cmd_buf,
1556 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1557 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1558 1,
1559 focaltech_moc_enroll_capture_cb);
1560 32 break;
1561
1562 2 case MOC_ENROLL_SET_ENROLLED_INFO:
1563 {
1564 2 g_autofree struct EnrolledInfoSetData *set_data = NULL;
1565 2 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1566
1567 2 cmd_len = sizeof (struct EnrolledInfoSetData);
1568 2 resp_len = 0;
1569 2 set_data = (struct EnrolledInfoSetData *) g_malloc0 (cmd_len);
1570 2 set_data->data = 0x01;
1571 2 memcpy (&set_data->items[0], &data->enrolled_info->items[0],
1572 FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1573 2 cmd_buf = focaltech_moc_compose_cmd (0xaf, (const uint8_t *) set_data, cmd_len);
1574 2 focaltech_moc_get_cmd (device, cmd_buf,
1575 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1576 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1577 1,
1578 focaltech_moc_set_enrolled_info_cb);
1579 2 break;
1580 }
1581
1582 2 case MOC_ENROLL_COMMIT_RESULT:
1583 {
1584 2 FpPrint *print = NULL;
1585 2 g_autoptr(GVariant) data = NULL;
1586
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;
1587 2 const guint8 *user_id;
1588 2 gsize user_id_len = 0;
1589
1590 2 fpi_device_get_enroll_data (FP_DEVICE (self), &print);
1591 2 g_object_get (print, "fpi-data", &data, NULL);
1592
1593
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 40 taken 2 times.
2 if (!g_variant_check_format_string (data, "(@ay)", FALSE))
1594 {
1595 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
1596 return;
1597 }
1598
1599 2 g_variant_get (data,
1600 "(@ay)",
1601 &user_id_var);
1602 2 user_id = g_variant_get_fixed_array (user_id_var, &user_id_len, 1);
1603
1604 2 cmd_len = user_id_len;
1605 2 resp_len = 0;
1606 2 cmd_buf = focaltech_moc_compose_cmd (0xa3, user_id, cmd_len);
1607 2 focaltech_moc_get_cmd (device, cmd_buf,
1608 2 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1609 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1610 1,
1611 focaltech_moc_commit_cb);
1612
1/2
✓ Branch 44 → 45 taken 2 times.
✗ Branch 44 → 46 not taken.
2 break;
1613 }
1614 }
1615 }
1616
1617 static void
1618 2 focaltech_moc_enroll (FpDevice *device)
1619 {
1620 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1621 2 FpActionData *data = g_new0 (FpActionData, 1);
1622
1623 2 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
1624 2 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
1625
1626 2 self->task_ssm = fpi_ssm_new (FP_DEVICE (self),
1627 focaltech_enroll_run_state,
1628 MOC_ENROLL_NUM_STATES);
1629 2 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
1630 2 fpi_ssm_start (self->task_ssm, task_ssm_done);
1631 2 }
1632
1633 static void
1634 1 focaltech_moc_delete_cb (FpiDeviceFocaltechMoc *self,
1635 uint8_t *buffer_in,
1636 gsize length_in,
1637 GError *error)
1638 {
1639 1 FpCmd *fp_cmd = NULL;
1640
1641
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 1 time.
1 if (error)
1642 {
1643 fpi_ssm_mark_failed (self->task_ssm, error);
1644 return;
1645 }
1646
1647
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 16 not taken.
1 if (!focaltech_moc_require_response_len (self, length_in,
1648 sizeof (FpCmd) + sizeof (uint8_t),
1649 "delete"))
1650 return;
1651
1652 1 fp_cmd = (FpCmd *) buffer_in;
1653
1654
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 1 time.
1 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1655 {
1656 fpi_ssm_mark_failed (self->task_ssm,
1657 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1658 "Can't get response!!"));
1659 }
1660 else
1661 {
1662 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1663 1 int ssm_state;
1664
1665
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 14 not taken.
1 if (self->delete_slot != -1)
1666 {
1667 1 fp_dbg ("delete slot %d", self->delete_slot);
1668 1 data->enrolled_info->actived[self->delete_slot] = 0;
1669 1 memset (&data->enrolled_info->items[self->delete_slot], 0, sizeof (struct EnrolledInfoItem));
1670 1 memset (&data->enrolled_info->user_id[self->delete_slot], 0, sizeof (struct UserId));
1671 1 memset (&data->enrolled_info->user_des[self->delete_slot], 0, sizeof (struct UserDes));
1672 }
1673
1674 1 ssm_state = fpi_ssm_get_cur_state (self->task_ssm);
1675 1 fpi_ssm_jump_to_state (self->task_ssm, ssm_state);
1676 }
1677 }
1678
1679 enum delete_states {
1680 MOC_DELETE_GET_ENROLLED_INFO,
1681 MOC_DELETE_GET_ENROLLED_LIST,
1682 MOC_DELETE_SET_ENROLLED_INFO,
1683 MOC_DELETE_BY_UID,
1684 MOC_DELETE_BY_USER_INFO,
1685 MOC_DELETE_NUM_STATES,
1686 };
1687
1688 static void
1689 6 focaltech_delete_run_state (FpiSsm *ssm, FpDevice *device)
1690 {
1691 6 guint8 *cmd_buf = NULL;
1692 6 uint16_t cmd_len = 0;
1693 6 uint16_t resp_len = 0;
1694
1695
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))
1696 {
1697 1 case MOC_DELETE_GET_ENROLLED_INFO:
1698 {
1699 1 uint8_t data = 0x00;
1700 1 cmd_len = sizeof (uint8_t);
1701 1 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1702 1 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1703 1 focaltech_moc_get_cmd (device, cmd_buf,
1704 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1705 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1706 1,
1707 focaltech_moc_get_enrolled_info_cb);
1708 1 break;
1709 }
1710
1711 1 case MOC_DELETE_GET_ENROLLED_LIST:
1712 {
1713 1 cmd_len = 0;
1714 1 resp_len = sizeof (struct UidList) + sizeof (struct UserId) * FOCALTECH_MOC_MAX_FINGERS;
1715 1 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1716 1 focaltech_moc_get_cmd (device, cmd_buf,
1717 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1718 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1719 1,
1720 focaltech_moc_get_enrolled_list_cb);
1721 1 break;
1722 }
1723
1724 case MOC_DELETE_SET_ENROLLED_INFO:
1725 {
1726 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1727 1 g_autofree struct EnrolledInfoSetData *set_data = NULL;
1728 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1729
1730 1 cmd_len = sizeof (struct EnrolledInfoSetData);
1731 1 resp_len = 0;
1732 1 set_data = (struct EnrolledInfoSetData *) g_malloc0 (cmd_len);
1733 1 set_data->data = 0x01;
1734 1 memcpy (&set_data->items[0], &data->enrolled_info->items[0], FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
1735 1 cmd_buf = focaltech_moc_compose_cmd (0xaf, (const uint8_t *) set_data, cmd_len);
1736 1 focaltech_moc_get_cmd (device, cmd_buf,
1737 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1738 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1739 1,
1740 focaltech_moc_set_enrolled_info_cb);
1741 1 break;
1742 }
1743
1744 case MOC_DELETE_BY_UID:
1745 {
1746 2 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1747 2 FpPrint *print = NULL;
1748 2 g_autoptr(GVariant) data = NULL;
1749
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;
1750 2 const guint8 *user_id;
1751 2 gsize user_id_len = 0;
1752 2 struct EnrolledInfoItem *item = NULL;
1753 2 int index;
1754
1755 2 self->delete_slot = -1;
1756 2 fpi_device_get_delete_data (device, &print);
1757 2 g_object_get (print, "fpi-data", &data, NULL);
1758
1759
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 26 taken 2 times.
2 if (!g_variant_check_format_string (data, "(@ay)", FALSE))
1760 {
1761 fpi_device_delete_complete (device,
1762 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
1763 return;
1764 }
1765
1766 2 g_variant_get (data, "(@ay)", &user_id_var);
1767 2 user_id = g_variant_get_fixed_array (user_id_var, &user_id_len, 1);
1768
1769
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)
1770 1 self->delete_slot = index;
1771
1772
2/2
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 34 taken 1 time.
2 if (self->delete_slot != -1)
1773 {
1774 1 cmd_len = sizeof (struct UserId);
1775 1 resp_len = 0;
1776 1 cmd_buf = focaltech_moc_compose_cmd (0xa8, user_id, cmd_len);
1777 1 focaltech_moc_get_cmd (device, cmd_buf,
1778 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1779 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1780 1,
1781 focaltech_moc_delete_cb);
1782 }
1783 else
1784 {
1785 1 fpi_ssm_next_state (self->task_ssm);
1786 }
1787
1788
1/2
✓ Branch 35 → 36 taken 2 times.
✗ Branch 35 → 37 not taken.
2 break;
1789 }
1790
1791 case MOC_DELETE_BY_USER_INFO:
1792 {
1793 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1794 1 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1795 1 FpPrint *print = NULL;
1796 1 const guint8 *user_id;
1797 1 const gchar *username;
1798 1 uint8_t finger;
1799 1 int i;
1800
1801 1 self->delete_slot = -1;
1802 1 fpi_device_get_delete_data (device, &print);
1803 1 username = fp_print_get_username (print);
1804 1 finger = fp_print_get_finger (print);
1805
1806
2/2
✓ Branch 53 → 45 taken 10 times.
✓ Branch 53 → 54 taken 1 time.
11 for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
1807 {
1808 10 struct UserDes *user_des = &data->enrolled_info->user_des[i];
1809
1810
1/2
✓ Branch 45 → 46 taken 10 times.
✗ Branch 45 → 47 not taken.
10 if (username == NULL)
1811 10 continue;
1812
1813 if (strncmp (user_des->username, username, FOCALTECH_MOC_USER_ID_LENGTH) != 0)
1814 continue;
1815
1816 if (finger != user_des->finger)
1817 continue;
1818
1819 self->delete_slot = i;
1820 }
1821
1822
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 57 taken 1 time.
1 if (self->delete_slot != -1)
1823 {
1824 user_id = (const guint8 *) &data->enrolled_info->user_id[self->delete_slot].uid[0];
1825 cmd_len = sizeof (struct UserId);
1826 resp_len = 0;
1827 cmd_buf = focaltech_moc_compose_cmd (0xa8, user_id, cmd_len);
1828 focaltech_moc_get_cmd (device, cmd_buf,
1829 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1830 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1831 1,
1832 focaltech_moc_delete_cb);
1833 }
1834 else
1835 {
1836 1 fpi_device_delete_complete (FP_DEVICE (self), NULL);
1837 1 fpi_ssm_next_state (self->task_ssm);
1838 }
1839
1840 1 break;
1841 }
1842 }
1843 }
1844
1845 static void
1846 1 focaltech_moc_delete_print (FpDevice *device)
1847 {
1848 1 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1849 1 FpActionData *data = NULL;
1850
1851 1 data = g_new0 (FpActionData, 1);
1852 1 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
1853 1 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
1854
1855 1 self->task_ssm = fpi_ssm_new (device,
1856 focaltech_delete_run_state,
1857 MOC_DELETE_NUM_STATES);
1858 1 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
1859 1 fpi_ssm_start (self->task_ssm, task_ssm_done);
1860 1 }
1861
1862 enum moc_clear_storage_states {
1863 MOC_CLEAR_STORAGE_SEND,
1864 MOC_CLEAR_STORAGE_NUM_STATES,
1865 };
1866
1867 static void
1868 3 focaltech_moc_clear_storage_cb (FpiDeviceFocaltechMoc *self,
1869 uint8_t *buffer_in,
1870 gsize length_in,
1871 GError *error)
1872 {
1873 3 FpCmd *fp_cmd = NULL;
1874
1875
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 3 times.
3 if (error)
1876 {
1877 fp_warn ("Mass erase command completed with warning: %s", error->message);
1878 fpi_ssm_mark_failed (self->task_ssm, error);
1879 return;
1880 }
1881
1882
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 10 taken 3 times.
3 if (length_in == 0)
1883 {
1884 fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
1885 fpi_ssm_next_state (self->task_ssm);
1886 return;
1887 }
1888
1889
1/2
✓ Branch 11 → 12 taken 3 times.
✗ Branch 11 → 18 not taken.
3 if (!focaltech_moc_require_response_len (self, length_in,
1890 sizeof (FpCmd) + sizeof (uint8_t),
1891 "clear storage"))
1892 return;
1893
1894 3 fp_cmd = (FpCmd *) buffer_in;
1895
1896
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 16 taken 3 times.
3 if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
1897 {
1898 fpi_ssm_mark_failed (self->task_ssm,
1899 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1900 "Clear storage failed: unexpected response code 0x%02x",
1901 fp_cmd->code));
1902 return;
1903 }
1904
1905 3 fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
1906 3 fpi_ssm_next_state (self->task_ssm);
1907 }
1908
1909 static void
1910 3 focaltech_clear_storage_run_state (FpiSsm *ssm, FpDevice *device)
1911 {
1912 3 guint64 quirk = fpi_device_get_driver_data (device);
1913 3 guint8 *cmd_buf = NULL;
1914 3 uint16_t cmd_len = 0;
1915 3 uint16_t resp_len = 0;
1916
1917
1/2
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 8 not taken.
3 switch (fpi_ssm_get_cur_state (ssm))
1918 {
1919 3 case MOC_CLEAR_STORAGE_SEND:
1920 3 resp_len = quirk == FOCALTECH_QUIRK_SINGLE_SLOT ? 0 : sizeof (uint8_t);
1921 3 cmd_buf = focaltech_moc_compose_cmd (0xac, NULL, cmd_len);
1922
1923 3 focaltech_moc_get_cmd (device, cmd_buf,
1924 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1925 3 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1926 FALSE,
1927 focaltech_moc_clear_storage_cb);
1928 3 break;
1929 }
1930 3 }
1931
1932 static void
1933 3 focaltech_moc_clear_storage (FpDevice *device)
1934 {
1935 3 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1936
1937 3 self->task_ssm = fpi_ssm_new (device,
1938 focaltech_clear_storage_run_state,
1939 MOC_CLEAR_STORAGE_NUM_STATES);
1940 3 fpi_ssm_start (self->task_ssm, task_ssm_done);
1941 3 }
1942
1943 enum moc_list_states {
1944 MOC_LIST_GET_ENROLLED_INFO,
1945 MOC_LIST_GET_ENROLLED_LIST,
1946 MOC_LIST_REPORT,
1947 MOC_LIST_NUM_STATES,
1948 };
1949
1950 static void
1951 9 focaltech_list_run_state (FpiSsm *ssm, FpDevice *device)
1952 {
1953 9 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
1954 9 guint8 *cmd_buf = NULL;
1955 9 uint16_t cmd_len = 0;
1956 9 uint16_t resp_len = 0;
1957
1958
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))
1959 {
1960 3 case MOC_LIST_GET_ENROLLED_INFO:
1961 {
1962 3 uint8_t data = 0x00;
1963 3 cmd_len = sizeof (uint8_t);
1964 3 resp_len = sizeof (struct EnrolledInfoItem) * FOCALTECH_MOC_MAX_FINGERS;
1965 3 cmd_buf = focaltech_moc_compose_cmd (0xaf, &data, cmd_len);
1966 3 focaltech_moc_get_cmd (device, cmd_buf,
1967 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1968 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1969 1,
1970 focaltech_moc_get_enrolled_info_cb);
1971 3 break;
1972 }
1973
1974 3 case MOC_LIST_GET_ENROLLED_LIST:
1975 {
1976 3 cmd_len = 0;
1977 3 resp_len = sizeof (struct UidList) + sizeof (struct UserId) * FOCALTECH_MOC_MAX_FINGERS;
1978 3 cmd_buf = focaltech_moc_compose_cmd (0xab, NULL, cmd_len);
1979 3 focaltech_moc_get_cmd (device, cmd_buf,
1980 sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
1981 sizeof (FpCmd) + resp_len + sizeof (uint8_t),
1982 1,
1983 focaltech_moc_get_enrolled_list_cb);
1984 3 break;
1985 }
1986
1987 3 case MOC_LIST_REPORT:
1988 {
1989 3 FpActionData *data = fpi_ssm_get_data (self->task_ssm);
1990 3 fpi_device_list_complete (FP_DEVICE (self), g_steal_pointer (&data->list_result), NULL);
1991 3 fpi_ssm_next_state (self->task_ssm);
1992 3 break;
1993 }
1994 }
1995 9 }
1996
1997 static void
1998 3 focaltech_moc_list (FpDevice *device)
1999 {
2000 3 FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
2001 3 FpActionData *data = g_new0 (FpActionData, 1);
2002
2003 3 data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
2004 3 data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
2005 3 self->task_ssm = fpi_ssm_new (device,
2006 focaltech_list_run_state,
2007 MOC_LIST_NUM_STATES);
2008 3 fpi_ssm_set_data (self->task_ssm, data, (GDestroyNotify) fp_action_ssm_done_data_free);
2009 3 fpi_ssm_start (self->task_ssm, task_ssm_done);
2010 3 }
2011
2012 static void
2013 2 fpi_device_focaltech_moc_init (FpiDeviceFocaltechMoc *self)
2014 {
2015 2 G_DEBUG_HERE ();
2016 2 }
2017
2018 static void
2019 2 focaltech_moc_probe (FpDevice *device)
2020 {
2021 2 guint64 quirk = fpi_device_get_driver_data (device);
2022
2023
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
2 if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
2024 1 fpi_device_update_features (device, FP_DEVICE_FEATURE_STORAGE_DELETE, 0);
2025
2026 2 fpi_device_probe_complete (device, NULL, NULL, NULL);
2027 2 }
2028
2029 static void
2030 125 fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
2031 {
2032 125 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
2033
2034 125 dev_class->id = FP_COMPONENT;
2035 125 dev_class->full_name = FOCALTECH_MOC_DRIVER_FULLNAME;
2036
2037 125 dev_class->type = FP_DEVICE_TYPE_USB;
2038 125 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
2039 125 dev_class->id_table = id_table;
2040 125 dev_class->nr_enroll_stages = FOCALTECH_MOC_MAX_FINGERS;
2041 125 dev_class->temp_hot_seconds = -1;
2042
2043 125 dev_class->probe = focaltech_moc_probe;
2044 125 dev_class->open = focaltech_moc_open;
2045 125 dev_class->close = focaltech_moc_close;
2046 125 dev_class->verify = focaltech_moc_identify;
2047 125 dev_class->enroll = focaltech_moc_enroll;
2048 125 dev_class->identify = focaltech_moc_identify;
2049 125 dev_class->delete = focaltech_moc_delete_print;
2050 125 dev_class->clear_storage = focaltech_moc_clear_storage;
2051 125 dev_class->list = focaltech_moc_list;
2052
2053 125 fpi_device_class_auto_initialize_features (dev_class);
2054 125 }
2055