GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/egismoc/egismoc.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 610 708 86.2%
Functions: 42 43 97.7%
Branches: 189 313 60.4%

Line Branch Exec Source
1 /*
2 * Driver for Egis Technology (LighTuning) Match-On-Chip sensors
3 * Originally authored 2023 by Joshua Grisham <josh@joshuagrisham.com>
4 *
5 * Portions of code and logic inspired from the elanmoc libfprint driver
6 * which is copyright (C) 2021 Elan Microelectronics Inc (see elanmoc.c)
7 *
8 * Based on original reverse-engineering work by Joshua Grisham. The protocol has
9 * been reverse-engineered from captures of the official Windows driver, and by
10 * testing commands on the sensor with a multiplatform Python prototype driver:
11 * https://github.com/joshuagrisham/galaxy-book2-pro-linux/tree/main/fingerprint/
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 #define FP_COMPONENT "egismoc"
29
30 #include <stdio.h>
31 #include <glib.h>
32 #include <sys/param.h>
33
34 #include "drivers_api.h"
35 #include "fpi-byte-writer.h"
36
37 #include "egismoc.h"
38
39 struct _FpiDeviceEgisMoc
40 {
41 FpDevice parent;
42 FpiSsm *task_ssm;
43 FpiSsm *cmd_ssm;
44 FpiUsbTransfer *cmd_transfer;
45 GCancellable *interrupt_cancellable;
46 GPtrArray *enrolled_ids;
47 gint max_enroll_stages;
48 };
49
50
4/5
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
768 G_DEFINE_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FP_TYPE_DEVICE);
51
52 static const FpIdEntry egismoc_id_table[] = {
53 { .vid = 0x1c7a, .pid = 0x0582, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 },
54 { .vid = 0x1c7a, .pid = 0x0583, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 },
55 { .vid = 0x1c7a, .pid = 0x0586, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
56 { .vid = 0x1c7a, .pid = 0x0587, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
57 { .vid = 0x1c7a, .pid = 0x05a1, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 },
58 { .vid = 0, .pid = 0, .driver_data = 0 }
59 };
60
61 typedef void (*SynCmdMsgCallback) (FpDevice *device,
62 guchar *buffer_in,
63 gsize length_in,
64 GError *error);
65
66 typedef struct egismoc_command_data
67 {
68 SynCmdMsgCallback callback;
69 } CommandData;
70
71 typedef struct egismoc_enroll_print
72 {
73 FpPrint *print;
74 int stage;
75 } EnrollPrint;
76
77 static void
78 163 egismoc_finger_on_sensor_cb (FpiUsbTransfer *transfer,
79 FpDevice *device,
80 gpointer userdata,
81 GError *error)
82 {
83 163 fp_dbg ("Finger on sensor callback");
84 163 fpi_device_report_finger_status (device, FP_FINGER_STATUS_PRESENT);
85
86
1/2
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
163 g_return_if_fail (transfer->ssm);
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163 times.
163 if (error)
88 fpi_ssm_mark_failed (transfer->ssm, error);
89 else
90 163 fpi_ssm_next_state (transfer->ssm);
91 }
92
93 static void
94 163 egismoc_wait_finger_on_sensor (FpiSsm *ssm,
95 FpDevice *device)
96 {
97 163 fp_dbg ("Wait for finger on sensor");
98 163 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
99
100 163 g_autoptr(FpiUsbTransfer) transfer = fpi_usb_transfer_new (device);
101
102 163 fpi_usb_transfer_fill_interrupt (transfer, EGISMOC_EP_CMD_INTERRUPT_IN,
103 EGISMOC_USB_INTERRUPT_IN_RECV_LENGTH);
104 163 transfer->ssm = ssm;
105 /* Interrupt on this device always returns 1 byte short; this is expected */
106 163 transfer->short_is_error = FALSE;
107
108 163 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NEEDED);
109
110 163 fpi_usb_transfer_submit (g_steal_pointer (&transfer),
111 EGISMOC_USB_INTERRUPT_TIMEOUT,
112 self->interrupt_cancellable,
113 egismoc_finger_on_sensor_cb,
114 NULL);
115 163 }
116
117 static gboolean
118 179 egismoc_validate_response_prefix (const guchar *buffer_in,
119 const gsize buffer_in_len,
120 const guchar *valid_prefix,
121 const gsize valid_prefix_len)
122 {
123 179 const gboolean result = memcmp (buffer_in +
124 (egismoc_read_prefix_len +
125 EGISMOC_CHECK_BYTES_LENGTH),
126 valid_prefix,
127 179 valid_prefix_len) == 0;
128
129
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 177 times.
181 fp_dbg ("Response prefix valid: %s", result ? "yes" : "NO");
130 179 return result;
131 }
132
133 static gboolean
134 188 egismoc_validate_response_suffix (const guchar *buffer_in,
135 const gsize buffer_in_len,
136 const guchar *valid_suffix,
137 const gsize valid_suffix_len)
138 {
139 188 const gboolean result = memcmp (buffer_in + (buffer_in_len - valid_suffix_len),
140 valid_suffix,
141 188 valid_suffix_len) == 0;
142
143
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 162 times.
214 fp_dbg ("Response suffix valid: %s", result ? "yes" : "NO");
144 188 return result;
145 }
146
147 static void
148 64 egismoc_task_ssm_done (FpiSsm *ssm,
149 FpDevice *device,
150 GError *error)
151 {
152 64 fp_dbg ("Task SSM done");
153 64 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
154
155 /* task_ssm is going to be freed by completion of SSM */
156
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
64 g_assert (!self->task_ssm || self->task_ssm == ssm);
157 64 self->task_ssm = NULL;
158
159
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
64 g_clear_pointer (&self->enrolled_ids, g_ptr_array_unref);
160
161
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 60 times.
64 if (error)
162 4 fpi_device_action_error (device, error);
163 64 }
164
165 static void
166 386 egismoc_task_ssm_next_state_cb (FpDevice *device,
167 guchar *buffer_in,
168 gsize length_in,
169 GError *error)
170 {
171 386 fp_dbg ("Task SSM next state callback");
172 386 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
173
174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 386 times.
386 if (error)
175 fpi_ssm_mark_failed (self->task_ssm, error);
176 else
177 386 fpi_ssm_next_state (self->task_ssm);
178 386 }
179
180 static void
181 625 egismoc_cmd_receive_cb (FpiUsbTransfer *transfer,
182 FpDevice *device,
183 gpointer userdata,
184 GError *error)
185 {
186 625 g_autofree guchar *buffer = NULL;
187 625 CommandData *data = userdata;
188 625 SynCmdMsgCallback callback;
189 625 gssize actual_length;
190
191 625 fp_dbg ("Command receive callback");
192
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
625 if (error)
194 {
195 fpi_ssm_mark_failed (transfer->ssm, error);
196 return;
197 }
198
2/4
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 625 times.
625 if (data == NULL || transfer->actual_length < egismoc_read_prefix_len)
199 {
200 fpi_ssm_mark_failed (transfer->ssm,
201 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
202 return;
203 }
204
205 /* Let's complete the previous ssm and then handle the callback, so that
206 * we are sure that we won't start a transfer or a new command while there is
207 * another one still ongoing
208 */
209 625 callback = data->callback;
210 625 buffer = g_steal_pointer (&transfer->buffer);
211 625 actual_length = transfer->actual_length;
212
213 625 fpi_ssm_mark_completed (transfer->ssm);
214
215
1/2
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
625 if (callback)
216 625 callback (device, buffer, actual_length, NULL);
217 }
218
219 static void
220 1250 egismoc_cmd_run_state (FpiSsm *ssm,
221 FpDevice *device)
222 {
223 1250 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
224
225 2500 g_autoptr(FpiUsbTransfer) transfer = NULL;
226
227
2/3
✓ Branch 1 taken 625 times.
✓ Branch 2 taken 625 times.
✗ Branch 3 not taken.
1250 switch (fpi_ssm_get_cur_state (ssm))
228 {
229 625 case CMD_SEND:
230
1/2
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
625 if (self->cmd_transfer)
231 {
232 625 self->cmd_transfer->ssm = ssm;
233 625 fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer),
234 EGISMOC_USB_SEND_TIMEOUT,
235 fpi_device_get_cancellable (device),
236 fpi_ssm_usb_transfer_cb,
237 NULL);
238 625 break;
239 }
240
241 fpi_ssm_next_state (ssm);
242 break;
243
244 625 case CMD_GET:
245 625 transfer = fpi_usb_transfer_new (device);
246 625 transfer->ssm = ssm;
247 625 fpi_usb_transfer_fill_bulk (transfer, EGISMOC_EP_CMD_IN,
248 EGISMOC_USB_IN_RECV_LENGTH);
249 625 fpi_usb_transfer_submit (g_steal_pointer (&transfer),
250 EGISMOC_USB_RECV_TIMEOUT,
251 fpi_device_get_cancellable (device),
252 egismoc_cmd_receive_cb,
253 fpi_ssm_get_data (ssm));
254 625 break;
255 }
256 1250 }
257
258 static void
259 625 egismoc_cmd_ssm_done (FpiSsm *ssm,
260 FpDevice *device,
261 GError *error)
262 {
263 1250 g_autoptr(GError) local_error = error;
264 625 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
265 625 CommandData *data = fpi_ssm_get_data (ssm);
266
267
1/2
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
625 g_assert (self->cmd_ssm == ssm);
268
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
625 g_assert (!self->cmd_transfer || self->cmd_transfer->ssm == ssm);
269
270 625 self->cmd_ssm = NULL;
271 625 self->cmd_transfer = NULL;
272
273
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
625 if (error && data && data->callback)
274 data->callback (device, NULL, 0, g_steal_pointer (&local_error));
275 625 }
276
277 /*
278 * Derive the 2 "check bytes" for write payloads
279 * 32-bit big-endian sum of all 16-bit words (including check bytes) MOD 0xFFFF
280 * should be 0, otherwise the device will reject the payload
281 */
282 static guint16
283 625 egismoc_get_check_bytes (FpiByteReader *reader)
284 {
285 625 fp_dbg ("Get check bytes");
286 625 size_t sum_values = 0;
287 625 guint16 val;
288
289 625 fpi_byte_reader_set_pos (reader, 0);
290
291
2/2
✓ Branch 2 taken 7195 times.
✓ Branch 3 taken 625 times.
7820 while (fpi_byte_reader_get_uint16_be (reader, &val))
292 7195 sum_values += val;
293
294 625 return G_MAXUINT16 - (sum_values % G_MAXUINT16);
295 }
296
297 static void
298 625 egismoc_exec_cmd (FpDevice *device,
299 guchar *cmd,
300 const gsize cmd_length,
301 GDestroyNotify cmd_destroy,
302 SynCmdMsgCallback callback)
303 {
304 625 g_auto(FpiByteWriter) writer = {0};
305 625 g_autoptr(FpiUsbTransfer) transfer = NULL;
306 625 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
307 625 g_autofree CommandData *data = NULL;
308 625 gsize buffer_out_length = 0;
309 625 gboolean written = TRUE;
310 625 guint16 check_value;
311
312 625 fp_dbg ("Execute command and get response");
313
314 /*
315 * buffer_out should be a fully composed command (with prefix, check bytes, etc)
316 * which looks like this:
317 * E G I S 00 00 00 01 {cb1} {cb2} {payload}
318 * where cb1 and cb2 are some check bytes generated by the
319 * egismoc_get_check_bytes() method and payload is what is passed via the cmd
320 * parameter
321 */
322 625 buffer_out_length = egismoc_write_prefix_len
323 + EGISMOC_CHECK_BYTES_LENGTH
324 625 + cmd_length;
325
326 625 fpi_byte_writer_init_with_size (&writer, buffer_out_length +
327 (buffer_out_length % 2 ? 1 : 0), TRUE);
328
329 /* Prefix */
330
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 625 times.
625 written &= fpi_byte_writer_put_data (&writer, egismoc_write_prefix,
331 egismoc_write_prefix_len);
332
333 /* Check Bytes - leave them as 00 for now then later generate and copy over
334 * the real ones */
335 625 written &= fpi_byte_writer_change_pos (&writer, EGISMOC_CHECK_BYTES_LENGTH);
336
337 /* Command Payload */
338
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 625 times.
625 written &= fpi_byte_writer_put_data (&writer, cmd, cmd_length);
339
340 /* Now fetch and set the "real" check bytes based on the currently
341 * assembled payload */
342 625 check_value = egismoc_get_check_bytes (FPI_BYTE_READER (&writer));
343 625 fpi_byte_writer_set_pos (&writer, egismoc_write_prefix_len);
344
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 625 times.
625 written &= fpi_byte_writer_put_uint16_be (&writer, check_value);
345
346 /* destroy cmd if requested */
347
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 585 times.
625 if (cmd_destroy)
348
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 g_clear_pointer (&cmd, cmd_destroy);
349
350
1/2
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
625 g_assert (self->cmd_ssm == NULL);
351 625 self->cmd_ssm = fpi_ssm_new (device,
352 egismoc_cmd_run_state,
353 CMD_STATES);
354
355 625 data = g_new0 (CommandData, 1);
356 625 data->callback = callback;
357 625 fpi_ssm_set_data (self->cmd_ssm, g_steal_pointer (&data), g_free);
358
359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
625 if (!written)
360 {
361 fpi_ssm_start (self->cmd_ssm, egismoc_cmd_ssm_done);
362 fpi_ssm_mark_failed (self->cmd_ssm,
363 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
364 return;
365 }
366
367 625 transfer = fpi_usb_transfer_new (device);
368 625 transfer->short_is_error = TRUE;
369 625 transfer->ssm = self->cmd_ssm;
370
371 625 fpi_usb_transfer_fill_bulk_full (transfer,
372 EGISMOC_EP_CMD_OUT,
373 fpi_byte_writer_reset_and_get_data (&writer),
374 buffer_out_length,
375 g_free);
376
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
625 g_assert (self->cmd_transfer == NULL);
378 625 self->cmd_transfer = g_steal_pointer (&transfer);
379 625 fpi_ssm_start (self->cmd_ssm, egismoc_cmd_ssm_done);
380 }
381
382 static void
383 48 egismoc_set_print_data (FpPrint *print,
384 const gchar *device_print_id,
385 const gchar *user_id)
386 {
387 48 GVariant *print_id_var = NULL;
388 48 GVariant *fpi_data = NULL;
389 96 g_autofree gchar *fill_user_id = NULL;
390
391
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 40 times.
48 if (user_id)
392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 fill_user_id = g_strdup (user_id);
393 else
394 40 fill_user_id = g_strndup (device_print_id, EGISMOC_FINGERPRINT_DATA_SIZE);
395
396 48 fpi_print_fill_from_user_id (print, fill_user_id);
397
398 48 fpi_print_set_type (print, FPI_PRINT_RAW);
399 48 fpi_print_set_device_stored (print, TRUE);
400
401 48 g_object_set (print, "description", fill_user_id, NULL);
402
403 48 print_id_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
404 device_print_id,
405 EGISMOC_FINGERPRINT_DATA_SIZE,
406 sizeof (guchar));
407 48 fpi_data = g_variant_new ("(@ay)", print_id_var);
408 48 g_object_set (print, "fpi-data", fpi_data, NULL);
409 48 }
410
411 static GPtrArray *
412 28 egismoc_get_enrolled_prints (FpDevice *device)
413 {
414 28 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
415
416 28 g_autoptr(GPtrArray) result = g_ptr_array_new_with_free_func (g_object_unref);
417
418
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (!self->enrolled_ids)
419 return g_steal_pointer (&result);
420
421
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 28 times.
60 for (guint i = 0; i < self->enrolled_ids->len; i++)
422 {
423 32 FpPrint *print = fp_print_new (device);
424 32 egismoc_set_print_data (print, g_ptr_array_index (self->enrolled_ids, i), NULL);
425 32 g_ptr_array_add (result, g_object_ref_sink (print));
426 }
427
428 return g_steal_pointer (&result);
429 }
430
431 static void
432 60 egismoc_list_fill_enrolled_ids_cb (FpDevice *device,
433 guchar *buffer_in,
434 gsize length_in,
435 GError *error)
436 {
437 60 fp_dbg ("List callback");
438 60 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
439
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (error)
441 {
442 fpi_ssm_mark_failed (self->task_ssm, error);
443 return;
444 }
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 g_clear_pointer (&self->enrolled_ids, g_ptr_array_unref);
447 60 self->enrolled_ids = g_ptr_array_new_with_free_func (g_free);
448
449 60 FpiByteReader reader;
450 60 gboolean read = TRUE;
451
452 60 fpi_byte_reader_init (&reader, buffer_in, length_in);
453
454 60 read &= fpi_byte_reader_set_pos (&reader, EGISMOC_LIST_RESPONSE_PREFIX_SIZE);
455
456 /*
457 * Each fingerprint ID will be returned in this response as a 32 byte array
458 * The other stuff in the payload is 16 bytes long, so if there is at least 1
459 * print then the length should be at least 16+32=48 bytes long
460 */
461
1/2
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
132 while (read)
462 {
463 132 const guint8 *data;
464 132 g_autofree gchar *print_id = NULL;
465
466
2/2
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 72 times.
132 read &= fpi_byte_reader_get_data (&reader, EGISMOC_FINGERPRINT_DATA_SIZE,
467 &data);
468
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 60 times.
132 if (!read)
469 break;
470
471 72 print_id = g_strndup ((gchar *) data, EGISMOC_FINGERPRINT_DATA_SIZE);
472 72 fp_dbg ("Device fingerprint %0d: %.*s", self->enrolled_ids->len + 1,
473 EGISMOC_FINGERPRINT_DATA_SIZE, print_id);
474 72 g_ptr_array_add (self->enrolled_ids, g_steal_pointer (&print_id));
475 }
476
477 60 fp_info ("Number of currently enrolled fingerprints on the device is %d",
478 self->enrolled_ids->len);
479
480
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 if (self->task_ssm)
481 60 fpi_ssm_next_state (self->task_ssm);
482 }
483
484 static void
485 56 egismoc_list_run_state (FpiSsm *ssm,
486 FpDevice *device)
487 {
488 112 g_autoptr(GPtrArray) enrolled_prints = NULL;
489
490
2/3
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
56 switch (fpi_ssm_get_cur_state (ssm))
491 {
492 28 case LIST_GET_ENROLLED_IDS:
493 28 egismoc_exec_cmd (device, cmd_list, cmd_list_len, NULL,
494 egismoc_list_fill_enrolled_ids_cb);
495 28 break;
496
497 28 case LIST_RETURN_ENROLLED_PRINTS:
498 28 enrolled_prints = egismoc_get_enrolled_prints (device);
499 28 fpi_device_list_complete (device, g_steal_pointer (&enrolled_prints), NULL);
500 28 fpi_ssm_next_state (ssm);
501 28 break;
502 }
503 56 }
504
505 static void
506 28 egismoc_list (FpDevice *device)
507 {
508 28 fp_dbg ("List");
509 28 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
510
511
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 g_assert (self->task_ssm == NULL);
512 28 self->task_ssm = fpi_ssm_new (device,
513 egismoc_list_run_state,
514 LIST_STATES);
515 28 fpi_ssm_start (self->task_ssm, egismoc_task_ssm_done);
516 28 }
517
518 static guchar *
519 12 egismoc_get_delete_cmd (FpDevice *device,
520 FpPrint *delete_print,
521 gsize *length_out)
522 {
523 12 fp_dbg ("Get delete command");
524 12 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
525 24 g_auto(FpiByteWriter) writer = {0};
526 12 g_autoptr(GVariant) print_data = NULL;
527
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 g_autoptr(GVariant) print_data_id_var = NULL;
528 12 const guchar *print_data_id = NULL;
529 12 gsize print_data_id_len = 0;
530
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 g_autofree gchar *print_description = NULL;
531 12 g_autofree guchar *enrolled_print_id = NULL;
532 12 g_autofree guchar *result = NULL;
533 12 gboolean written = TRUE;
534
535 /*
536 * The final command body should contain:
537 * 1) hard-coded 00 00
538 * 2) 2-byte size indiciator, 20*Number deleted identifiers plus 7 in form of:
539 * num_to_delete * 0x20 + 0x07
540 * Since max prints can be higher than 7 then this goes up to 2 bytes
541 * (e9 + 9 = 109)
542 * 3) Hard-coded prefix (cmd_delete_prefix)
543 * 4) 2-byte size indiciator, 20*Number of enrolled identifiers without plus 7
544 * (num_to_delete * 0x20)
545 * 5) All of the currently registered prints to delete in their 32-byte device
546 * identifiers (enrolled_list)
547 */
548
549 12 int num_to_delete = 0;
550
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if (delete_print)
551 num_to_delete = 1;
552
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 else if (self->enrolled_ids)
553 8 num_to_delete = self->enrolled_ids->len;
554
555 12 const gsize body_length = sizeof (guchar) * EGISMOC_FINGERPRINT_DATA_SIZE *
556 num_to_delete;
557 /* total_length is the 6 various bytes plus prefix and body payload */
558 12 const gsize total_length = (sizeof (guchar) * 6) + cmd_delete_prefix_len +
559 body_length;
560
561 /* pre-fill entire payload with 00s */
562 12 fpi_byte_writer_init_with_size (&writer, total_length, TRUE);
563
564 /* start with 00 00 (just move starting offset up by 2) */
565 12 written &= fpi_byte_writer_set_pos (&writer, 2);
566
567 /* Size Counter bytes */
568 /* "easiest" way to handle 2-bytes size for counter is to hard-code logic for
569 * when we go to the 2nd byte
570 * note this will not work in case any model ever supports more than 14 prints
571 * (assumed max is 10) */
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (num_to_delete > 7)
573 {
574 written &= fpi_byte_writer_put_uint8 (&writer, 0x01);
575 written &= fpi_byte_writer_put_uint8 (&writer, ((num_to_delete - 8) * 0x20) + 0x07);
576 }
577 else
578 {
579 /* first byte is 0x00, just skip it */
580 12 written &= fpi_byte_writer_change_pos (&writer, 1);
581
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 written &= fpi_byte_writer_put_uint8 (&writer, (num_to_delete * 0x20) + 0x07);
582 }
583
584 /* command prefix */
585
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 written &= fpi_byte_writer_put_data (&writer, cmd_delete_prefix,
586 cmd_delete_prefix_len);
587
588 /* 2-bytes size logic for counter again */
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (num_to_delete > 7)
590 {
591 written &= fpi_byte_writer_put_uint8 (&writer, 0x01);
592 written &= fpi_byte_writer_put_uint8 (&writer, (num_to_delete - 8) * 0x20);
593 }
594 else
595 {
596 /* first byte is 0x00, just skip it */
597 12 written &= fpi_byte_writer_change_pos (&writer, 1);
598
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 written &= fpi_byte_writer_put_uint8 (&writer, num_to_delete * 0x20);
599 }
600
601 /* append desired 32-byte fingerprint IDs */
602 /* if passed a delete_print then fetch its data from the FpPrint */
603
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (delete_print)
604 {
605 4 g_object_get (delete_print, "description", &print_description, NULL);
606 4 g_object_get (delete_print, "fpi-data", &print_data, NULL);
607
608
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!g_variant_check_format_string (print_data, "(@ay)", FALSE))
609 {
610 fpi_ssm_mark_failed (self->task_ssm,
611 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
612 return NULL;
613 }
614
615 4 g_variant_get (print_data, "(@ay)", &print_data_id_var);
616 4 print_data_id = g_variant_get_fixed_array (print_data_id_var,
617 &print_data_id_len, sizeof (guchar));
618
619
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
4 if (!g_str_has_prefix (print_description, "FP"))
620 fp_dbg ("Fingerprint '%s' was not created by libfprint; deleting anyway.",
621 print_description);
622
623 4 fp_info ("Delete fingerprint %s (%s)", print_description, print_data_id);
624
625
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 written &= fpi_byte_writer_put_data (&writer, print_data_id,
626 EGISMOC_FINGERPRINT_DATA_SIZE);
627 }
628 /* Otherwise assume this is a "clear" - just loop through and append all enrolled IDs */
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 else if (self->enrolled_ids)
630 {
631
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
24 for (guint i = 0; i < self->enrolled_ids->len && written; i++)
632 {
633
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 written &= fpi_byte_writer_put_data (&writer,
634 g_ptr_array_index (self->enrolled_ids, i),
635 EGISMOC_FINGERPRINT_DATA_SIZE);
636 }
637 }
638
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 g_assert (written);
640
641
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (length_out)
642 12 *length_out = total_length;
643
644 12 return fpi_byte_writer_reset_and_get_data (&writer);
645 }
646
647 static void
648 12 egismoc_delete_cb (FpDevice *device,
649 guchar *buffer_in,
650 gsize length_in,
651 GError *error)
652 {
653 12 fp_dbg ("Delete callback");
654 12 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
655
656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (error)
657 {
658 fpi_ssm_mark_failed (self->task_ssm, error);
659 return;
660 }
661
662 /* Check that the read payload indicates "success" with the delete */
663
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (egismoc_validate_response_prefix (buffer_in,
664 length_in,
665 rsp_delete_success_prefix,
666 rsp_delete_success_prefix_len))
667 {
668
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 4 times.
12 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_CLEAR_STORAGE)
669 {
670 8 fpi_device_clear_storage_complete (device, NULL);
671 8 fpi_ssm_next_state (self->task_ssm);
672 }
673
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 else if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_DELETE)
674 {
675 4 fpi_device_delete_complete (device, NULL);
676 4 fpi_ssm_next_state (self->task_ssm);
677 }
678 else
679 {
680 fpi_ssm_mark_failed (self->task_ssm,
681 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
682 "Unsupported delete action."));
683 }
684 }
685 else
686 {
687 fpi_ssm_mark_failed (self->task_ssm,
688 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
689 "Delete print was not successful"));
690 }
691 }
692
693 static void
694 24 egismoc_delete_run_state (FpiSsm *ssm,
695 FpDevice *device)
696 {
697 48 g_autofree guchar *payload = NULL;
698 24 gsize payload_length = 0;
699
700
2/3
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 switch (fpi_ssm_get_cur_state (ssm))
701 {
702 12 case DELETE_GET_ENROLLED_IDS:
703 /* get enrolled_ids from device for use building delete payload below */
704 12 egismoc_exec_cmd (device, cmd_list, cmd_list_len, NULL,
705 egismoc_list_fill_enrolled_ids_cb);
706 12 break;
707
708 12 case DELETE_DELETE:
709
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
12 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_DELETE)
710 4 payload = egismoc_get_delete_cmd (device, fpi_ssm_get_data (ssm),
711 &payload_length);
712 else
713 8 payload = egismoc_get_delete_cmd (device, NULL, &payload_length);
714
715 12 egismoc_exec_cmd (device, g_steal_pointer (&payload), payload_length,
716 g_free, egismoc_delete_cb);
717 12 break;
718 }
719 24 }
720
721 static void
722 8 egismoc_clear_storage (FpDevice *device)
723 {
724 8 fp_dbg ("Clear storage");
725 8 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
726
727
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 g_assert (self->task_ssm == NULL);
728 8 self->task_ssm = fpi_ssm_new (device,
729 egismoc_delete_run_state,
730 DELETE_STATES);
731 8 fpi_ssm_start (self->task_ssm, egismoc_task_ssm_done);
732 8 }
733
734 static void
735 4 egismoc_delete (FpDevice *device)
736 {
737 4 fp_dbg ("Delete");
738 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
739 4 FpPrint *delete_print = NULL;
740
741 4 fpi_device_get_delete_data (device, &delete_print);
742
743
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 g_assert (self->task_ssm == NULL);
744 4 self->task_ssm = fpi_ssm_new (device,
745 egismoc_delete_run_state,
746 DELETE_STATES);
747 /* the print is owned by libfprint during deletion task */
748 4 fpi_ssm_set_data (self->task_ssm, delete_print, NULL);
749 4 fpi_ssm_start (self->task_ssm, egismoc_task_ssm_done);
750 4 }
751
752 static void
753 155 egismoc_enroll_status_report (FpDevice *device,
754 EnrollPrint *enroll_print,
755 EnrollStatus status,
756 GError *error)
757 {
758 155 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
759
760
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
151 switch (status)
761 {
762 case ENROLL_STATUS_DEVICE_FULL:
763 case ENROLL_STATUS_DUPLICATE:
764 4 fpi_ssm_mark_failed (self->task_ssm, error);
765 break;
766
767 23 case ENROLL_STATUS_RETRY:
768 23 fpi_device_enroll_progress (device, enroll_print->stage, NULL, error);
769 23 break;
770
771 120 case ENROLL_STATUS_PARTIAL_OK:
772 120 enroll_print->stage++;
773 120 fp_info ("Partial capture successful. Please touch the sensor again (%d/%d)",
774 enroll_print->stage,
775 self->max_enroll_stages);
776 120 fpi_device_enroll_progress (device, enroll_print->stage, enroll_print->print, NULL);
777 120 break;
778
779 8 case ENROLL_STATUS_COMPLETE:
780 8 fp_info ("Enrollment was successful!");
781 8 fpi_device_enroll_complete (device, g_object_ref (enroll_print->print), NULL);
782 8 break;
783
784 default:
785 if (error)
786 fpi_ssm_mark_failed (self->task_ssm, error);
787 else
788 fpi_ssm_mark_failed (self->task_ssm,
789 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
790 "Unknown error"));
791 }
792 151 }
793
794 static void
795 143 egismoc_read_capture_cb (FpDevice *device,
796 guchar *buffer_in,
797 gsize length_in,
798 GError *error)
799 {
800 143 fp_dbg ("Read capture callback");
801 143 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
802 143 EnrollPrint *enroll_print = fpi_ssm_get_data (self->task_ssm);
803
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 if (error)
805 {
806 fpi_ssm_mark_failed (self->task_ssm, error);
807 return;
808 }
809
810 /* Check that the read payload indicates "success" */
811
2/2
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 1 times.
143 if (egismoc_validate_response_prefix (buffer_in,
812 length_in,
813 rsp_read_success_prefix,
814
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 22 times.
142 rsp_read_success_prefix_len) &&
815 142 egismoc_validate_response_suffix (buffer_in,
816 length_in,
817 rsp_read_success_suffix,
818 rsp_read_success_suffix_len))
819 {
820 120 egismoc_enroll_status_report (device, enroll_print,
821 ENROLL_STATUS_PARTIAL_OK, NULL);
822 }
823 else
824 {
825 /* If not success then the sensor can either report "off center" or "sensor is dirty" */
826
827 /* "Off center" */
828
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 1 times.
23 if (egismoc_validate_response_prefix (buffer_in,
829 length_in,
830 rsp_read_offcenter_prefix,
831
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 rsp_read_offcenter_prefix_len) &&
832 22 egismoc_validate_response_suffix (buffer_in,
833 length_in,
834 rsp_read_offcenter_suffix,
835 rsp_read_offcenter_suffix_len))
836 22 error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER);
837
838 /* "Sensor is dirty" */
839
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 else if (egismoc_validate_response_prefix (buffer_in,
840 length_in,
841 rsp_read_dirty_prefix,
842 rsp_read_dirty_prefix_len))
843 1 error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
844 "Your device is having trouble recognizing you. "
845 "Make sure your sensor is clean.");
846
847 else
848 error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
849 "Unknown failure trying to read your finger. "
850 "Please try again.");
851
852 23 egismoc_enroll_status_report (device, enroll_print, ENROLL_STATUS_RETRY, error);
853 }
854
855
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 135 times.
143 if (enroll_print->stage == self->max_enroll_stages)
856 8 fpi_ssm_next_state (self->task_ssm);
857 else
858 135 fpi_ssm_jump_to_state (self->task_ssm, ENROLL_CAPTURE_SENSOR_RESET);
859 }
860
861 static void
862 12 egismoc_enroll_check_cb (FpDevice *device,
863 guchar *buffer_in,
864 gsize length_in,
865 GError *error)
866 {
867 12 fp_dbg ("Enroll check callback");
868 12 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
869
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (error)
871 {
872 fpi_ssm_mark_failed (self->task_ssm, error);
873 return;
874 }
875
876 /* Check that the read payload reports "not yet enrolled" */
877
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 4 times.
12 if (egismoc_validate_response_suffix (buffer_in,
878 length_in,
879 rsp_check_not_yet_enrolled_suffix,
880 rsp_check_not_yet_enrolled_suffix_len))
881 8 fpi_ssm_next_state (self->task_ssm);
882 else
883 4 egismoc_enroll_status_report (device, NULL, ENROLL_STATUS_DUPLICATE,
884 fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE));
885 }
886
887 /*
888 * Builds the full "check" payload which includes identifiers for all
889 * fingerprints which currently should exist on the storage. This payload is
890 * used during both enrollment and verify actions.
891 */
892 static guchar *
893 20 egismoc_get_check_cmd (FpDevice *device,
894 gsize *length_out)
895 {
896 20 fp_dbg ("Get check command");
897 20 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
898 40 g_auto(FpiByteWriter) writer = {0};
899 20 g_autofree guchar *result = NULL;
900 20 gboolean written = TRUE;
901
902 /*
903 * The final command body should contain:
904 * 1) hard-coded 00 00
905 * 2) 2-byte size indiciator, 20*Number enrolled identifiers plus 9 in form of:
906 * (enrolled_ids->len + 1) * 0x20 + 0x09
907 * Since max prints can be higher than 7 then this goes up to 2 bytes
908 * (e9 + 9 = 109)
909 * 3) Hard-coded prefix (cmd_check_prefix)
910 * 4) 2-byte size indiciator, 20*Number of enrolled identifiers without plus 9
911 * ((enrolled_ids->len + 1) * 0x20)
912 * 5) Hard-coded 32 * 0x00 bytes
913 * 6) All of the currently registered prints in their 32-byte device identifiers
914 * (enrolled_list)
915 * 7) Hard-coded suffix (cmd_check_suffix)
916 */
917
918
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 g_assert (self->enrolled_ids);
919 20 const gsize body_length = sizeof (guchar) * self->enrolled_ids->len *
920 EGISMOC_FINGERPRINT_DATA_SIZE;
921
922 /* prefix length can depend on the type */
923 20 const gsize check_prefix_length = (fpi_device_get_driver_data (device) &
924 EGISMOC_DRIVER_CHECK_PREFIX_TYPE2) ?
925
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 15 times.
20 cmd_check_prefix_type2_len :
926 cmd_check_prefix_type1_len;
927
928 /* total_length is the 6 various bytes plus all other prefixes/suffixes and
929 * the body payload */
930 20 const gsize total_length = (sizeof (guchar) * 6)
931 + check_prefix_length
932 + EGISMOC_CMD_CHECK_SEPARATOR_LENGTH
933 20 + body_length
934 20 + cmd_check_suffix_len;
935
936 /* pre-fill entire payload with 00s */
937 20 fpi_byte_writer_init_with_size (&writer, total_length, TRUE);
938
939 /* start with 00 00 (just move starting offset up by 2) */
940 20 written &= fpi_byte_writer_set_pos (&writer, 2);
941
942 /* Size Counter bytes */
943 /* "easiest" way to handle 2-bytes size for counter is to hard-code logic for
944 * when we go to the 2nd byte
945 * note this will not work in case any model ever supports more than 14 prints
946 * (assumed max is 10) */
947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (self->enrolled_ids->len > 6)
948 {
949 written &= fpi_byte_writer_put_uint8 (&writer, 0x01);
950 written &= fpi_byte_writer_put_uint8 (&writer,
951 ((self->enrolled_ids->len - 7) * 0x20)
952 + 0x09);
953 }
954 else
955 {
956 /* first byte is 0x00, just skip it */
957 20 written &= fpi_byte_writer_change_pos (&writer, 1);
958
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 written &= fpi_byte_writer_put_uint8 (&writer,
959 ((self->enrolled_ids->len + 1) * 0x20) +
960 0x09);
961 }
962
963 /* command prefix */
964
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 15 times.
20 if (fpi_device_get_driver_data (device) & EGISMOC_DRIVER_CHECK_PREFIX_TYPE2)
965
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 written &= fpi_byte_writer_put_data (&writer, cmd_check_prefix_type2,
966 cmd_check_prefix_type2_len);
967 else
968
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 written &= fpi_byte_writer_put_data (&writer, cmd_check_prefix_type1,
969 cmd_check_prefix_type1_len);
970
971 /* 2-bytes size logic for counter again */
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (self->enrolled_ids->len > 6)
973 {
974 written &= fpi_byte_writer_put_uint8 (&writer, 0x01);
975 written &= fpi_byte_writer_put_uint8 (&writer,
976 (self->enrolled_ids->len - 7) * 0x20);
977 }
978 else
979 {
980 /* first byte is 0x00, just skip it */
981 20 written &= fpi_byte_writer_change_pos (&writer, 1);
982
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 written &= fpi_byte_writer_put_uint8 (&writer,
983 (self->enrolled_ids->len + 1) * 0x20);
984 }
985
986 /* add 00s "separator" to offset position */
987 20 written &= fpi_byte_writer_change_pos (&writer,
988 EGISMOC_CMD_CHECK_SEPARATOR_LENGTH);
989
990
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
36 for (guint i = 0; i < self->enrolled_ids->len && written; i++)
991 {
992
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 written &= fpi_byte_writer_put_data (&writer,
993 g_ptr_array_index (self->enrolled_ids, i),
994 EGISMOC_FINGERPRINT_DATA_SIZE);
995 }
996
997 /* command suffix */
998
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 written &= fpi_byte_writer_put_data (&writer, cmd_check_suffix,
999 cmd_check_suffix_len);
1000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 g_assert (written);
1001
1002
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (length_out)
1003 20 *length_out = total_length;
1004
1005 20 return fpi_byte_writer_reset_and_get_data (&writer);
1006 }
1007
1008 static void
1009 696 egismoc_enroll_run_state (FpiSsm *ssm,
1010 FpDevice *device)
1011 {
1012 696 g_auto(FpiByteWriter) writer = {0};
1013 696 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1014 696 EnrollPrint *enroll_print = fpi_ssm_get_data (ssm);
1015 696 g_autofree guchar *payload = NULL;
1016 696 gsize payload_length = 0;
1017 696 g_autofree gchar *device_print_id = NULL;
1018 696 g_autofree gchar *user_id = NULL;
1019
1020
16/17
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 143 times.
✓ Branch 11 taken 143 times.
✓ Branch 12 taken 143 times.
✓ Branch 13 taken 143 times.
✓ Branch 14 taken 8 times.
✓ Branch 15 taken 8 times.
✓ Branch 16 taken 8 times.
✓ Branch 17 taken 8 times.
696 switch (fpi_ssm_get_cur_state (ssm))
1021 {
1022 12 case ENROLL_GET_ENROLLED_IDS:
1023 /* get enrolled_ids from device for use in check stages below */
1024 12 egismoc_exec_cmd (device, cmd_list, cmd_list_len,
1025 NULL, egismoc_list_fill_enrolled_ids_cb);
1026 12 break;
1027
1028 12 case ENROLL_CHECK_ENROLLED_NUM:
1029
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (self->enrolled_ids->len >= EGISMOC_MAX_ENROLL_NUM)
1030 {
1031 egismoc_enroll_status_report (device, enroll_print, ENROLL_STATUS_DEVICE_FULL,
1032 fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL));
1033 return;
1034 }
1035 12 fpi_ssm_next_state (ssm);
1036 12 break;
1037
1038 12 case ENROLL_SENSOR_RESET:
1039 12 egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
1040 NULL, egismoc_task_ssm_next_state_cb);
1041 12 break;
1042
1043 12 case ENROLL_SENSOR_ENROLL:
1044 12 egismoc_exec_cmd (device, cmd_sensor_enroll, cmd_sensor_enroll_len,
1045 NULL, egismoc_task_ssm_next_state_cb);
1046 12 break;
1047
1048 12 case ENROLL_WAIT_FINGER:
1049 12 egismoc_wait_finger_on_sensor (ssm, device);
1050 12 break;
1051
1052 12 case ENROLL_SENSOR_CHECK:
1053 12 egismoc_exec_cmd (device, cmd_sensor_check, cmd_sensor_check_len,
1054 NULL, egismoc_task_ssm_next_state_cb);
1055 12 break;
1056
1057 12 case ENROLL_CHECK:
1058 12 payload = egismoc_get_check_cmd (device, &payload_length);
1059 12 egismoc_exec_cmd (device, g_steal_pointer (&payload), payload_length,
1060 g_free, egismoc_enroll_check_cb);
1061 12 break;
1062
1063 8 case ENROLL_START:
1064 8 egismoc_exec_cmd (device, cmd_enroll_starting, cmd_enroll_starting_len,
1065 NULL, egismoc_task_ssm_next_state_cb);
1066 8 break;
1067
1068 143 case ENROLL_CAPTURE_SENSOR_RESET:
1069 143 egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
1070 NULL, egismoc_task_ssm_next_state_cb);
1071 143 break;
1072
1073 143 case ENROLL_CAPTURE_SENSOR_START_CAPTURE:
1074 143 egismoc_exec_cmd (device, cmd_sensor_start_capture, cmd_sensor_start_capture_len,
1075 NULL,
1076 egismoc_task_ssm_next_state_cb);
1077 143 break;
1078
1079 143 case ENROLL_CAPTURE_WAIT_FINGER:
1080 143 egismoc_wait_finger_on_sensor (ssm, device);
1081 143 break;
1082
1083 143 case ENROLL_CAPTURE_READ_RESPONSE:
1084 143 egismoc_exec_cmd (device, cmd_read_capture, cmd_read_capture_len,
1085 NULL, egismoc_read_capture_cb);
1086 143 break;
1087
1088 8 case ENROLL_COMMIT_START:
1089 8 egismoc_exec_cmd (device, cmd_commit_starting, cmd_commit_starting_len,
1090 NULL, egismoc_task_ssm_next_state_cb);
1091 8 break;
1092
1093 8 case ENROLL_COMMIT:
1094 8 user_id = fpi_print_generate_user_id (enroll_print->print);
1095 8 fp_dbg ("New fingerprint ID: %s", user_id);
1096
1097 8 device_print_id = g_strndup (user_id, EGISMOC_FINGERPRINT_DATA_SIZE);
1098 8 egismoc_set_print_data (enroll_print->print, device_print_id, user_id);
1099
1100 8 fpi_byte_writer_init (&writer);
1101
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (!fpi_byte_writer_put_data (&writer, cmd_new_print_prefix,
1102 cmd_new_print_prefix_len))
1103 {
1104 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
1105 break;
1106 }
1107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (!fpi_byte_writer_put_data (&writer, (guint8 *) device_print_id,
1108 EGISMOC_FINGERPRINT_DATA_SIZE))
1109 {
1110 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
1111 break;
1112 }
1113
1114 8 payload_length = fpi_byte_writer_get_size (&writer);
1115 8 egismoc_exec_cmd (device, fpi_byte_writer_reset_and_get_data (&writer),
1116 payload_length,
1117 g_free, egismoc_task_ssm_next_state_cb);
1118 8 break;
1119
1120 8 case ENROLL_COMMIT_SENSOR_RESET:
1121 8 egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
1122 NULL, egismoc_task_ssm_next_state_cb);
1123 8 break;
1124
1125 8 case ENROLL_COMPLETE:
1126 8 egismoc_enroll_status_report (device, enroll_print, ENROLL_STATUS_COMPLETE, NULL);
1127 8 fpi_ssm_next_state (ssm);
1128 8 break;
1129 }
1130 }
1131
1132 static void
1133 12 egismoc_enroll (FpDevice *device)
1134 {
1135 12 fp_dbg ("Enroll");
1136 12 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1137 12 EnrollPrint *enroll_print = g_new0 (EnrollPrint, 1);
1138
1139 12 fpi_device_get_enroll_data (device, &enroll_print->print);
1140 12 enroll_print->stage = 0;
1141
1142
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 g_assert (self->task_ssm == NULL);
1143 12 self->task_ssm = fpi_ssm_new (device, egismoc_enroll_run_state, ENROLL_STATES);
1144 12 fpi_ssm_set_data (self->task_ssm, g_steal_pointer (&enroll_print), g_free);
1145 12 fpi_ssm_start (self->task_ssm, egismoc_task_ssm_done);
1146 12 }
1147
1148 static void
1149 8 egismoc_identify_check_cb (FpDevice *device,
1150 guchar *buffer_in,
1151 gsize length_in,
1152 GError *error)
1153 {
1154 8 fp_dbg ("Identify check callback");
1155 8 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1156 8 gchar device_print_id[EGISMOC_FINGERPRINT_DATA_SIZE];
1157 8 FpPrint *print = NULL;
1158 8 FpPrint *verify_print = NULL;
1159 8 GPtrArray *prints;
1160 8 gboolean found = FALSE;
1161 8 guint index;
1162
1163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (error)
1164 {
1165 fpi_ssm_mark_failed (self->task_ssm, error);
1166 return;
1167 }
1168
1169 /* Check that the read payload indicates "match" */
1170
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (egismoc_validate_response_suffix (buffer_in,
1171 length_in,
1172 rsp_identify_match_suffix,
1173 rsp_identify_match_suffix_len))
1174 {
1175 /*
1176 On success, there is a 32 byte array of "something"(?) in chars 14-45
1177 and then the 32 byte array ID of the matched print comes as chars 46-77
1178 */
1179 8 memcpy (device_print_id,
1180 buffer_in + EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET,
1181 EGISMOC_FINGERPRINT_DATA_SIZE);
1182
1183 /* Create a new print from this device_print_id and then see if it matches
1184 * the one indicated
1185 */
1186 8 print = fp_print_new (device);
1187 8 egismoc_set_print_data (print, device_print_id, NULL);
1188
1189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!print)
1190 {
1191 fpi_ssm_mark_failed (self->task_ssm,
1192 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
1193 "Failed to build a print from "
1194 "device response."));
1195 return;
1196 }
1197
1198 8 fp_info ("Identify successful for: %s", fp_print_get_description (print));
1199
1200
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
1201 {
1202 4 fpi_device_get_identify_data (device, &prints);
1203 4 found = g_ptr_array_find_with_equal_func (prints,
1204 print,
1205 (GEqualFunc) fp_print_equal,
1206 &index);
1207
1208
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (found)
1209 4 fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
1210 else
1211 fpi_device_identify_report (device, NULL, print, NULL);
1212 }
1213 else
1214 {
1215 4 fpi_device_get_verify_data (device, &verify_print);
1216 4 fp_info ("Verifying against: %s", fp_print_get_description (verify_print));
1217
1218
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (fp_print_equal (verify_print, print))
1219 4 fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
1220 else
1221 fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
1222 }
1223 }
1224 /* If device was successfully read but it was a "not matched" */
1225 else if (egismoc_validate_response_suffix (buffer_in,
1226 length_in,
1227 rsp_identify_notmatch_suffix,
1228 rsp_identify_notmatch_suffix_len))
1229 {
1230 fp_info ("Print was not identified by the device");
1231
1232 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
1233 fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
1234 else
1235 fpi_device_identify_report (device, NULL, NULL, NULL);
1236 }
1237 else
1238 {
1239 fpi_ssm_mark_failed (self->task_ssm,
1240 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1241 "Unrecognized response from device."));
1242 return;
1243 }
1244
1245 8 fpi_ssm_next_state (self->task_ssm);
1246 }
1247
1248 static void
1249 72 egismoc_identify_run_state (FpiSsm *ssm,
1250 FpDevice *device)
1251 {
1252 72 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1253 72 g_autofree guchar *payload = NULL;
1254 72 gsize payload_length = 0;
1255
1256
9/10
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
72 switch (fpi_ssm_get_cur_state (ssm))
1257 {
1258 8 case IDENTIFY_GET_ENROLLED_IDS:
1259 /* get enrolled_ids from device for use in check stages below */
1260 8 egismoc_exec_cmd (device, cmd_list, cmd_list_len,
1261 NULL, egismoc_list_fill_enrolled_ids_cb);
1262 8 break;
1263
1264 8 case IDENTIFY_CHECK_ENROLLED_NUM:
1265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (self->enrolled_ids->len == 0)
1266 {
1267 fpi_ssm_mark_failed (g_steal_pointer (&self->task_ssm),
1268 fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
1269 return;
1270 }
1271 8 fpi_ssm_next_state (ssm);
1272 8 break;
1273
1274 8 case IDENTIFY_SENSOR_RESET:
1275 8 egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
1276 NULL, egismoc_task_ssm_next_state_cb);
1277 8 break;
1278
1279 8 case IDENTIFY_SENSOR_IDENTIFY:
1280 8 egismoc_exec_cmd (device, cmd_sensor_identify, cmd_sensor_identify_len,
1281 NULL, egismoc_task_ssm_next_state_cb);
1282 8 break;
1283
1284 8 case IDENTIFY_WAIT_FINGER:
1285 8 egismoc_wait_finger_on_sensor (ssm, device);
1286 8 break;
1287
1288 8 case IDENTIFY_SENSOR_CHECK:
1289 8 egismoc_exec_cmd (device, cmd_sensor_check, cmd_sensor_check_len,
1290 NULL, egismoc_task_ssm_next_state_cb);
1291 8 break;
1292
1293 8 case IDENTIFY_CHECK:
1294 8 payload = egismoc_get_check_cmd (device, &payload_length);
1295 8 egismoc_exec_cmd (device, g_steal_pointer (&payload), payload_length,
1296 g_free, egismoc_identify_check_cb);
1297 8 break;
1298
1299 8 case IDENTIFY_COMPLETE_SENSOR_RESET:
1300 8 egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
1301 NULL, egismoc_task_ssm_next_state_cb);
1302 8 break;
1303
1304 /*
1305 * In Windows, the driver seems at this point to then immediately take
1306 * another read from the sensor; this is suspected to be an on-chip
1307 * "verify". However, because the user's finger is still on the sensor from
1308 * the identify, then it seems to always return positive. We will consider
1309 * this extra step unnecessary and just skip it in this driver. This driver
1310 * will instead handle matching of the FpPrint from the gallery in the
1311 * "verify" case of the callback egismoc_identify_check_cb.
1312 */
1313 8 case IDENTIFY_COMPLETE:
1314
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
1315 4 fpi_device_identify_complete (device, NULL);
1316 else
1317 4 fpi_device_verify_complete (device, NULL);
1318
1319 8 fpi_ssm_mark_completed (ssm);
1320 8 break;
1321 }
1322 }
1323
1324 static void
1325 8 egismoc_identify_verify (FpDevice *device)
1326 {
1327 8 fp_dbg ("Identify or Verify");
1328 8 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1329
1330
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 g_assert (self->task_ssm == NULL);
1331 8 self->task_ssm = fpi_ssm_new (device, egismoc_identify_run_state, IDENTIFY_STATES);
1332 8 fpi_ssm_start (self->task_ssm, egismoc_task_ssm_done);
1333 8 }
1334
1335 static void
1336 4 egismoc_fw_version_cb (FpDevice *device,
1337 guchar *buffer_in,
1338 gsize length_in,
1339 GError *error)
1340 {
1341 4 fp_dbg ("Firmware version callback");
1342 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1343 4 g_autofree gchar *fw_version = NULL;
1344 4 gsize prefix_length;
1345 4 guchar *fw_version_start;
1346 4 gsize fw_version_length;
1347
1348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (error)
1349 {
1350 fpi_ssm_mark_failed (self->task_ssm, error);
1351 return;
1352 }
1353
1354 /* Check that the read payload indicates "success" */
1355
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!egismoc_validate_response_suffix (buffer_in,
1356 length_in,
1357 rsp_fw_version_suffix,
1358 rsp_fw_version_suffix_len))
1359 {
1360 fpi_ssm_mark_failed (self->task_ssm,
1361 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1362 "Device firmware response "
1363 "was not valid."));
1364 return;
1365 }
1366
1367 /*
1368 * FW Version is 12 bytes: a carriage return (0x0d) plus the version string
1369 * itself. Always skip [the read prefix] + [2 * check bytes] + [3 * 0x00] that
1370 * come with every payload Then we will also skip the carriage return and take
1371 * all but the last 2 bytes as the FW Version
1372 */
1373 4 prefix_length = egismoc_read_prefix_len + 2 + 3 + 1;
1374 4 fw_version_start = buffer_in + prefix_length;
1375 4 fw_version_length = length_in - prefix_length - rsp_fw_version_suffix_len;
1376 4 fw_version = g_strndup ((gchar *) fw_version_start, fw_version_length);
1377
1378 4 fp_info ("Device firmware version is %s", fw_version);
1379
1380 4 fpi_ssm_next_state (self->task_ssm);
1381 }
1382
1383 static void
1384 4 egismoc_dev_init_done (FpiSsm *ssm,
1385 FpDevice *device,
1386 GError *error)
1387 {
1388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (error)
1389 {
1390 g_usb_device_release_interface (
1391 fpi_device_get_usb_device (device), 0, 0, NULL);
1392 egismoc_task_ssm_done (ssm, device, error);
1393 return;
1394 }
1395
1396 4 egismoc_task_ssm_done (ssm, device, NULL);
1397 4 fpi_device_open_complete (device, NULL);
1398 }
1399
1400 static void
1401 24 egismoc_dev_init_handler (FpiSsm *ssm,
1402 FpDevice *device)
1403 {
1404 44 g_autoptr(FpiUsbTransfer) transfer = fpi_usb_transfer_new (device);
1405
1406
6/7
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
24 switch (fpi_ssm_get_cur_state (ssm))
1407 {
1408 4 case DEV_INIT_CONTROL1:
1409 4 fpi_usb_transfer_fill_control (transfer,
1410 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
1411 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
1412 G_USB_DEVICE_RECIPIENT_DEVICE,
1413 32, 0x0000, 4, 16);
1414 4 break;
1415
1416 4 case DEV_INIT_CONTROL2:
1417 4 fpi_usb_transfer_fill_control (transfer,
1418 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
1419 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
1420 G_USB_DEVICE_RECIPIENT_DEVICE,
1421 32, 0x0000, 4, 40);
1422 4 break;
1423
1424 4 case DEV_INIT_CONTROL3:
1425 4 fpi_usb_transfer_fill_control (transfer,
1426 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
1427 G_USB_DEVICE_REQUEST_TYPE_STANDARD,
1428 G_USB_DEVICE_RECIPIENT_DEVICE,
1429 0, 0x0000, 0, 2);
1430 4 break;
1431
1432 4 case DEV_INIT_CONTROL4:
1433 4 fpi_usb_transfer_fill_control (transfer,
1434 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
1435 G_USB_DEVICE_REQUEST_TYPE_STANDARD,
1436 G_USB_DEVICE_RECIPIENT_DEVICE,
1437 0, 0x0000, 0, 2);
1438 4 break;
1439
1440 4 case DEV_INIT_CONTROL5:
1441 4 fpi_usb_transfer_fill_control (transfer,
1442 G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
1443 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
1444 G_USB_DEVICE_RECIPIENT_DEVICE,
1445 82, 0x0000, 0, 8);
1446 4 break;
1447
1448 4 case DEV_GET_FW_VERSION:
1449 4 egismoc_exec_cmd (device, cmd_fw_version, cmd_fw_version_len,
1450 NULL, egismoc_fw_version_cb);
1451
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return;
1452
1453 default:
1454 g_assert_not_reached ();
1455 }
1456
1457 20 transfer->ssm = ssm;
1458 20 transfer->short_is_error = TRUE;
1459 20 fpi_usb_transfer_submit (g_steal_pointer (&transfer),
1460 EGISMOC_USB_CONTROL_TIMEOUT,
1461 fpi_device_get_cancellable (device),
1462 fpi_ssm_usb_transfer_cb,
1463 NULL);
1464 }
1465
1466 static void
1467 4 egismoc_probe (FpDevice *device)
1468 {
1469 4 GUsbDevice *usb_dev;
1470 4 GError *error = NULL;
1471 4 g_autofree gchar *serial = NULL;
1472 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1473
1474 4 fp_dbg ("%s enter --> ", G_STRFUNC);
1475
1476 /* Claim usb interface */
1477 4 usb_dev = fpi_device_get_usb_device (device);
1478
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!g_usb_device_open (usb_dev, &error))
1479 {
1480 fp_dbg ("%s g_usb_device_open failed %s", G_STRFUNC, error->message);
1481 fpi_device_probe_complete (device, NULL, NULL, error);
1482 return;
1483 }
1484
1485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!g_usb_device_reset (usb_dev, &error))
1486 {
1487 fp_dbg ("%s g_usb_device_reset failed %s", G_STRFUNC, error->message);
1488 g_usb_device_close (usb_dev, NULL);
1489 fpi_device_probe_complete (device, NULL, NULL, error);
1490 return;
1491 }
1492
1493
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
1494 {
1495 fp_dbg ("%s g_usb_device_claim_interface failed %s", G_STRFUNC, error->message);
1496 g_usb_device_close (usb_dev, NULL);
1497 fpi_device_probe_complete (device, NULL, NULL, error);
1498 return;
1499 }
1500
1501
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
1502 4 serial = g_strdup ("emulated-device");
1503 else
1504 serial = g_usb_device_get_string_descriptor (usb_dev,
1505 g_usb_device_get_serial_number_index (usb_dev),
1506 &error);
1507
1508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (error)
1509 {
1510 fp_dbg ("%s g_usb_device_get_string_descriptor failed %s", G_STRFUNC, error->message);
1511 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)),
1512 0, 0, NULL);
1513 g_usb_device_close (usb_dev, NULL);
1514 fpi_device_probe_complete (device, NULL, NULL, error);
1515 return;
1516 }
1517
1518
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (fpi_device_get_driver_data (device) & EGISMOC_DRIVER_MAX_ENROLL_STAGES_20)
1519 2 self->max_enroll_stages = 20;
1520 else
1521 2 self->max_enroll_stages = EGISMOC_MAX_ENROLL_STAGES_DEFAULT;
1522
1523 4 fpi_device_set_nr_enroll_stages (device, self->max_enroll_stages);
1524
1525 4 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), 0, 0, NULL);
1526 4 g_usb_device_close (usb_dev, NULL);
1527
1528 4 fpi_device_probe_complete (device, serial, NULL, error);
1529 }
1530
1531 static void
1532 4 egismoc_open (FpDevice *device)
1533 {
1534 4 fp_dbg ("Opening device");
1535 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1536 4 GError *error = NULL;
1537
1538 4 self->interrupt_cancellable = g_cancellable_new ();
1539
1540
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
1541 {
1542 fpi_device_open_complete (device, error);
1543 return;
1544 }
1545
1546
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device),
1547 0, 0, &error))
1548 {
1549 fpi_device_open_complete (device, error);
1550 return;
1551 }
1552
1553
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 g_assert (self->task_ssm == NULL);
1554 4 self->task_ssm = fpi_ssm_new (device, egismoc_dev_init_handler, DEV_INIT_STATES);
1555 4 fpi_ssm_start (self->task_ssm, egismoc_dev_init_done);
1556 }
1557
1558 static void
1559 4 egismoc_cancel (FpDevice *device)
1560 {
1561 4 fp_dbg ("Cancel");
1562 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1563
1564 4 g_cancellable_cancel (self->interrupt_cancellable);
1565
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 g_clear_object (&self->interrupt_cancellable);
1566 4 self->interrupt_cancellable = g_cancellable_new ();
1567 4 }
1568
1569 static void
1570 egismoc_suspend (FpDevice *device)
1571 {
1572 fp_dbg ("Suspend");
1573
1574 egismoc_cancel (device);
1575 g_cancellable_cancel (fpi_device_get_cancellable (device));
1576 fpi_device_suspend_complete (device, NULL);
1577 }
1578
1579 static void
1580 4 egismoc_close (FpDevice *device)
1581 {
1582 4 fp_dbg ("Closing device");
1583 4 FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
1584 4 GError *error = NULL;
1585
1586 4 egismoc_cancel (device);
1587
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 g_clear_object (&self->interrupt_cancellable);
1588
1589 4 g_usb_device_release_interface (fpi_device_get_usb_device (device),
1590 0, 0, &error);
1591 4 fpi_device_close_complete (device, error);
1592 4 }
1593
1594 static void
1595 4 fpi_device_egismoc_init (FpiDeviceEgisMoc *self)
1596 {
1597 4 G_DEBUG_HERE ();
1598 4 }
1599
1600 static void
1601 120 fpi_device_egismoc_class_init (FpiDeviceEgisMocClass *klass)
1602 {
1603 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1604
1605 120 dev_class->id = FP_COMPONENT;
1606 120 dev_class->full_name = EGISMOC_DRIVER_FULLNAME;
1607
1608 120 dev_class->type = FP_DEVICE_TYPE_USB;
1609 120 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
1610 120 dev_class->id_table = egismoc_id_table;
1611 120 dev_class->nr_enroll_stages = EGISMOC_MAX_ENROLL_STAGES_DEFAULT;
1612 /* device should be "always off" unless being used */
1613 120 dev_class->temp_hot_seconds = 0;
1614
1615 120 dev_class->probe = egismoc_probe;
1616 120 dev_class->open = egismoc_open;
1617 120 dev_class->cancel = egismoc_cancel;
1618 120 dev_class->suspend = egismoc_suspend;
1619 120 dev_class->close = egismoc_close;
1620 120 dev_class->identify = egismoc_identify_verify;
1621 120 dev_class->verify = egismoc_identify_verify;
1622 120 dev_class->enroll = egismoc_enroll;
1623 120 dev_class->delete = egismoc_delete;
1624 120 dev_class->clear_storage = egismoc_clear_storage;
1625 120 dev_class->list = egismoc_list;
1626
1627 120 fpi_device_class_auto_initialize_features (dev_class);
1628 120 dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
1629 120 }
1630