GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/egismoc/egismoc.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 589 669 88.0%
Functions: 41 42 97.6%
Branches: 182 301 60.5%

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