GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.1% 607 / 0 / 705
Functions: 97.7% 42 / 0 / 43
Branches: 59.6% 186 / 0 / 312

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