GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/egismoc/egismoc.c
Date: 2025-12-06 02:24:24
Exec Total Coverage
Lines: 611 709 86.2%
Functions: 42 43 97.7%
Branches: 186 310 60.0%

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