GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.8% 875 / 0 / 933
Functions: 98.4% 60 / 0 / 61
Branches: 74.3% 422 / 0 / 568

libfprint/fpi-device.c
Line Branch Exec Source
1 /*
2 * FpDevice - A fingerprint reader device - Private APIs
3 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
4 * Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "device"
22 #include <math.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <gmodule.h>
26
27 #include "fpi-log.h"
28
29 #include "fp-device-private.h"
30 #include "tests/fpi-test-emulation.h"
31
32 /**
33 * SECTION: fpi-device
34 * @title: Internal FpDevice
35 * @short_description: Internal device routines
36 *
37 * The methods that are available for drivers to manipulate a device. See
38 * #FpDeviceClass for more information. Also note that most of these are
39 * not relevant for image based devices, see #FpImageDeviceClass in that
40 * case.
41 *
42 * Also see the public #FpDevice routines.
43 */
44
45 /* Manually redefine what G_DEFINE_* macro does */
46 static inline gpointer
47 832543 fp_device_get_instance_private (FpDevice *self)
48 {
49 832543 FpDeviceClass *dev_class = g_type_class_peek_static (FP_TYPE_DEVICE);
50
51 832543 return G_STRUCT_MEMBER_P (self,
52 g_type_class_get_instance_private_offset (dev_class));
53 }
54
55 20 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GModule, g_module_close)
56
57 static char *
58 1067 error_to_string (GError * error)
59 {
60 2134 g_autofree char *domain_str = NULL;
61
62
2/2
✓ Branch 2 → 3 taken 944 times.
✓ Branch 2 → 5 taken 123 times.
1067 if (!error)
63 944 return g_strdup ("none");
64
65
2/2
✓ Branch 6 → 7 taken 30 times.
✓ Branch 6 → 9 taken 93 times.
123 if (error->domain == FP_DEVICE_RETRY)
66 30 domain_str = g_enum_to_string (FP_TYPE_DEVICE_RETRY, error->code);
67
2/2
✓ Branch 10 → 11 taken 77 times.
✓ Branch 10 → 13 taken 16 times.
93 else if (error->domain == FP_DEVICE_ERROR)
68 77 domain_str = g_enum_to_string (FP_TYPE_DEVICE_ERROR, error->code);
69
1/2
✓ Branch 14 → 15 taken 16 times.
✗ Branch 14 → 16 not taken.
16 else if (error->domain == G_IO_ERROR)
70 16 domain_str = g_enum_to_string (g_io_error_enum_get_type (), error->code);
71 else if (error->domain == G_USB_DEVICE_ERROR)
72 domain_str = g_strdup_printf ("G_USB_DEVICE_ERROR_%u", error->code);
73 else
74 domain_str = g_strdup_printf ("%s_%u",
75 g_quark_to_string (error->domain),
76 error->code);
77
78 123 return g_strdup_printf ("[%s] %s", domain_str, error->message);
79 }
80
81 /**
82 * fpi_device_emulation_mode_enabled:
83 * @device: The #FpDevice to check
84 *
85 * Checks if the device is running in emulation mode, which is enabled by
86 * setting the FP_DEVICE_EMULATION environment variable to a '1' value but
87 * only when the test emulation library is loaded.
88 * This is used by some drivers to enable special behavior for testing
89 * and development purposes.
90 */
91 gboolean
92 51 (fpi_device_emulation_mode_enabled) (FpDevice *device)
93 {
94 51 static gboolean (*real_fn)(FpDevice *) = NULL;
95 51 static gsize emulation_mode = 0;
96
97
3/4
✓ Branch 2 → 3 taken 20 times.
✓ Branch 2 → 25 taken 31 times.
✓ Branch 4 → 5 taken 20 times.
✗ Branch 4 → 25 not taken.
51 if (g_once_init_enter (&emulation_mode))
98 {
99
1/2
✓ Branch 7 → 8 taken 20 times.
✗ Branch 7 → 22 not taken.
20 if (g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0)
100 {
101 20 const char *dirs[] = {
102 FPI_EMULATION_HELPER_BUILDDIR,
103 FPI_EMULATION_HELPER_INSTALLDIR,
104 };
105
106
1/2
✓ Branch 20 → 9 taken 20 times.
✗ Branch 20 → 21 not taken.
20 for (size_t i = 0; i < G_N_ELEMENTS (dirs); ++i)
107 {
108 20 g_autofree char *path = NULL;
109 g_autoptr(GModule) mod = NULL;
110 20 gpointer sym;
111
112 20 path = g_build_filename (dirs[i], FPI_EMULATION_HELPER_MODULE, NULL);
113
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 20 times.
20 if (!(mod = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
114 continue;
115
116
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 20 times.
20 if (!g_module_symbol (mod, "fpi_device_emulation_mode_enabled", &sym))
117 continue;
118
119 20 real_fn = (gboolean (*)(FpDevice *)) sym;
120 20 g_steal_pointer (&mod);
121 20 break;
122 }
123 }
124
125
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 20 times.
20 g_once_init_leave (&emulation_mode, real_fn ? TRUE : G_MAXSIZE);
126 }
127
128
1/2
✓ Branch 25 → 26 taken 51 times.
✗ Branch 25 → 27 not taken.
51 if (real_fn)
129 51 return real_fn (device);
130
131 return FALSE;
132 }
133
134 /**
135 * fpi_device_class_auto_initialize_features:
136 * @device_class: An #FpDeviceClass to initialize
137 *
138 * Initializes the #FpDeviceClass @features flags checking what device vfuncs
139 * are implemented.
140 * Drivers should call this at the end of the class initialization.
141 */
142 void
143 1662 fpi_device_class_auto_initialize_features (FpDeviceClass *device_class)
144 {
145
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1662 times.
1662 g_return_if_fail (FP_IS_DEVICE_CLASS (device_class));
146
147
2/2
✓ Branch 5 → 6 taken 136 times.
✓ Branch 5 → 7 taken 1526 times.
1662 if (device_class->capture)
148 136 device_class->features |= FP_DEVICE_FEATURE_CAPTURE;
149
150
2/2
✓ Branch 7 → 8 taken 643 times.
✓ Branch 7 → 9 taken 1019 times.
1662 if (device_class->verify)
151 643 device_class->features |= FP_DEVICE_FEATURE_VERIFY;
152
153
2/2
✓ Branch 9 → 10 taken 1405 times.
✓ Branch 9 → 11 taken 257 times.
1662 if (device_class->identify)
154 1405 device_class->features |= FP_DEVICE_FEATURE_IDENTIFY | FP_DEVICE_FEATURE_VERIFY;
155
156
2/2
✓ Branch 11 → 12 taken 1151 times.
✓ Branch 11 → 13 taken 511 times.
1662 if (device_class->list)
157 1151 device_class->features |= FP_DEVICE_FEATURE_STORAGE_LIST;
158
159
2/2
✓ Branch 13 → 14 taken 1277 times.
✓ Branch 13 → 15 taken 385 times.
1662 if (device_class->delete)
160 1277 device_class->features |= FP_DEVICE_FEATURE_STORAGE_DELETE;
161
162
2/2
✓ Branch 15 → 16 taken 1151 times.
✓ Branch 15 → 17 taken 511 times.
1662 if (device_class->clear_storage)
163 1151 device_class->features |= FP_DEVICE_FEATURE_STORAGE_CLEAR;
164
165
5/6
✓ Branch 17 → 18 taken 1277 times.
✓ Branch 17 → 21 taken 385 times.
✓ Branch 18 → 19 taken 128 times.
✓ Branch 18 → 20 taken 1149 times.
✓ Branch 19 → 20 taken 128 times.
✗ Branch 19 → 21 not taken.
1662 if (device_class->delete && (device_class->list || device_class->clear_storage))
166 1277 device_class->features |= FP_DEVICE_FEATURE_STORAGE;
167
168
2/2
✓ Branch 21 → 22 taken 1016 times.
✓ Branch 21 → 23 taken 646 times.
1662 if (device_class->temp_hot_seconds < 0)
169 1016 device_class->features |= FP_DEVICE_FEATURE_ALWAYS_ON;
170 }
171
172 /**
173 * fpi_device_retry_new:
174 * @error: The #FpDeviceRetry error value describing the issue
175 *
176 * Create a new retry error code for use with fpi_device_verify_complete()
177 * and similar calls.
178 */
179 GError *
180 93 fpi_device_retry_new (FpDeviceRetry error)
181 {
182 93 const gchar *msg;
183
184
6/6
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 4 taken 37 times.
✓ Branch 2 → 5 taken 15 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 1 time.
✓ Branch 2 → 8 taken 28 times.
93 switch (error)
185 {
186 case FP_DEVICE_RETRY_GENERAL:
187 msg = "Please try again.";
188 break;
189
190 case FP_DEVICE_RETRY_TOO_SHORT:
191 93 msg = "The swipe was too short, please try again.";
192 break;
193
194 37 case FP_DEVICE_RETRY_CENTER_FINGER:
195 37 msg = "The finger was not centered properly, please try again.";
196 37 break;
197
198 15 case FP_DEVICE_RETRY_REMOVE_FINGER:
199 15 msg = "Please try again after removing the finger first.";
200 15 break;
201
202 1 case FP_DEVICE_RETRY_TOO_FAST:
203 1 msg = "The swipe was too fast, please try again.";
204 1 break;
205
206 1 default:
207 1 g_warning ("Unsupported error, returning general error instead!");
208 1 error = FP_DEVICE_RETRY_GENERAL;
209 1 msg = "Please try again.";
210 }
211
212 93 return g_error_new_literal (FP_DEVICE_RETRY, error, msg);
213 }
214
215 /**
216 * fpi_device_error_new:
217 * @error: The #FpDeviceRetry error value describing the issue
218 *
219 * Create a new error code for use with fpi_device_verify_complete() and
220 * similar calls.
221 */
222 GError *
223 105 fpi_device_error_new (FpDeviceError error)
224 {
225 105 const gchar *msg;
226
227
13/13
✓ Branch 2 → 3 taken 27 times.
✓ Branch 2 → 4 taken 11 times.
✓ Branch 2 → 5 taken 2 times.
✓ Branch 2 → 6 taken 14 times.
✓ Branch 2 → 7 taken 11 times.
✓ Branch 2 → 8 taken 10 times.
✓ Branch 2 → 9 taken 1 time.
✓ Branch 2 → 10 taken 4 times.
✓ Branch 2 → 11 taken 6 times.
✓ Branch 2 → 12 taken 8 times.
✓ Branch 2 → 13 taken 2 times.
✓ Branch 2 → 14 taken 1 time.
✓ Branch 2 → 15 taken 8 times.
105 switch (error)
228 {
229 case FP_DEVICE_ERROR_GENERAL:
230 msg = "An unspecified error occurred!";
231 break;
232
233 case FP_DEVICE_ERROR_NOT_SUPPORTED:
234 105 msg = "The operation is not supported on this device!";
235 break;
236
237 11 case FP_DEVICE_ERROR_NOT_OPEN:
238 11 msg = "The device needs to be opened first!";
239 11 break;
240
241 2 case FP_DEVICE_ERROR_ALREADY_OPEN:
242 2 msg = "The device has already been opened!";
243 2 break;
244
245 14 case FP_DEVICE_ERROR_BUSY:
246 14 msg = "The device is still busy with another operation, please try again later.";
247 14 break;
248
249 11 case FP_DEVICE_ERROR_PROTO:
250 11 msg = "The driver encountered a protocol error with the device.";
251 11 break;
252
253 10 case FP_DEVICE_ERROR_DATA_INVALID:
254 10 msg = "Passed (print) data is not valid.";
255 10 break;
256
257 1 case FP_DEVICE_ERROR_DATA_FULL:
258 1 msg = "On device storage space is full.";
259 1 break;
260
261 4 case FP_DEVICE_ERROR_DATA_NOT_FOUND:
262 4 msg = "Print was not found on the devices storage.";
263 4 break;
264
265 6 case FP_DEVICE_ERROR_DATA_DUPLICATE:
266 6 msg = "This finger has already enrolled, please try a different finger";
267 6 break;
268
269 8 case FP_DEVICE_ERROR_REMOVED:
270 8 msg = "This device has been removed from the system.";
271 8 break;
272
273 2 case FP_DEVICE_ERROR_TOO_HOT:
274 2 msg = "Device disabled to prevent overheating.";
275 2 break;
276
277 1 default:
278 1 g_warning ("Unsupported error, returning general error instead!");
279 1 error = FP_DEVICE_ERROR_GENERAL;
280 1 msg = "An unspecified error occurred!";
281 }
282
283 105 return g_error_new_literal (FP_DEVICE_ERROR, error, msg);
284 }
285
286 /**
287 * fpi_device_retry_new_msg:
288 * @error: The #FpDeviceRetry error value describing the issue
289 * @msg: Custom message to use with printf-style formatting
290 * @...: args for @msg
291 *
292 * Create a new retry error code for use with fpi_device_verify_complete()
293 * and similar calls.
294 */
295 GError *
296 11 fpi_device_retry_new_msg (FpDeviceRetry device_error,
297 const gchar *msg,
298 ...)
299 {
300 11 GError *error;
301 11 va_list args;
302
303 11 va_start (args, msg);
304 11 error = g_error_new_valist (FP_DEVICE_RETRY, device_error, msg, args);
305 11 va_end (args);
306
307 11 return error;
308 }
309
310 /**
311 * fpi_device_error_new_msg:
312 * @error: The #FpDeviceRetry error value describing the issue
313 * @msg: Custom message to use with printf-style formatting
314 * @...: args for @msg
315 *
316 * Create a new error code for use with fpi_device_verify_complete()
317 * and similar calls.
318 */
319 GError *
320 34 fpi_device_error_new_msg (FpDeviceError device_error,
321 const gchar *msg,
322 ...)
323 {
324 34 GError *error;
325 34 va_list args;
326
327 34 va_start (args, msg);
328 34 error = g_error_new_valist (FP_DEVICE_ERROR, device_error, msg, args);
329 34 va_end (args);
330
331 34 return error;
332 }
333
334 /**
335 * fpi_device_set_nr_enroll_stages:
336 * @device: The #FpDevice
337 * @enroll_stages: The number of enroll stages
338 *
339 * Updates the reported number of enroll stages that the device needs.
340 * If all supported devices have the same number of stages, then the
341 * value can simply be set in the class.
342 */
343 void
344 88 fpi_device_set_nr_enroll_stages (FpDevice *device,
345 gint enroll_stages)
346 {
347 88 FpDevicePrivate *priv = fp_device_get_instance_private (device);
348
349
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 88 times.
88 g_return_if_fail (FP_IS_DEVICE (device));
350
2/2
✓ Branch 6 → 7 taken 84 times.
✓ Branch 6 → 8 taken 4 times.
88 g_return_if_fail (enroll_stages > 0);
351
352 84 priv->nr_enroll_stages = enroll_stages;
353 84 g_object_notify (G_OBJECT (device), "nr-enroll-stages");
354 }
355
356 /**
357 * fpi_device_set_scan_type:
358 * @device: The #FpDevice
359 * @scan_type: The scan type of the device
360 *
361 * Updates the the scan type of the device from the default.
362 * If all supported devices have the same scan type, then the
363 * value can simply be set in the class.
364 */
365 void
366 6 fpi_device_set_scan_type (FpDevice *device,
367 FpScanType scan_type)
368 {
369 6 FpDevicePrivate *priv = fp_device_get_instance_private (device);
370
371
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 6 times.
6 g_return_if_fail (FP_IS_DEVICE (device));
372
373 6 priv->scan_type = scan_type;
374 6 g_object_notify (G_OBJECT (device), "scan-type");
375 }
376
377 /**
378 * fpi_device_update_features:
379 * @device: The #FpDevice
380 * @update: The feature flags to update
381 * @value: The value to set the flags to
382 *
383 * Updates the feature flags for the device. This can be used
384 * to runtime detect features that are supported by the device.
385 */
386 void
387 46 fpi_device_update_features (FpDevice *device,
388 FpDeviceFeature update,
389 FpDeviceFeature value)
390 {
391 46 FpDevicePrivate *priv = fp_device_get_instance_private (device);
392
393
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 46 times.
46 g_return_if_fail (FP_IS_DEVICE (device));
394
1/2
✓ Branch 6 → 7 taken 46 times.
✗ Branch 6 → 8 not taken.
46 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
395
1/2
✓ Branch 7 → 9 taken 46 times.
✗ Branch 7 → 10 not taken.
46 g_return_if_fail ((value & update) == value);
396
397 46 priv->features = (priv->features & ~update) | (value & update);
398 }
399
400 typedef struct
401 {
402 GSource source;
403 FpDevice *device;
404 } FpDeviceTimeoutSource;
405
406 static void
407 1096 timeout_finalize (GSource *source)
408 {
409 1096 FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source;
410 1096 FpDevicePrivate *priv;
411
412 1096 priv = fp_device_get_instance_private (timeout_source->device);
413 1096 priv->sources = g_slist_remove (priv->sources, source);
414 1096 }
415
416 static gboolean
417 643 timeout_dispatch (GSource *source, GSourceFunc gsource_func, gpointer user_data)
418 {
419 643 FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source;
420 643 FpTimeoutFunc callback = (FpTimeoutFunc) gsource_func;
421
422 643 callback (timeout_source->device, user_data);
423
424 643 return G_SOURCE_REMOVE;
425 }
426
427 static GSourceFuncs timeout_funcs = {
428 NULL, /* prepare */
429 NULL, /* check */
430 timeout_dispatch,
431 timeout_finalize,
432 NULL, NULL
433 };
434
435 /**
436 * fpi_device_add_timeout:
437 * @device: The #FpDevice
438 * @interval: The interval in milliseconds
439 * @func: The #FpTimeoutFunc to call on timeout
440 * @user_data: (nullable): User data to pass to the callback
441 * @destroy_notify: (nullable): #GDestroyNotify for @user_data
442 *
443 * Register a timeout to run. Drivers should always make sure that timers are
444 * cancelled when appropriate.
445 *
446 * Returns: (transfer none): A newly created and attached #GSource
447 */
448 GSource *
449 1104 fpi_device_add_timeout (FpDevice *device,
450 gint interval,
451 FpTimeoutFunc func,
452 gpointer user_data,
453 GDestroyNotify destroy_notify)
454 {
455 1104 FpDevicePrivate *priv = fp_device_get_instance_private (device);
456 1104 FpDeviceTimeoutSource *source;
457 1104 GMainContext *context;
458
459 1104 source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs,
460 sizeof (FpDeviceTimeoutSource));
461 1104 source->device = device;
462
463
2/2
✓ Branch 4 → 5 taken 625 times.
✓ Branch 4 → 6 taken 479 times.
1104 if (priv->current_task)
464 625 context = g_task_get_context (priv->current_task);
465 else
466 479 context = g_main_context_get_thread_default ();
467
468 1104 g_source_attach (&source->source, context);
469 1104 g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify);
470 2208 g_source_set_ready_time (&source->source,
471 1104 g_source_get_time (&source->source) + interval * (guint64) 1000);
472 1104 priv->sources = g_slist_prepend (priv->sources, source);
473 1104 g_source_unref (&source->source);
474
475 1104 return &source->source;
476 }
477
478 /**
479 * fpi_device_get_usb_device:
480 * @device: The #FpDevice
481 *
482 * Get the #GUsbDevice for this #FpDevice. Only permissible to call if the
483 * #FpDevice is of type %FP_DEVICE_TYPE_USB.
484 *
485 * Returns: The #GUsbDevice
486 */
487 GUsbDevice *
488 21104 fpi_device_get_usb_device (FpDevice *device)
489 {
490 21104 FpDevicePrivate *priv = fp_device_get_instance_private (device);
491
492
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 21104 times.
21104 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
493
2/2
✓ Branch 6 → 7 taken 21103 times.
✓ Branch 6 → 8 taken 1 time.
21104 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_USB, NULL);
494
495 21103 return priv->usb_device;
496 }
497
498 /**
499 * fpi_device_get_udev_data:
500 * @device: The #FpDevice
501 * @subtype: Which subtype to get information about
502 *
503 * Get a subtype-specific hardware resource for this #FpDevice. Only permissible to call if the
504 * #FpDevice is of type %FP_DEVICE_TYPE_UDEV.
505 *
506 * Returns: Depends on @subtype; for SPIDEV/HIDRAW returns a path to the relevant device.
507 */
508 gpointer
509 1 fpi_device_get_udev_data (FpDevice *device, FpiDeviceUdevSubtypeFlags subtype)
510 {
511 1 FpDevicePrivate *priv = fp_device_get_instance_private (device);
512
513
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
514
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
1 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_UDEV, NULL);
515
516
1/3
✗ Branch 7 → 9 not taken.
✓ Branch 7 → 10 taken 1 time.
✗ Branch 7 → 11 not taken.
1 switch (subtype)
517 {
518 case FPI_DEVICE_UDEV_SUBTYPE_HIDRAW:
519 return priv->udev_data.hidraw_path;
520
521 1 case FPI_DEVICE_UDEV_SUBTYPE_SPIDEV:
522 1 return priv->udev_data.spidev_path;
523
524 default:
525 g_return_val_if_reached (NULL);
526 return NULL;
527 }
528 }
529
530 /**
531 * fpi_device_get_virtual_env:
532 * @device: The #FpDevice
533 *
534 * Get the value of the environment variable that caused the virtual #FpDevice to be
535 * generated. Only permissible to call if the #FpDevice is of type %FP_DEVICE_TYPE_VIRTUAL.
536 *
537 * Returns: The value of the environment variable
538 */
539 const gchar *
540 116 fpi_device_get_virtual_env (FpDevice *device)
541 {
542 116 FpDevicePrivate *priv = fp_device_get_instance_private (device);
543
544
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 116 times.
116 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
545
2/2
✓ Branch 6 → 7 taken 115 times.
✓ Branch 6 → 8 taken 1 time.
116 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_VIRTUAL, NULL);
546
547 115 return priv->virtual_env;
548 }
549
550 /**
551 * fpi_device_get_current_action:
552 * @device: The #FpDevice
553 *
554 * Get the currently ongoing action or %FPI_DEVICE_ACTION_NONE if there
555 * is no operation at this time.
556 *
557 * This is useful for drivers that might share code paths between different
558 * actions (e.g. verify and identify) and want to find out again later which
559 * action was started in the beginning.
560 *
561 * Returns: The ongoing #FpiDeviceAction
562 */
563 FpiDeviceAction
564 2145 fpi_device_get_current_action (FpDevice *device)
565 {
566 2145 FpDevicePrivate *priv = fp_device_get_instance_private (device);
567
568
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2145 times.
2145 g_return_val_if_fail (FP_IS_DEVICE (device), FPI_DEVICE_ACTION_NONE);
569
570 2145 return priv->current_action;
571 }
572
573 /**
574 * fpi_device_action_is_cancelled:
575 * @device: The #FpDevice
576 *
577 * Checks whether the current action has been cancelled by the user.
578 * This is equivalent to first getting the cancellable using
579 * fpi_device_get_cancellable() and then checking whether it has been
580 * cancelled (if it is non-NULL).
581 *
582 * Returns: %TRUE if action should be cancelled
583 */
584 gboolean
585 100 fpi_device_action_is_cancelled (FpDevice *device)
586 {
587 100 FpDevicePrivate *priv = fp_device_get_instance_private (device);
588
589
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 100 times.
100 g_return_val_if_fail (FP_IS_DEVICE (device), TRUE);
590
2/2
✓ Branch 6 → 7 taken 99 times.
✓ Branch 6 → 8 taken 1 time.
100 g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, TRUE);
591
592 99 return g_cancellable_is_cancelled (priv->current_cancellable);
593 }
594
595 /**
596 * fpi_device_get_driver_data:
597 * @device: The #FpDevice
598 *
599 * Returns: The driver data from the #FpIdEntry table entry
600 */
601 guint64
602 792682 fpi_device_get_driver_data (FpDevice *device)
603 {
604 792682 FpDevicePrivate *priv = fp_device_get_instance_private (device);
605
606
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 792682 times.
792682 g_return_val_if_fail (FP_IS_DEVICE (device), 0);
607
608 792682 return priv->driver_data;
609 }
610
611 /**
612 * fpi_device_get_enroll_data:
613 * @device: The #FpDevice
614 * @print: (out) (transfer none): The user provided template print
615 *
616 * Get data for enrollment.
617 */
618 void
619 258 fpi_device_get_enroll_data (FpDevice *device,
620 FpPrint **print)
621 {
622 258 FpDevicePrivate *priv = fp_device_get_instance_private (device);
623 258 FpEnrollData *data;
624
625
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 258 times.
258 g_return_if_fail (FP_IS_DEVICE (device));
626
1/2
✓ Branch 6 → 7 taken 258 times.
✗ Branch 6 → 9 not taken.
258 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
627
628 258 data = g_task_get_task_data (priv->current_task);
629
1/2
✓ Branch 8 → 10 taken 258 times.
✗ Branch 8 → 11 not taken.
258 g_assert (data);
630
631
1/2
✓ Branch 10 → 12 taken 258 times.
✗ Branch 10 → 13 not taken.
258 if (print)
632 258 *print = data->print;
633 }
634
635 /**
636 * fpi_device_get_capture_data:
637 * @device: The #FpDevice
638 * @wait_for_finger: (out): Whether to wait for finger or not
639 *
640 * Get data for capture.
641 */
642 void
643 21 fpi_device_get_capture_data (FpDevice *device,
644 gboolean *wait_for_finger)
645 {
646 21 FpDevicePrivate *priv = fp_device_get_instance_private (device);
647
648
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 21 times.
21 g_return_if_fail (FP_IS_DEVICE (device));
649
1/2
✓ Branch 6 → 7 taken 21 times.
✗ Branch 6 → 8 not taken.
21 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
650
651
1/2
✓ Branch 7 → 9 taken 21 times.
✗ Branch 7 → 10 not taken.
21 if (wait_for_finger)
652 21 *wait_for_finger = priv->wait_for_finger;
653 }
654
655 /**
656 * fpi_device_get_verify_data:
657 * @device: The #FpDevice
658 * @print: (out) (transfer none): The enrolled print
659 *
660 * Get data for verify.
661 */
662 void
663 29 fpi_device_get_verify_data (FpDevice *device,
664 FpPrint **print)
665 {
666 29 FpDevicePrivate *priv = fp_device_get_instance_private (device);
667 29 FpMatchData *data;
668
669
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 29 times.
29 g_return_if_fail (FP_IS_DEVICE (device));
670
1/2
✓ Branch 6 → 7 taken 29 times.
✗ Branch 6 → 9 not taken.
29 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
671
672 29 data = g_task_get_task_data (priv->current_task);
673
1/2
✓ Branch 8 → 10 taken 29 times.
✗ Branch 8 → 11 not taken.
29 g_assert (data);
674
675
1/2
✓ Branch 10 → 12 taken 29 times.
✗ Branch 10 → 13 not taken.
29 if (print)
676 29 *print = data->enrolled_print;
677 }
678
679 /**
680 * fpi_device_get_identify_data:
681 * @device: The #FpDevice
682 * @prints: (out) (transfer none) (element-type FpPrint): The gallery of prints
683 *
684 * Get prints gallery for identification.
685 *
686 * The @prints array is always non-%NULL and may contain a list of #FpPrint's
687 * that the device should match against.
688 *
689 * Note that @prints can be an empty array, in such case the device is expected
690 * to report the scanned print matching the one in its internal storage, if any.
691 *
692 */
693 void
694 63 fpi_device_get_identify_data (FpDevice *device,
695 GPtrArray **prints)
696 {
697 63 FpDevicePrivate *priv = fp_device_get_instance_private (device);
698 63 FpMatchData *data;
699
700
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 63 times.
63 g_return_if_fail (FP_IS_DEVICE (device));
701
1/2
✓ Branch 6 → 7 taken 63 times.
✗ Branch 6 → 9 not taken.
63 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
702
703 63 data = g_task_get_task_data (priv->current_task);
704
1/2
✓ Branch 8 → 10 taken 63 times.
✗ Branch 8 → 11 not taken.
63 g_assert (data);
705
706
1/2
✓ Branch 10 → 12 taken 63 times.
✗ Branch 10 → 13 not taken.
63 if (prints)
707 63 *prints = data->gallery;
708 }
709
710 /**
711 * fpi_device_get_delete_data:
712 * @device: The #FpDevice
713 * @print: (out) (transfer none): The print to delete
714 *
715 * Get data for delete.
716 */
717 void
718 28 fpi_device_get_delete_data (FpDevice *device,
719 FpPrint **print)
720 {
721 28 FpDevicePrivate *priv = fp_device_get_instance_private (device);
722
723
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 28 times.
28 g_return_if_fail (FP_IS_DEVICE (device));
724
1/2
✓ Branch 6 → 7 taken 28 times.
✗ Branch 6 → 8 not taken.
28 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
725
726
1/2
✓ Branch 7 → 9 taken 28 times.
✗ Branch 7 → 11 not taken.
28 if (print)
727 28 *print = g_task_get_task_data (priv->current_task);
728 }
729
730 /**
731 * fpi_device_get_cancellable:
732 * @device: The #FpDevice
733 *
734 * Retrieve the #GCancellable that may cancel the currently ongoing operation. This
735 * is primarily useful to pass directly to e.g. fpi_usb_transfer_submit() for cancellable
736 * transfers.
737 * In many cases the cancel vfunc may be more convenient to react to cancellation in some
738 * way.
739 *
740 * Returns: (transfer none): The #GCancellable for the current action.
741 */
742 GCancellable *
743 3232 fpi_device_get_cancellable (FpDevice *device)
744 {
745 3232 FpDevicePrivate *priv = fp_device_get_instance_private (device);
746
747
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3232 times.
3232 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
748
2/2
✓ Branch 6 → 7 taken 3231 times.
✓ Branch 6 → 8 taken 1 time.
3232 g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, NULL);
749
750 3231 return priv->current_cancellable;
751 }
752
753 static void
754 4 emit_removed_on_task_completed (FpDevice *device)
755 {
756 4 g_signal_emit_by_name (device, "removed");
757 4 }
758
759 /**
760 * fpi_device_remove:
761 * @device: The #FpDevice
762 *
763 * Called to signal to the #FpDevice that it has been unplugged (physically
764 * removed from the system).
765 *
766 * For USB devices, this API is called automatically by #FpContext.
767 */
768 void
769 7 fpi_device_remove (FpDevice *device)
770 {
771 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
772
773
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
774
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 9 not taken.
7 g_return_if_fail (!priv->is_removed);
775
776 7 priv->is_removed = TRUE;
777
778 7 g_object_notify (G_OBJECT (device), "removed");
779
780 /* If there is a pending action, we wait for it to fail, otherwise we
781 * immediately emit the "removed" signal. */
782
2/2
✓ Branch 8 → 10 taken 4 times.
✓ Branch 8 → 11 taken 3 times.
7 if (priv->current_task)
783 {
784 4 g_signal_connect_object (priv->current_task,
785 "notify::completed",
786 (GCallback) emit_removed_on_task_completed,
787 device,
788 G_CONNECT_SWAPPED);
789 }
790 else
791 {
792 3 g_signal_emit_by_name (device, "removed");
793 }
794 }
795
796 /**
797 * fpi_device_action_error:
798 * @device: The #FpDevice
799 * @error: (nullable) (transfer full): The #GError or %NULL on success
800 *
801 * Finish an ongoing action with an error. This is the same as calling
802 * the corresponding complete function such as fpi_device_open_complete()
803 * with an error set. If possible, use the correct complete function as
804 * that results in improved error detection.
805 */
806 void
807 32 fpi_device_action_error (FpDevice *device,
808 GError *error)
809 {
810 32 FpDevicePrivate *priv = fp_device_get_instance_private (device);
811
812
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 32 times.
32 g_return_if_fail (FP_IS_DEVICE (device));
813
2/2
✓ Branch 6 → 7 taken 31 times.
✓ Branch 6 → 8 taken 1 time.
32 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
814
815
2/2
✓ Branch 7 → 9 taken 22 times.
✓ Branch 7 → 17 taken 9 times.
31 if (error != NULL)
816 {
817
1/2
✓ Branch 10 → 11 taken 22 times.
✗ Branch 10 → 19 not taken.
22 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
818 {
819 44 g_autofree char *error_str = error_to_string (error);
820 44 g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
821
822 22 g_debug ("Device reported generic error (%s) during action; action was: %s",
823 error_str, action_str);
824 }
825 }
826 else
827 {
828 9 g_warning ("Device failed to pass an error to generic action error function");
829 9 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "Device reported error but did not provide an error condition");
830 }
831
832
833
10/11
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 22 taken 2 times.
✓ Branch 19 → 24 taken 2 times.
✓ Branch 19 → 26 taken 7 times.
✓ Branch 19 → 28 taken 3 times.
✓ Branch 19 → 30 taken 6 times.
✓ Branch 19 → 32 taken 4 times.
✓ Branch 19 → 34 taken 2 times.
✓ Branch 19 → 36 taken 2 times.
✓ Branch 19 → 38 taken 2 times.
✗ Branch 19 → 40 not taken.
31 switch (priv->current_action)
834 {
835 1 case FPI_DEVICE_ACTION_PROBE:
836 1 fpi_device_probe_complete (device, NULL, NULL, error);
837 1 break;
838
839 2 case FPI_DEVICE_ACTION_OPEN:
840 2 fpi_device_open_complete (device, error);
841 2 break;
842
843 2 case FPI_DEVICE_ACTION_CLOSE:
844 2 fpi_device_close_complete (device, error);
845 2 break;
846
847 7 case FPI_DEVICE_ACTION_ENROLL:
848 7 fpi_device_enroll_complete (device, NULL, error);
849 7 break;
850
851 3 case FPI_DEVICE_ACTION_VERIFY:
852 3 fpi_device_verify_complete (device, error);
853 3 break;
854
855 6 case FPI_DEVICE_ACTION_IDENTIFY:
856 6 fpi_device_identify_complete (device, error);
857 6 break;
858
859 4 case FPI_DEVICE_ACTION_CAPTURE:
860 4 fpi_device_capture_complete (device, NULL, error);
861 4 break;
862
863 2 case FPI_DEVICE_ACTION_DELETE:
864 2 fpi_device_delete_complete (device, error);
865 2 break;
866
867 2 case FPI_DEVICE_ACTION_LIST:
868 2 fpi_device_list_complete (device, NULL, error);
869 2 break;
870
871 2 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
872 2 fpi_device_clear_storage_complete (device, error);
873 2 break;
874
875 default:
876 case FPI_DEVICE_ACTION_NONE:
877 g_return_if_reached ();
878 break;
879 }
880 }
881
882 /**
883 * fpi_device_critical_enter:
884 * @device: The #FpDevice
885 *
886 * Enter a critical section in the driver code where no outside calls from
887 * libfprint should happen. Drivers can already assume that everything
888 * happens from the same thread, however, that still allows e.g. the cancel
889 * vfunc to be called at any point in time.
890 *
891 * Using this kind of critical section, the driver can assume that libfprint
892 * will not forward any external requests to the driver for the time being.
893 * This is for example useful to prevent cancellation while the device is being
894 * set up. Or, said differently, using this feature means that the cancel
895 * handler is able to make more assumptions about the current state.
896 *
897 * Please note that the driver is not shielded from all external changes. For
898 * example the cancellable as returned by fpi_device_get_cancellable() will
899 * still change immediately.
900 *
901 * The driver may call this function multiple times, but must also ensure that
902 * fpi_device_critical_leave() is called an equal amount of times and that all
903 * critical sections are left before command completion.
904 */
905 void
906 60 fpi_device_critical_enter (FpDevice *device)
907 {
908 60 FpDevicePrivate *priv = fp_device_get_instance_private (device);
909
910
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 60 times.
60 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
911
912 60 priv->critical_section += 1;
913
914 /* Stop flushing events if that was previously queued. */
915
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 58 times.
60 if (priv->critical_section_flush_source)
916 2 g_source_destroy (priv->critical_section_flush_source);
917 60 priv->critical_section_flush_source = NULL;
918 }
919
920 static gboolean
921 59 fpi_device_critical_section_flush_idle_cb (FpDevice *device)
922 {
923 59 FpDevicePrivate *priv = fp_device_get_instance_private (device);
924
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 58 times.
59 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
925
926
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 58 times.
59 if (priv->cancel_queued)
927 {
928 /* Cancellation must only happen if the driver is busy. */
929
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 7 not taken.
1 if (priv->current_action != FPI_DEVICE_ACTION_NONE &&
930
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
1 priv->current_task_idle_return_source == NULL)
931 1 cls->cancel (device);
932 1 priv->cancel_queued = FALSE;
933
934 1 return G_SOURCE_CONTINUE;
935 }
936
937
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 56 times.
58 if (priv->suspend_queued)
938 {
939 2 priv->suspend_queued = FALSE;
940 2 fpi_device_suspend (device);
941
942 2 return G_SOURCE_CONTINUE;
943 }
944
945
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 14 taken 55 times.
56 if (priv->resume_queued)
946 {
947 1 priv->resume_queued = FALSE;
948 1 fpi_device_resume (device);
949
950 1 return G_SOURCE_CONTINUE;
951 }
952
953 55 priv->critical_section_flush_source = NULL;
954
955 55 return G_SOURCE_REMOVE;
956 }
957
958 /**
959 * fpi_device_critical_leave:
960 * @device: The #FpDevice
961 *
962 * Leave a critical section started by fpi_device_critical_enter().
963 *
964 * Once all critical sections have been left, libfprint will start flushing
965 * out the queued up requests. This is done from the mainloop and the driver
966 * is protected from reentrency issues.
967 */
968 void
969 60 fpi_device_critical_leave (FpDevice *device)
970 {
971 60 FpDevicePrivate *priv = fp_device_get_instance_private (device);
972
973
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 60 times.
60 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
974
1/2
✓ Branch 5 → 6 taken 60 times.
✗ Branch 5 → 7 not taken.
60 g_return_if_fail (priv->critical_section);
975
976 60 priv->critical_section -= 1;
977
2/2
✓ Branch 6 → 8 taken 57 times.
✓ Branch 6 → 16 taken 3 times.
60 if (priv->critical_section)
978 return;
979
980 /* We left the critical section, make sure a flush is queued. */
981
1/2
✓ Branch 8 → 9 taken 57 times.
✗ Branch 8 → 16 not taken.
57 if (priv->critical_section_flush_source)
982 return;
983
984 57 priv->critical_section_flush_source = g_idle_source_new ();
985 57 g_source_set_priority (priv->critical_section_flush_source, G_PRIORITY_HIGH);
986 57 g_source_set_callback (priv->critical_section_flush_source,
987 (GSourceFunc) fpi_device_critical_section_flush_idle_cb,
988 device,
989 NULL);
990 57 g_source_set_name (priv->critical_section_flush_source,
991 "Flush libfprint driver critical section");
992 57 g_source_attach (priv->critical_section_flush_source,
993 g_task_get_context (priv->current_task));
994 57 g_source_unref (priv->critical_section_flush_source);
995 }
996
997 static void
998 939 clear_device_cancel_action (FpDevice *device)
999 {
1000 939 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1001
1002
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 935 times.
939 g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
1003
1004
2/2
✓ Branch 5 → 6 taken 860 times.
✓ Branch 5 → 8 taken 79 times.
939 if (priv->current_cancellable_id)
1005 {
1006 860 g_cancellable_disconnect (priv->current_cancellable,
1007 priv->current_cancellable_id);
1008 860 priv->current_cancellable_id = 0;
1009 }
1010
1011
2/2
✓ Branch 8 → 9 taken 183 times.
✓ Branch 8 → 12 taken 756 times.
939 if (priv->current_task_cancellable_id)
1012 {
1013 183 g_cancellable_disconnect (g_task_get_cancellable (priv->current_task),
1014 priv->current_task_cancellable_id);
1015 183 priv->current_task_cancellable_id = 0;
1016 }
1017 939 }
1018
1019 typedef enum _FpDeviceTaskReturnType {
1020 FP_DEVICE_TASK_RETURN_INT,
1021 FP_DEVICE_TASK_RETURN_BOOL,
1022 FP_DEVICE_TASK_RETURN_OBJECT,
1023 FP_DEVICE_TASK_RETURN_PTR_ARRAY,
1024 FP_DEVICE_TASK_RETURN_ERROR,
1025 } FpDeviceTaskReturnType;
1026
1027 typedef struct _FpDeviceTaskReturnData
1028 {
1029 FpDevice *device;
1030 FpDeviceTaskReturnType type;
1031 gpointer result;
1032 } FpDeviceTaskReturnData;
1033
1034 static gboolean
1035 939 fp_device_task_return_in_idle_cb (gpointer user_data)
1036 {
1037 1878 g_autoptr(GTask) task = NULL;
1038
1/2
✓ Branch 39 → 40 taken 939 times.
✗ Branch 39 → 41 not taken.
939 g_autoptr(GError) cancellation_reason = NULL;
1039 939 FpDeviceTaskReturnData *data = user_data;
1040 939 FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
1041 939 FpiDeviceAction action;
1042
1043
1/2
✓ Branch 4 → 5 taken 939 times.
✗ Branch 4 → 9 not taken.
939 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1044 {
1045 1878 g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
1046
1047 939 g_debug ("Completing action %s in idle!", action_str);
1048 }
1049
1050
1/2
✓ Branch 9 → 10 taken 939 times.
✗ Branch 9 → 11 not taken.
939 task = g_steal_pointer (&priv->current_task);
1051 939 action = priv->current_action;
1052 939 priv->current_action = FPI_DEVICE_ACTION_NONE;
1053 939 priv->current_task_idle_return_source = NULL;
1054
1/2
✓ Branch 9 → 10 taken 939 times.
✗ Branch 9 → 11 not taken.
939 g_clear_object (&priv->current_cancellable);
1055 939 cancellation_reason = g_steal_pointer (&priv->current_cancellation_reason);
1056
1057 939 fpi_device_update_temp (data->device, FALSE);
1058
1059
2/2
✓ Branch 12 → 13 taken 224 times.
✓ Branch 12 → 15 taken 715 times.
939 if (action == FPI_DEVICE_ACTION_OPEN &&
1060
2/2
✓ Branch 13 → 14 taken 217 times.
✓ Branch 13 → 15 taken 7 times.
224 data->type != FP_DEVICE_TASK_RETURN_ERROR)
1061 {
1062 217 priv->is_open = TRUE;
1063 217 g_object_notify (G_OBJECT (data->device), "open");
1064 }
1065
2/2
✓ Branch 15 → 16 taken 217 times.
✓ Branch 15 → 17 taken 505 times.
722 else if (action == FPI_DEVICE_ACTION_CLOSE)
1066 {
1067 /* Always consider the device closed. Drivers should try hard to close the
1068 * device. Generally, e.g. cancellations should be ignored.
1069 */
1070 217 priv->is_open = FALSE;
1071 217 g_object_notify (G_OBJECT (data->device), "open");
1072 }
1073
1074 /* TODO: Port/use the cancellation mechanism for device removal! */
1075
1076 /* Return FP_DEVICE_ERROR_REMOVED if the device is removed,
1077 * with the exception of a successful open, which is an odd corner case. */
1078
4/4
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 22 taken 930 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 8 times.
939 if (priv->is_removed &&
1079 1 ((action != FPI_DEVICE_ACTION_OPEN) ||
1080
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 1 time.
1 (action == FPI_DEVICE_ACTION_OPEN && data->type == FP_DEVICE_TASK_RETURN_ERROR)))
1081 {
1082 8 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
1083
1084 /* NOTE: The removed signal will be emitted from the GTask
1085 * notify::completed if that is necessary. */
1086
1087 8 return G_SOURCE_REMOVE;
1088 }
1089
1090
5/6
✓ Branch 22 → 23 taken 15 times.
✓ Branch 22 → 25 taken 698 times.
✓ Branch 22 → 27 taken 73 times.
✓ Branch 22 → 29 taken 48 times.
✓ Branch 22 → 31 taken 97 times.
✗ Branch 22 → 35 not taken.
931 switch (data->type)
1091 {
1092 15 case FP_DEVICE_TASK_RETURN_INT:
1093 15 g_task_return_int (task, GPOINTER_TO_INT (data->result));
1094 15 break;
1095
1096 698 case FP_DEVICE_TASK_RETURN_BOOL:
1097 698 g_task_return_boolean (task, GPOINTER_TO_UINT (data->result));
1098 698 break;
1099
1100 73 case FP_DEVICE_TASK_RETURN_OBJECT:
1101 73 g_task_return_pointer (task, g_steal_pointer (&data->result),
1102 g_object_unref);
1103 73 break;
1104
1105 48 case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
1106 48 g_task_return_pointer (task, g_steal_pointer (&data->result),
1107 (GDestroyNotify) g_ptr_array_unref);
1108 48 break;
1109
1110 97 case FP_DEVICE_TASK_RETURN_ERROR:
1111 /* Return internal cancellation reason instead if we have one.
1112 * Note that an external cancellation always returns G_IO_ERROR_CANCELLED
1113 */
1114
2/2
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 34 taken 95 times.
97 if (cancellation_reason)
1115 {
1116 2 g_task_set_task_data (task, NULL, NULL);
1117 2 g_task_return_error (task, g_steal_pointer (&cancellation_reason));
1118 }
1119 else
1120 {
1121 95 g_task_return_error (task, g_steal_pointer (&data->result));
1122 }
1123 break;
1124
1125 default:
1126 g_assert_not_reached ();
1127 }
1128
1129 return G_SOURCE_REMOVE;
1130 }
1131
1132 static void
1133 939 fpi_device_task_return_data_free (FpDeviceTaskReturnData *data)
1134 {
1135
4/5
✓ Branch 2 → 3 taken 73 times.
✓ Branch 2 → 5 taken 48 times.
✓ Branch 2 → 7 taken 99 times.
✗ Branch 2 → 8 not taken.
✓ Branch 2 → 10 taken 719 times.
939 switch (data->type)
1136 {
1137 case FP_DEVICE_TASK_RETURN_INT:
1138 case FP_DEVICE_TASK_RETURN_BOOL:
1139 break;
1140
1141 73 case FP_DEVICE_TASK_RETURN_OBJECT:
1142
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 10 taken 73 times.
73 g_clear_object ((GObject **) &data->result);
1143 break;
1144
1145 48 case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
1146
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 10 taken 48 times.
48 g_clear_pointer ((GPtrArray **) &data->result, g_ptr_array_unref);
1147 break;
1148
1149 99 case FP_DEVICE_TASK_RETURN_ERROR:
1150 99 g_clear_error ((GError **) &data->result);
1151 99 break;
1152
1153 default:
1154 g_assert_not_reached ();
1155 }
1156
1157 939 g_object_unref (data->device);
1158 939 g_free (data);
1159 939 }
1160
1161 /**
1162 * fpi_device_return_task_in_idle:
1163 * @device: The #FpDevice
1164 * @return_type: The #FpDeviceTaskReturnType of @return_data
1165 * @return_data: (nullable) (transfer full): The data to return.
1166 *
1167 * Completes a #FpDevice task in an idle source, stealing the ownership of
1168 * the passed @returned_data.
1169 */
1170 static void
1171 939 fpi_device_return_task_in_idle (FpDevice *device,
1172 FpDeviceTaskReturnType return_type,
1173 gpointer return_data)
1174 {
1175 939 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1176 939 FpDeviceTaskReturnData *data;
1177
1178 939 data = g_new0 (FpDeviceTaskReturnData, 1);
1179 939 data->device = g_object_ref (device);
1180 939 data->type = return_type;
1181 939 data->result = return_data;
1182
1183 939 priv->current_task_idle_return_source = g_idle_source_new ();
1184 939 g_source_set_priority (priv->current_task_idle_return_source,
1185 g_task_get_priority (priv->current_task));
1186 939 g_source_set_callback (priv->current_task_idle_return_source,
1187 fp_device_task_return_in_idle_cb,
1188 data,
1189 (GDestroyNotify) fpi_device_task_return_data_free);
1190
1191 939 g_source_attach (priv->current_task_idle_return_source,
1192 g_task_get_context (priv->current_task));
1193 939 g_source_unref (priv->current_task_idle_return_source);
1194 939 }
1195
1196 /**
1197 * fpi_device_probe_complete:
1198 * @device: The #FpDevice
1199 * @device_id: Unique ID for the device or %NULL
1200 * @device_name: Human readable name or %NULL for driver name
1201 * @error: (nullable) (transfer full): The #GError or %NULL on success
1202 *
1203 * Finish an ongoing probe operation. If error is %NULL success is assumed.
1204 */
1205 void
1206 153 fpi_device_probe_complete (FpDevice *device,
1207 const gchar *device_id,
1208 const gchar *device_name,
1209 GError *error)
1210 {
1211 153 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1212
1213
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 153 times.
153 g_return_if_fail (FP_IS_DEVICE (device));
1214
2/2
✓ Branch 6 → 7 taken 152 times.
✓ Branch 6 → 9 taken 1 time.
153 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
1215
1216
1/2
✓ Branch 8 → 10 taken 152 times.
✗ Branch 8 → 13 not taken.
152 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1217 {
1218 304 g_autofree char *error_str = error_to_string (error);
1219
1220 152 g_debug ("Device reported probe completion (ID: %s, name: %s, error: %s)",
1221 device_id, device_name, error_str);
1222 }
1223
1224 152 clear_device_cancel_action (device);
1225 152 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1226
1227
2/2
✓ Branch 15 → 16 taken 150 times.
✓ Branch 15 → 33 taken 2 times.
152 if (!error)
1228 {
1229
2/2
✓ Branch 16 → 17 taken 11 times.
✓ Branch 16 → 24 taken 139 times.
150 if (device_id)
1230 {
1231
1/2
✓ Branch 17 → 18 taken 11 times.
✗ Branch 17 → 19 not taken.
11 g_clear_pointer (&priv->device_id, g_free);
1232
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 11 times.
11 priv->device_id = g_strdup (device_id);
1233 11 g_object_notify (G_OBJECT (device), "device-id");
1234 }
1235
2/2
✓ Branch 24 → 25 taken 6 times.
✓ Branch 24 → 32 taken 144 times.
150 if (device_name)
1236 {
1237
1/2
✓ Branch 25 → 26 taken 6 times.
✗ Branch 25 → 27 not taken.
6 g_clear_pointer (&priv->device_name, g_free);
1238
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 6 times.
6 priv->device_name = g_strdup (device_name);
1239 6 g_object_notify (G_OBJECT (device), "name");
1240 }
1241 150 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1242 GUINT_TO_POINTER (TRUE));
1243 }
1244 else
1245 {
1246 2 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1247 }
1248 }
1249
1250 /**
1251 * fpi_device_open_complete:
1252 * @device: The #FpDevice
1253 * @error: (nullable) (transfer full): The #GError or %NULL on success
1254 *
1255 * Finish an ongoing open operation. If error is %NULL success is assumed.
1256 */
1257 void
1258 225 fpi_device_open_complete (FpDevice *device, GError *error)
1259 {
1260 225 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1261
1262
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 225 times.
225 g_return_if_fail (FP_IS_DEVICE (device));
1263
2/2
✓ Branch 6 → 7 taken 224 times.
✓ Branch 6 → 9 taken 1 time.
225 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_OPEN);
1264
1265
1/2
✓ Branch 8 → 10 taken 224 times.
✗ Branch 8 → 13 not taken.
224 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1266 {
1267 448 g_autofree char *error_str = error_to_string (error);
1268
1269 224 g_debug ("Device reported open completion (error: %s)", error_str);
1270 }
1271
1272 224 clear_device_cancel_action (device);
1273 224 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1274
1275
2/2
✓ Branch 15 → 16 taken 217 times.
✓ Branch 15 → 17 taken 7 times.
224 if (!error)
1276 217 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1277 GUINT_TO_POINTER (TRUE));
1278 else
1279 7 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1280 }
1281
1282 /**
1283 * fpi_device_close_complete:
1284 * @device: The #FpDevice
1285 * @error: (nullable) (transfer full): The #GError or %NULL on success
1286 *
1287 * Finish an ongoing close operation. If error is %NULL success is assumed.
1288 */
1289 void
1290 218 fpi_device_close_complete (FpDevice *device, GError *error)
1291 {
1292 218 g_autoptr(GError) nested_error = NULL;
1293 218 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1294
1295
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 218 times.
218 g_return_if_fail (FP_IS_DEVICE (device));
1296
2/2
✓ Branch 6 → 7 taken 217 times.
✓ Branch 6 → 9 taken 1 time.
218 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLOSE);
1297
1298
1/2
✓ Branch 8 → 10 taken 217 times.
✗ Branch 8 → 13 not taken.
217 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1299 {
1300 434 g_autofree char *error_str = error_to_string (error);
1301
1302 217 g_debug ("Device reported close completion (error: %s)", error_str);
1303 }
1304
1305 217 clear_device_cancel_action (device);
1306 217 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1307
1308
2/3
✓ Branch 15 → 16 taken 33 times.
✗ Branch 15 → 21 not taken.
✓ Branch 15 → 22 taken 184 times.
217 switch (priv->type)
1309 {
1310 33 case FP_DEVICE_TYPE_USB:
1311
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 22 taken 33 times.
33 if (!g_usb_device_close (priv->usb_device, &nested_error))
1312 {
1313 if (error == NULL)
1314 error = g_steal_pointer (&nested_error);
1315
1316 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1317 return;
1318 }
1319 break;
1320
1321 case FP_DEVICE_TYPE_VIRTUAL:
1322 case FP_DEVICE_TYPE_UDEV:
1323 break;
1324
1325 default:
1326 g_assert_not_reached ();
1327 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1328 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1329 return;
1330 }
1331
1332
2/2
✓ Branch 22 → 23 taken 212 times.
✓ Branch 22 → 24 taken 5 times.
217 if (!error)
1333 212 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1334 GUINT_TO_POINTER (TRUE));
1335 else
1336 5 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1337 }
1338
1339 /**
1340 * fpi_device_enroll_complete:
1341 * @device: The #FpDevice
1342 * @print: (nullable) (transfer full): The #FpPrint or %NULL on failure
1343 * @error: (nullable) (transfer full): The #GError or %NULL on success
1344 *
1345 * Finish an ongoing enroll operation. The #FpPrint can be stored by the
1346 * caller for later verification.
1347 */
1348 void
1349 68 fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
1350 {
1351 68 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1352
1353
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 68 times.
68 g_return_if_fail (FP_IS_DEVICE (device));
1354
2/2
✓ Branch 6 → 7 taken 67 times.
✓ Branch 6 → 9 taken 1 time.
68 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
1355
1356
1/2
✓ Branch 8 → 10 taken 67 times.
✗ Branch 8 → 13 not taken.
67 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1357 {
1358 134 g_autofree char *error_str = error_to_string (error);
1359
1360 67 g_debug ("Device reported enroll completion (print: %p, error: %s)",
1361 print, error_str);
1362 }
1363
1364 67 clear_device_cancel_action (device);
1365 67 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1366
1367
2/2
✓ Branch 15 → 16 taken 57 times.
✓ Branch 15 → 38 taken 10 times.
67 if (!error)
1368 {
1369
2/2
✓ Branch 17 → 18 taken 56 times.
✓ Branch 17 → 35 taken 1 time.
57 if (FP_IS_PRINT (print))
1370 {
1371 56 FpiPrintType print_type;
1372
1373 56 g_object_get (print, "fpi-type", &print_type, NULL);
1374
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 26 taken 55 times.
56 if (print_type == FPI_PRINT_UNDEFINED)
1375 {
1376 1 g_warning ("Driver did not set the type on the returned print!");
1377
1/2
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 23 not taken.
1 g_clear_object (&print);
1378
1379 1 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1380 "Driver provided incorrect print data!");
1381 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1382 1 return;
1383 }
1384
1385
1/2
✓ Branch 27 → 28 taken 55 times.
✗ Branch 27 → 33 not taken.
55 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1386 {
1387 110 g_autofree char *finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
1388
1389 55 g_debug ("Print for finger %s enrolled", finger_str);
1390 }
1391
1392 55 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
1393 }
1394 else
1395 {
1396 1 g_warning ("Driver did not provide a valid print and failed to provide an error!");
1397 1 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1398 "Driver failed to provide print data!");
1399 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1400 }
1401 }
1402 else
1403 {
1404 10 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1405
2/2
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 9 times.
10 if (FP_IS_PRINT (print))
1406 {
1407 1 g_warning ("Driver passed an error but also provided a print, returning error!");
1408 1 g_object_unref (print);
1409 }
1410 }
1411 }
1412
1413 /**
1414 * fpi_device_verify_complete:
1415 * @device: The #FpDevice
1416 * @error: A #GError if result is %FPI_MATCH_ERROR
1417 *
1418 * Finish an ongoing verify operation.
1419 *
1420 * Note that @error should only be set for actual errors. In the case
1421 * of retry errors, report these using fpi_device_verify_report()
1422 * and then call this function without any error argument.
1423 *
1424 * If @error is not set, we expect that a result (and print, in case)
1425 * have been already reported via fpi_device_verify_report().
1426 */
1427 void
1428 39 fpi_device_verify_complete (FpDevice *device,
1429 GError *error)
1430 {
1431 39 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1432 39 FpMatchData *data;
1433
1434
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 39 times.
39 g_return_if_fail (FP_IS_DEVICE (device));
1435
2/2
✓ Branch 6 → 7 taken 38 times.
✓ Branch 6 → 9 taken 1 time.
39 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
1436
1437
1/2
✓ Branch 8 → 10 taken 38 times.
✗ Branch 8 → 13 not taken.
38 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1438 {
1439 76 g_autofree char *error_str = error_to_string (error);
1440
1441 38 g_debug ("Device reported verify completion (error: %s)", error_str);
1442 }
1443
1444 38 data = g_task_get_task_data (priv->current_task);
1445
1446 38 clear_device_cancel_action (device);
1447 38 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1448
1449
2/2
✓ Branch 16 → 17 taken 27 times.
✓ Branch 16 → 26 taken 11 times.
38 if (!error)
1450 {
1451
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 21 taken 26 times.
27 if (!data->result_reported)
1452 {
1453 1 g_warning ("Driver reported successful verify complete but did not report the result earlier. Reporting error instead");
1454 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1455 1 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1456 }
1457
2/2
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 23 taken 15 times.
26 else if (data->error)
1458 {
1459 11 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
1460 }
1461 else
1462 {
1463 15 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT,
1464
2/2
✓ Branch 23 → 24 taken 7 times.
✓ Branch 23 → 25 taken 8 times.
15 GINT_TO_POINTER (data->match != NULL ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL));
1465 }
1466 }
1467 else
1468 {
1469 /* Replace a retry error with a general error, this is a driver bug. */
1470
2/2
✓ Branch 27 → 28 taken 2 times.
✓ Branch 27 → 32 taken 9 times.
11 if (error->domain == FP_DEVICE_RETRY)
1471 {
1472 2 g_warning ("Driver reported a retry error to fpi_device_verify_complete. "
1473 "This is not permissible and needs to be reported using "
1474 "fpi_device_verify_report, reporting general verification "
1475 "failure instead.");
1476 2 g_clear_error (&error);
1477 2 error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
1478 }
1479 11 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1480 }
1481 }
1482
1483 /**
1484 * fpi_device_identify_complete:
1485 * @device: The #FpDevice
1486 * @error: (nullable) (transfer full): The #GError or %NULL on success
1487 *
1488 * Finish an ongoing identify operation.
1489 *
1490 * Note that @error should only be set for actual errors. In the case
1491 * of retry errors, report these using fpi_device_identify_report()
1492 * and then call this function without any error argument.
1493 *
1494 * If @error is not set, we expect that a match and / or a print have been
1495 * already reported via fpi_device_identify_report()
1496 */
1497 void
1498 82 fpi_device_identify_complete (FpDevice *device,
1499 GError *error)
1500 {
1501 82 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1502 82 FpMatchData *data;
1503
1504
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 82 times.
82 g_return_if_fail (FP_IS_DEVICE (device));
1505
2/2
✓ Branch 6 → 7 taken 81 times.
✓ Branch 6 → 9 taken 1 time.
82 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
1506
1507
1/2
✓ Branch 8 → 10 taken 81 times.
✗ Branch 8 → 13 not taken.
81 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1508 {
1509 162 g_autofree char *error_str = error_to_string (error);
1510
1511 81 g_debug ("Device reported identify completion (error: %s)", error_str);
1512 }
1513
1514 81 data = g_task_get_task_data (priv->current_task);
1515
1516 81 clear_device_cancel_action (device);
1517 81 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1518
1519
2/2
✓ Branch 16 → 17 taken 62 times.
✓ Branch 16 → 24 taken 19 times.
81 if (!error)
1520 {
1521
2/2
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 21 taken 60 times.
62 if (!data->result_reported)
1522 {
1523 2 g_warning ("Driver reported successful identify complete but did not report the result earlier. Reporting error instead");
1524 2 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1525 2 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1526 }
1527
2/2
✓ Branch 21 → 22 taken 10 times.
✓ Branch 21 → 23 taken 50 times.
60 else if (data->error)
1528 {
1529 10 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
1530 }
1531 else
1532 {
1533 50 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, GUINT_TO_POINTER (TRUE));
1534 }
1535 }
1536 else
1537 {
1538 /* Replace a retry error with a general error, this is a driver bug. */
1539
2/2
✓ Branch 25 → 26 taken 3 times.
✓ Branch 25 → 30 taken 16 times.
19 if (error->domain == FP_DEVICE_RETRY)
1540 {
1541 3 g_warning ("Driver reported a retry error to fpi_device_identify_complete. "
1542 "This is not permissible and needs to be reported using "
1543 "fpi_device_identify_report, reporting general identification "
1544 "failure instead.");
1545 3 g_clear_error (&error);
1546 3 error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
1547 }
1548 19 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1549 }
1550 }
1551
1552
1553 /**
1554 * fpi_device_capture_complete:
1555 * @device: The #FpDevice
1556 * @image: The #FpImage, or %NULL on error
1557 * @error: (nullable) (transfer full): The #GError or %NULL on success
1558 *
1559 * Finish an ongoing capture operation.
1560 */
1561 void
1562 24 fpi_device_capture_complete (FpDevice *device,
1563 FpImage *image,
1564 GError *error)
1565 {
1566 24 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1567
1568
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 24 times.
24 g_return_if_fail (FP_IS_DEVICE (device));
1569
2/2
✓ Branch 6 → 7 taken 23 times.
✓ Branch 6 → 9 taken 1 time.
24 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
1570
1571
1/2
✓ Branch 8 → 10 taken 23 times.
✗ Branch 8 → 13 not taken.
23 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1572 {
1573 46 g_autofree char *error_str = error_to_string (error);
1574
1575 23 g_debug ("Device reported capture completion (image: %p, error: %s)",
1576 image, error_str);
1577 }
1578
1579 23 clear_device_cancel_action (device);
1580 23 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1581
1582
2/2
✓ Branch 15 → 16 taken 18 times.
✓ Branch 15 → 21 taken 5 times.
23 if (!error)
1583 {
1584
1/2
✓ Branch 16 → 17 taken 18 times.
✗ Branch 16 → 18 not taken.
18 if (image)
1585 {
1586 18 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, image);
1587 }
1588 else
1589 {
1590 g_warning ("Driver did not provide an error for a failed capture operation!");
1591 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1592 "Driver failed to provide an error!");
1593 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1594 }
1595 }
1596 else
1597 {
1598 5 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1599
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 25 taken 5 times.
5 if (image)
1600 {
1601 g_warning ("Driver passed an error but also provided an image, returning error!");
1602 g_clear_object (&image);
1603 }
1604 }
1605 }
1606
1607 /**
1608 * fpi_device_delete_complete:
1609 * @device: The #FpDevice
1610 * @error: (nullable) (transfer full): The #GError or %NULL on success
1611 *
1612 * Finish an ongoing delete operation.
1613 */
1614 void
1615 25 fpi_device_delete_complete (FpDevice *device,
1616 GError *error)
1617 {
1618 25 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1619
1620
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 25 times.
25 g_return_if_fail (FP_IS_DEVICE (device));
1621
2/2
✓ Branch 6 → 7 taken 24 times.
✓ Branch 6 → 9 taken 1 time.
25 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
1622
1623
1/2
✓ Branch 8 → 10 taken 24 times.
✗ Branch 8 → 13 not taken.
24 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1624 {
1625 48 g_autofree char *error_str = error_to_string (error);
1626
1627 24 g_debug ("Device reported delete completion (error: %s)", error_str);
1628 }
1629
1630 24 clear_device_cancel_action (device);
1631 24 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1632
1633
2/2
✓ Branch 15 → 16 taken 18 times.
✓ Branch 15 → 17 taken 6 times.
24 if (!error)
1634 18 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1635 GUINT_TO_POINTER (TRUE));
1636 else
1637 6 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1638 }
1639
1640 /**
1641 * fpi_device_list_complete:
1642 * @device: The #FpDevice
1643 * @prints: (element-type FpPrint) (transfer container): Possibly empty array of prints or %NULL on error
1644 * @error: (nullable) (transfer full): The #GError or %NULL on success
1645 *
1646 * Finish an ongoing list operation.
1647 *
1648 * Please note that the @prints array will be free'ed using
1649 * g_ptr_array_unref() and the elements are destroyed automatically.
1650 * As such, you must use g_ptr_array_new_with_free_func() with
1651 * g_object_unref() as free func to create the array.
1652 */
1653 void
1654 53 fpi_device_list_complete (FpDevice *device,
1655 GPtrArray *prints,
1656 GError *error)
1657 {
1658 53 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1659
1660
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 53 times.
53 g_return_if_fail (FP_IS_DEVICE (device));
1661
2/2
✓ Branch 6 → 7 taken 52 times.
✓ Branch 6 → 9 taken 1 time.
53 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_LIST);
1662
1663
1/2
✓ Branch 8 → 10 taken 52 times.
✗ Branch 8 → 15 not taken.
52 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1664 {
1665 104 g_autofree char *error_str = error_to_string (error);
1666
1667
2/2
✓ Branch 11 → 12 taken 48 times.
✓ Branch 11 → 13 taken 4 times.
52 g_debug ("Device reported listing completion (prints: %ld, error: %s)",
1668 prints ? (long) prints->len : -1, error_str);
1669 }
1670
1671 52 clear_device_cancel_action (device);
1672 52 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1673
1674
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 52 times.
52 if (prints && error)
1675 {
1676 g_warning ("Driver reported back prints and error, ignoring prints");
1677 g_clear_pointer (&prints, g_ptr_array_unref);
1678 }
1679
3/4
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 24 taken 48 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 26 taken 4 times.
52 else if (!prints && !error)
1680 {
1681 g_warning ("Driver did not pass array but failed to provide an error");
1682 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1683 "Driver failed to provide a list of prints");
1684 }
1685
1686
1/2
✓ Branch 24 → 25 taken 48 times.
✗ Branch 24 → 26 not taken.
48 if (!error)
1687 48 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_PTR_ARRAY, prints);
1688 else
1689 4 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1690 }
1691
1692 static int
1693 66 update_attr (const char *attr, const char *value)
1694 {
1695 66 int fd, err;
1696 66 gssize r;
1697 66 char buf[50] = { 0 };
1698
1699 66 fd = open (attr, O_RDONLY);
1700 66 err = -errno;
1701
2/2
✓ Branch 3 → 4 taken 60 times.
✓ Branch 3 → 19 taken 6 times.
66 if (fd < 0)
1702 return -err;
1703
1704 60 r = read (fd, buf, sizeof (buf) - 1);
1705 60 err = errno;
1706 60 close (fd);
1707
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 60 times.
60 if (r < 0)
1708 return -err;
1709
1710 60 g_strchomp (buf);
1711
2/2
✓ Branch 10 → 11 taken 17 times.
✓ Branch 10 → 19 taken 43 times.
60 if (g_strcmp0 (buf, value) == 0)
1712 return 0;
1713
1714 /* O_TRUNC makes things work in the umockdev environment */
1715 17 fd = open (attr, O_WRONLY | O_TRUNC);
1716 17 err = errno;
1717
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 17 times.
17 if (fd < 0)
1718 return -err;
1719
1720 17 r = write (fd, value, strlen (value));
1721 17 err = -errno;
1722 17 close (fd);
1723
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 17 times.
17 if (r < 0)
1724 {
1725 /* Write failures are weird, and are worth a warning */
1726 g_warning ("Could not write %s to %s", value, attr);
1727 return -err;
1728 }
1729
1730 return 0;
1731 }
1732
1733 static void
1734 complete_suspend_resume_task (FpDevice *device)
1735 {
1736 g_autoptr(GTask) task = NULL;
1737 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1738
1739 g_assert (priv->suspend_resume_task);
1740 task = g_steal_pointer (&priv->suspend_resume_task);
1741
1742 g_task_return_boolean (task, TRUE);
1743 }
1744
1745 void
1746 9 fpi_device_suspend (FpDevice *device)
1747 {
1748 9 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1749
1750 /* If the device is currently idle, just complete immediately.
1751 * For long running tasks, call the driver handler right away, for short
1752 * tasks, wait for completion and then return the task.
1753 */
1754
2/3
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 7 times.
✗ Branch 3 → 12 not taken.
9 switch (priv->current_action)
1755 {
1756 2 case FPI_DEVICE_ACTION_NONE:
1757 2 fpi_device_suspend_complete (device, NULL);
1758 2 break;
1759
1760 case FPI_DEVICE_ACTION_ENROLL:
1761 case FPI_DEVICE_ACTION_VERIFY:
1762 case FPI_DEVICE_ACTION_IDENTIFY:
1763 case FPI_DEVICE_ACTION_CAPTURE:
1764
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 10 not taken.
7 if (FP_DEVICE_GET_CLASS (device)->suspend)
1765 {
1766
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 if (priv->critical_section)
1767 2 priv->suspend_queued = TRUE;
1768 else
1769 5 FP_DEVICE_GET_CLASS (device)->suspend (device);
1770 }
1771 else
1772 {
1773 fpi_device_suspend_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1774 }
1775 break;
1776
1777 default:
1778 case FPI_DEVICE_ACTION_PROBE:
1779 case FPI_DEVICE_ACTION_OPEN:
1780 case FPI_DEVICE_ACTION_CLOSE:
1781 case FPI_DEVICE_ACTION_DELETE:
1782 case FPI_DEVICE_ACTION_LIST:
1783 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
1784 g_signal_connect_object (priv->current_task,
1785 "notify::completed",
1786 G_CALLBACK (complete_suspend_resume_task),
1787 device,
1788 G_CONNECT_SWAPPED);
1789
1790 break;
1791 }
1792 9 }
1793
1794 void
1795 8 fpi_device_resume (FpDevice *device)
1796 {
1797 8 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1798
1799
2/3
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 4 times.
✗ Branch 3 → 11 not taken.
8 switch (priv->current_action)
1800 {
1801 4 case FPI_DEVICE_ACTION_NONE:
1802 4 fpi_device_resume_complete (device, NULL);
1803 4 break;
1804
1805 case FPI_DEVICE_ACTION_ENROLL:
1806 case FPI_DEVICE_ACTION_VERIFY:
1807 case FPI_DEVICE_ACTION_IDENTIFY:
1808 case FPI_DEVICE_ACTION_CAPTURE:
1809
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 9 not taken.
4 if (FP_DEVICE_GET_CLASS (device)->resume)
1810 {
1811
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 3 times.
4 if (priv->critical_section)
1812 1 priv->resume_queued = TRUE;
1813 else
1814 3 FP_DEVICE_GET_CLASS (device)->resume (device);
1815 }
1816 else
1817 {
1818 fpi_device_resume_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1819 }
1820 break;
1821
1822 default:
1823 case FPI_DEVICE_ACTION_PROBE:
1824 case FPI_DEVICE_ACTION_OPEN:
1825 case FPI_DEVICE_ACTION_CLOSE:
1826 case FPI_DEVICE_ACTION_DELETE:
1827 case FPI_DEVICE_ACTION_LIST:
1828 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
1829 /* cannot happen as we make sure these tasks complete before suspend */
1830 g_assert_not_reached ();
1831 complete_suspend_resume_task (device);
1832 break;
1833 }
1834 8 }
1835
1836 void
1837 162 fpi_device_configure_wakeup (FpDevice *device, gboolean enabled)
1838 {
1839 162 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1840
1841
2/3
✓ Branch 3 → 4 taken 33 times.
✗ Branch 3 → 34 not taken.
✓ Branch 3 → 35 taken 129 times.
162 switch (priv->type)
1842 {
1843 33 case FP_DEVICE_TYPE_USB:
1844 {
1845 66 g_autoptr(GString) ports = NULL;
1846 33 g_autoptr(GUsbDevice) dev = NULL;
1847
2/2
✓ Branch 4 → 5 taken 32 times.
✓ Branch 4 → 6 taken 1 time.
33 const char *wakeup_command = enabled ? "enabled" : "disabled";
1848 33 guint8 bus;
1849
1/2
✓ Branch 30 → 31 taken 33 times.
✗ Branch 30 → 32 not taken.
33 g_autofree gchar *sysfs_wakeup = NULL;
1850 33 g_autofree gchar *sysfs_persist = NULL;
1851 33 int res;
1852
1853 33 ports = g_string_new (NULL);
1854 33 bus = g_usb_device_get_bus (priv->usb_device);
1855
1856 /* Walk up, skipping the root hub. */
1857 33 g_set_object (&dev, priv->usb_device);
1858 113 while (TRUE)
1859 40 {
1860 113 g_autoptr(GUsbDevice) parent = g_usb_device_get_parent (dev);
1861 73 g_autofree gchar *port_str = NULL;
1862 73 guint8 port;
1863
1864
2/2
✓ Branch 10 → 11 taken 40 times.
✓ Branch 10 → 18 taken 33 times.
73 if (!parent)
1865 break;
1866
1867 40 port = g_usb_device_get_port_number (dev);
1868 40 port_str = g_strdup_printf ("%d.", port);
1869 40 g_string_prepend (ports, port_str);
1870 40 g_set_object (&dev, parent);
1871 }
1872 33 g_string_set_size (ports, ports->len - 1);
1873
1874 33 sysfs_wakeup = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/wakeup", bus, ports->str);
1875 33 res = update_attr (sysfs_wakeup, wakeup_command);
1876
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 33 times.
33 if (res < 0)
1877 g_debug ("Failed to set %s to %s", sysfs_wakeup, wakeup_command);
1878
1879 /* Persist means that the kernel tries to keep the USB device open
1880 * in case it is "replugged" due to suspend.
1881 * This is not helpful, as it will receive a reset and will be in a bad
1882 * state. Instead, seeing an unplug and a new device makes more sense.
1883 */
1884 33 sysfs_persist = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/persist", bus, ports->str);
1885 33 res = update_attr (sysfs_persist, "0");
1886
1/2
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 33 times.
33 if (res < 0)
1887 g_warning ("Failed to disable USB persist by writing to %s", sysfs_persist);
1888
1889 33 break;
1890 }
1891
1892 case FP_DEVICE_TYPE_VIRTUAL:
1893 case FP_DEVICE_TYPE_UDEV:
1894 break;
1895
1896 default:
1897 g_assert_not_reached ();
1898 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1899 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1900 return;
1901 }
1902 }
1903
1904 static void
1905 7 fpi_device_suspend_completed (FpDevice *device)
1906 {
1907 14 g_autoptr(GTask) task = NULL;
1908 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1909
1910 /* We have an ongoing operation, allow the device to wake up the machine. */
1911
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 4 times.
7 if (priv->current_action != FPI_DEVICE_ACTION_NONE)
1912 3 fpi_device_configure_wakeup (device, TRUE);
1913
1914
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 7 times.
7 if (priv->critical_section)
1915 g_warning ("Driver was in a critical section at suspend time. It likely deadlocked!");
1916
1917
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 task = g_steal_pointer (&priv->suspend_resume_task);
1918
1919
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 if (priv->suspend_error)
1920 2 g_task_return_error (task, g_steal_pointer (&priv->suspend_error));
1921 else
1922 5 g_task_return_boolean (task, TRUE);
1923 7 }
1924
1925 /**
1926 * fpi_device_suspend_complete:
1927 * @device: The #FpDevice
1928 * @error: (nullable) (transfer full): The #GError or %NULL on success
1929 *
1930 * Finish a suspend request. Only return a %NULL error if suspend has been
1931 * correctly configured and the current action as returned by
1932 * fpi_device_get_current_action() will continue to run after resume.
1933 *
1934 * In all other cases an error must be returned. Should this happen, the
1935 * current action will be cancelled before the error is forwarded to the
1936 * application.
1937 *
1938 * It is recommended to set @error to #FP_DEVICE_ERROR_NOT_SUPPORTED.
1939 */
1940 void
1941 7 fpi_device_suspend_complete (FpDevice *device,
1942 GError *error)
1943 {
1944 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1945
1946
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
1947
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 8 not taken.
7 g_return_if_fail (priv->suspend_resume_task);
1948
1/2
✓ Branch 7 → 9 taken 7 times.
✗ Branch 7 → 11 not taken.
7 g_return_if_fail (priv->suspend_error == NULL);
1949
1950
1/2
✓ Branch 10 → 12 taken 7 times.
✗ Branch 10 → 15 not taken.
7 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1951 {
1952 14 g_autofree char *error_str = error_to_string (error);
1953
1954 7 g_debug ("Device reported suspend completion (error: %s)", error_str);
1955 }
1956
1957
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 5 times.
7 priv->suspend_error = g_steal_pointer (&error);
1958 7 priv->is_suspended = TRUE;
1959
1960 /* If there is no error, we have no running task, return immediately. */
1961
4/6
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 5 times.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 21 taken 2 times.
9 if (!priv->suspend_error || !priv->current_task ||
1962 2 g_task_get_completed (priv->current_task))
1963 {
1964 5 fpi_device_suspend_completed (device);
1965 5 return;
1966 }
1967
1968 /* Wait for completion of the current task. */
1969 2 g_signal_connect_object (priv->current_task,
1970 "notify::completed",
1971 G_CALLBACK (fpi_device_suspend_completed),
1972 device,
1973 G_CONNECT_SWAPPED);
1974
1975 /* And cancel any action that might be long-running. */
1976
1/2
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 25 not taken.
2 if (!priv->current_cancellation_reason)
1977 2 priv->current_cancellation_reason = fpi_device_error_new_msg (FP_DEVICE_ERROR_BUSY,
1978 "Cannot run while suspended.");
1979
1980 2 g_cancellable_cancel (priv->current_cancellable);
1981 }
1982
1983 /**
1984 * fpi_device_resume_complete:
1985 * @device: The #FpDevice
1986 * @error: (nullable) (transfer full): The #GError or %NULL on success
1987 *
1988 * Finish a resume request.
1989 */
1990 void
1991 7 fpi_device_resume_complete (FpDevice *device,
1992 GError *error)
1993 {
1994 14 g_autoptr(GTask) task = NULL;
1995 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1996
1997
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
1998
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 9 not taken.
7 g_return_if_fail (priv->suspend_resume_task);
1999
2000
1/2
✓ Branch 8 → 10 taken 7 times.
✗ Branch 8 → 13 not taken.
7 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2001 {
2002 14 g_autofree char *error_str = error_to_string (error);
2003
2004 7 g_debug ("Device reported resume completion (error: %s)", error_str);
2005 }
2006
2007 7 priv->is_suspended = FALSE;
2008 7 fpi_device_configure_wakeup (device, FALSE);
2009
2010
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 7 times.
7 task = g_steal_pointer (&priv->suspend_resume_task);
2011
2012
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 7 times.
7 if (error)
2013 g_task_return_error (task, error);
2014 else
2015 7 g_task_return_boolean (task, TRUE);
2016 }
2017
2018 /**
2019 * fpi_device_clear_storage_complete:
2020 * @device: The #FpDevice
2021 * @error: (nullable) (transfer full): The #GError or %NULL on success
2022 *
2023 * Finish an ongoing clear_storage operation.
2024 */
2025 void
2026 61 fpi_device_clear_storage_complete (FpDevice *device,
2027 GError *error)
2028 {
2029 61 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2030
2031
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 61 times.
61 g_return_if_fail (FP_IS_DEVICE (device));
2032
1/2
✓ Branch 6 → 7 taken 61 times.
✗ Branch 6 → 9 not taken.
61 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLEAR_STORAGE);
2033
2034
1/2
✓ Branch 8 → 10 taken 61 times.
✗ Branch 8 → 13 not taken.
61 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2035 {
2036 122 g_autofree char *error_str = error_to_string (error);
2037
2038 61 g_debug ("Device reported clear storage completion (error: %s)", error_str);
2039 }
2040
2041 61 clear_device_cancel_action (device);
2042 61 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
2043
2044
2/2
✓ Branch 15 → 16 taken 57 times.
✓ Branch 15 → 17 taken 4 times.
61 if (!error)
2045 57 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
2046 GUINT_TO_POINTER (TRUE));
2047 else
2048 4 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
2049 }
2050
2051 /**
2052
2053 * fpi_device_enroll_progress:
2054 * @device: The #FpDevice
2055 * @completed_stages: The number of stages that are completed at this point
2056 * @print: (transfer floating): The #FpPrint for the newly completed stage or %NULL on failure
2057 * @error: (nullable) (transfer full): The #GError or %NULL on success
2058 *
2059 * Notify about the progress of the enroll operation. This is important for UI interaction.
2060 * The passed error may be used if a scan needs to be retried, use fpi_device_retry_new().
2061 */
2062 void
2063 480 fpi_device_enroll_progress (FpDevice *device,
2064 gint completed_stages,
2065 FpPrint *print,
2066 GError *error)
2067 {
2068 480 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2069 480 FpEnrollData *data;
2070
2071
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 480 times.
480 g_return_if_fail (FP_IS_DEVICE (device));
2072
2/2
✓ Branch 6 → 7 taken 479 times.
✓ Branch 6 → 8 taken 1 time.
480 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
2073
4/4
✓ Branch 7 → 9 taken 75 times.
✓ Branch 7 → 11 taken 404 times.
✓ Branch 10 → 11 taken 74 times.
✓ Branch 10 → 13 taken 1 time.
479 g_return_if_fail (error == NULL || error->domain == FP_DEVICE_RETRY);
2074
2075 478 g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages);
2076
2077
2/2
✓ Branch 12 → 14 taken 308 times.
✓ Branch 12 → 15 taken 170 times.
478 if (print)
2078 308 g_object_ref_sink (print);
2079
2080
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 18 taken 477 times.
478 if (error && print)
2081 {
2082 1 g_warning ("Driver passed an error and also provided a print, returning error!");
2083 1 g_clear_object (&print);
2084 }
2085
2086 478 data = g_task_get_task_data (priv->current_task);
2087
2088
2/2
✓ Branch 19 → 20 taken 422 times.
✓ Branch 19 → 21 taken 56 times.
478 if (data->enroll_progress_cb)
2089 {
2090 422 data->enroll_progress_cb (device,
2091 completed_stages,
2092 print,
2093 data->enroll_progress_data,
2094 error);
2095 }
2096
2097 478 g_clear_error (&error);
2098
2/2
✓ Branch 22 → 23 taken 307 times.
✓ Branch 22 → 24 taken 171 times.
478 g_clear_object (&print);
2099 }
2100
2101 /**
2102 * fpi_device_verify_report:
2103 * @device: The #FpDevice
2104 * @result: The #FpiMatchResult of the operation
2105 * @print: (transfer floating) The scanned #FpPrint
2106 * @error: A #GError if result is %FPI_MATCH_ERROR
2107 *
2108 * Report the result of a verify operation. Note that the passed @error must be
2109 * a retry error with the %FP_DEVICE_RETRY domain. For all other error cases,
2110 * the error should passed to fpi_device_verify_complete().
2111 */
2112 void
2113 28 fpi_device_verify_report (FpDevice *device,
2114 FpiMatchResult result,
2115 FpPrint *print,
2116 GError *error)
2117 {
2118 28 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2119 28 FpMatchData *data = g_task_get_task_data (priv->current_task);
2120 28 gboolean call_cb = TRUE;
2121
2122
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 28 times.
28 g_return_if_fail (FP_IS_DEVICE (device));
2123
1/2
✓ Branch 7 → 8 taken 28 times.
✗ Branch 7 → 9 not taken.
28 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
2124
1/2
✓ Branch 8 → 10 taken 28 times.
✗ Branch 8 → 12 not taken.
28 g_return_if_fail (data->result_reported == FALSE);
2125
2126 28 data->result_reported = TRUE;
2127
2128
1/2
✓ Branch 11 → 13 taken 28 times.
✗ Branch 11 → 19 not taken.
28 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2129 {
2130 56 g_autofree char *result_str = g_enum_to_string (FPI_TYPE_MATCH_RESULT, result);
2131 56 g_autofree char *error_str = error_to_string (error);
2132
2133 28 g_debug ("Device reported verify result (result: %s, print: %p, error: %s)",
2134 result_str, print, error_str);
2135 }
2136
2137
2/2
✓ Branch 19 → 20 taken 13 times.
✓ Branch 19 → 21 taken 15 times.
28 if (print)
2138 13 print = g_object_ref_sink (print);
2139
2140
2/2
✓ Branch 21 → 22 taken 13 times.
✓ Branch 21 → 33 taken 15 times.
28 if (error || result == FPI_MATCH_ERROR)
2141 {
2142
2/2
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 11 times.
13 if (result != FPI_MATCH_ERROR)
2143 2 g_warning ("Driver reported an error code without setting match result to error!");
2144
2145
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 12 times.
13 if (error == NULL)
2146 {
2147 1 g_warning ("Driver reported an error without specifying a retry code, assuming general retry error!");
2148 1 error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
2149 }
2150
2151
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 30 taken 12 times.
13 if (print)
2152 {
2153 1 g_warning ("Driver reported a print together with an error!");
2154 1 g_clear_object (&print);
2155 }
2156
2157 13 data->error = error;
2158
2159
2/2
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 44 taken 12 times.
13 if (error->domain != FP_DEVICE_RETRY)
2160 {
2161 1 g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
2162 1 call_cb = FALSE;
2163 }
2164 }
2165 else
2166 {
2167
2/2
✓ Branch 33 → 34 taken 8 times.
✓ Branch 33 → 43 taken 7 times.
15 if (result == FPI_MATCH_SUCCESS)
2168 {
2169 8 fpi_device_get_verify_data (device, &data->match);
2170 8 g_object_ref (data->match);
2171
2172
3/4
✓ Branch 36 → 37 taken 7 times.
✓ Branch 36 → 43 taken 1 time.
✓ Branch 38 → 39 taken 7 times.
✗ Branch 38 → 43 not taken.
15 if (print &&
2173
2/2
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 6 times.
14 fpi_print_get_type (print) != FPI_PRINT_NBIS &&
2174 7 !fp_print_equal (print, data->match))
2175 {
2176 1 g_warning ("Driver reported a match providing a scanned print that is not matching it.");
2177 1 g_clear_object (&print);
2178 }
2179 }
2180
2181 15 data->print = g_steal_pointer (&print);
2182 }
2183
2184
2/2
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 46 taken 12 times.
28 if (call_cb && data->match_cb)
2185 15 data->match_cb (device, data->match, data->print, data->match_data, data->error);
2186 }
2187
2188 /**
2189 * fpi_device_identify_report:
2190 * @device: The #FpDevice
2191 * @match: (transfer none): The #FpPrint from the gallery that matched
2192 * @print: (transfer floating): The scanned #FpPrint, set in the absence
2193 * of an error.
2194 * @error: A #GError of %FP_DEVICE_RETRY type if @match and @print are unset.
2195 *
2196 * Report the results of an identify operation.
2197 *
2198 * In case of successful identification @match is expected to be set to a
2199 * #FpPrint that matches one from the provided gallery, while @print
2200 * represents the scanned print and will be different.
2201 *
2202 * If there are no errors, it's expected that the device always reports the
2203 * recognized @print even if there is no @match with the provided gallery (that
2204 * can be potentially empty). This is required for application logic further
2205 * up in the stack, such as for enroll-duplicate checking. @print needs to be
2206 * sufficiently filled to do a comparison.
2207 *
2208 * In case of error, both @match and @print are expected to be %NULL.
2209 * Note that the passed @error must be a retry error from the %FP_DEVICE_RETRY
2210 * domain. For all other error cases, the error should passed to
2211 * fpi_device_identify_complete().
2212 */
2213 void
2214 64 fpi_device_identify_report (FpDevice *device,
2215 FpPrint *match,
2216 FpPrint *print,
2217 GError *error)
2218 {
2219 64 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2220 64 FpMatchData *data = g_task_get_task_data (priv->current_task);
2221 64 gboolean call_cb = TRUE;
2222
2223
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 64 times.
64 g_return_if_fail (FP_IS_DEVICE (device));
2224
1/2
✓ Branch 7 → 8 taken 64 times.
✗ Branch 7 → 9 not taken.
64 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
2225
1/2
✓ Branch 8 → 10 taken 64 times.
✗ Branch 8 → 11 not taken.
64 g_return_if_fail (data->result_reported == FALSE);
2226
2227 64 data->result_reported = TRUE;
2228
2229
2/2
✓ Branch 10 → 12 taken 39 times.
✓ Branch 10 → 13 taken 25 times.
64 if (match)
2230 39 g_object_ref (match);
2231
2232
2/2
✓ Branch 13 → 14 taken 45 times.
✓ Branch 13 → 15 taken 19 times.
64 if (print)
2233 45 print = g_object_ref_sink (print);
2234
2235
1/2
✓ Branch 16 → 17 taken 64 times.
✗ Branch 16 → 20 not taken.
64 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2236 {
2237 128 g_autofree char *error_str = error_to_string (error);
2238
2239 64 g_debug ("Device reported identify result (match: %p, print: %p, error: %s)",
2240 match, print, error_str);
2241 }
2242
2243
4/4
✓ Branch 20 → 21 taken 39 times.
✓ Branch 20 → 25 taken 25 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 25 taken 37 times.
64 if (match && !g_ptr_array_find (data->gallery, match, NULL))
2244 {
2245 2 g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match.");
2246 2 g_clear_object (&match);
2247 }
2248
2249
2/2
✓ Branch 25 → 26 taken 14 times.
✓ Branch 25 → 35 taken 50 times.
64 if (error)
2250 {
2251
2/2
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 29 taken 13 times.
14 if (match != NULL)
2252 {
2253 1 g_warning ("Driver reported an error code but also provided a match!");
2254 1 g_clear_object (&match);
2255 }
2256
2257
2/2
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 32 taken 12 times.
14 if (print)
2258 {
2259 2 g_warning ("Driver reported a print together with an error!");
2260 2 g_clear_object (&print);
2261 }
2262
2263 14 data->error = error;
2264
2265
2/2
✓ Branch 33 → 34 taken 2 times.
✓ Branch 33 → 46 taken 12 times.
14 if (error->domain != FP_DEVICE_RETRY)
2266 {
2267 2 g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
2268 2 call_cb = FALSE;
2269 }
2270 }
2271 else
2272 {
2273
7/8
✓ Branch 35 → 36 taken 36 times.
✓ Branch 35 → 44 taken 14 times.
✓ Branch 36 → 37 taken 36 times.
✗ Branch 36 → 43 not taken.
✓ Branch 38 → 39 taken 30 times.
✓ Branch 38 → 43 taken 6 times.
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 29 times.
80 if (match && print && fpi_print_get_type (print) != FPI_PRINT_NBIS &&
2274 30 !g_ptr_array_find_with_equal_func (data->gallery, print,
2275 (GEqualFunc) fp_print_equal, NULL))
2276 {
2277 1 g_warning ("Driver reported a match providing a scanned print that is not matching any in the gallery.");
2278 1 g_clear_object (&print);
2279 }
2280
2281 36 if (match)
2282 36 data->match = g_steal_pointer (&match);
2283
2284
2/2
✓ Branch 44 → 45 taken 42 times.
✓ Branch 44 → 46 taken 8 times.
50 if (print)
2285 42 data->print = g_steal_pointer (&print);
2286 }
2287
2288
2/2
✓ Branch 46 → 47 taken 28 times.
✓ Branch 46 → 48 taken 34 times.
64 if (call_cb && data->match_cb)
2289 28 data->match_cb (device, data->match, data->print, data->match_data, data->error);
2290 }
2291
2292 /**
2293 * fpi_device_report_finger_status:
2294 * @device: The #FpDevice
2295 * @finger_status: The current #FpFingerStatusFlags to report
2296 *
2297 * Report the finger status for the @device.
2298 * This can be used by UI to give a feedback
2299 *
2300 * Returns: %TRUE if changed
2301 */
2302 gboolean
2303 3032 fpi_device_report_finger_status (FpDevice *device,
2304 FpFingerStatusFlags finger_status)
2305 {
2306 3032 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2307
2308
2/2
✓ Branch 3 → 4 taken 1260 times.
✓ Branch 3 → 15 taken 1772 times.
3032 if (priv->finger_status == finger_status)
2309 return FALSE;
2310
2311
1/2
✓ Branch 5 → 6 taken 1260 times.
✗ Branch 5 → 13 not taken.
1260 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2312 {
2313 1260 g_autofree char *status_string = NULL;
2314 1260 g_autofree char *old_status_string = NULL;
2315
2316 1260 old_status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, priv->finger_status);
2317 1260 status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
2318
2319 1260 g_debug ("Device reported finger status change: %s -> %s",
2320 old_status_string, status_string);
2321 }
2322
2323 1260 priv->finger_status = finger_status;
2324 1260 g_object_notify (G_OBJECT (device), "finger-status");
2325
2326 1260 return TRUE;
2327 }
2328
2329 /**
2330 * fpi_device_report_finger_status_changes:
2331 * @device: The #FpDevice
2332 * @added_status: The #FpFingerStatusFlags to add
2333 * @removed_status: The #FpFingerStatusFlags to remove
2334 *
2335 * Report the finger status for the @device adding the @added_status flags
2336 * and removing the @removed_status flags.
2337 *
2338 * This can be used by UI to give a feedback
2339 *
2340 * Returns: %TRUE if changed
2341 */
2342 gboolean
2343 1425 fpi_device_report_finger_status_changes (FpDevice *device,
2344 FpFingerStatusFlags added_status,
2345 FpFingerStatusFlags removed_status)
2346 {
2347 1425 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2348 1425 FpFingerStatusFlags finger_status = priv->finger_status;
2349
2350 1425 finger_status |= added_status;
2351 1425 finger_status &= ~removed_status;
2352
2353 1425 return fpi_device_report_finger_status (device, finger_status);
2354 }
2355
2356 static void
2357 31 update_temp_timeout (FpDevice *device, gpointer user_data)
2358 {
2359 31 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2360
2361 31 fpi_device_update_temp (device, priv->temp_last_active);
2362 31 }
2363
2364 /**
2365 * fpi_device_update_temp:
2366 * @device: The #FpDevice
2367 * @is_active: Whether the device is now active
2368 *
2369 * Purely internal function to update the temperature. Also ensure that the
2370 * state is updated once a threshold is reached.
2371 */
2372 void
2373 1181 fpi_device_update_temp (FpDevice *device, gboolean is_active)
2374 {
2375 1181 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2376 1181 gint64 now = g_get_monotonic_time ();
2377 1181 gdouble passed_seconds;
2378 1181 gdouble alpha;
2379 1181 gdouble next_threshold;
2380 1181 gdouble old_ratio;
2381 1181 FpTemperature old_temp;
2382
2383
2/2
✓ Branch 4 → 5 taken 126 times.
✓ Branch 4 → 7 taken 1055 times.
1181 if (priv->temp_hot_seconds < 0)
2384 {
2385 126 g_debug ("Not updating temperature model, device can run continuously!");
2386 126 return;
2387 }
2388
2389 1055 passed_seconds = (now - priv->temp_last_update) / 1e6;
2390 1055 old_ratio = priv->temp_current_ratio;
2391
2392
2/2
✓ Branch 7 → 8 taken 207 times.
✓ Branch 7 → 9 taken 848 times.
1055 if (priv->temp_last_active)
2393 {
2394 207 alpha = exp (-passed_seconds / priv->temp_hot_seconds);
2395 207 priv->temp_current_ratio = alpha * priv->temp_current_ratio + 1 - alpha;
2396 }
2397 else
2398 {
2399 848 alpha = exp (-passed_seconds / priv->temp_cold_seconds);
2400 848 priv->temp_current_ratio = alpha * priv->temp_current_ratio;
2401 }
2402
2403 1055 priv->temp_last_active = is_active;
2404 1055 priv->temp_last_update = now;
2405
2406 1055 old_temp = priv->temp_current;
2407
2/2
✓ Branch 10 → 11 taken 687 times.
✓ Branch 10 → 12 taken 368 times.
1055 if (priv->temp_current_ratio < TEMP_COLD_THRESH)
2408 {
2409 687 priv->temp_current = FP_TEMPERATURE_COLD;
2410
2/2
✓ Branch 11 → 20 taken 116 times.
✓ Branch 11 → 21 taken 571 times.
687 next_threshold = is_active ? TEMP_COLD_THRESH : -1.0;
2411 }
2412
2/2
✓ Branch 12 → 13 taken 364 times.
✓ Branch 12 → 14 taken 4 times.
368 else if (priv->temp_current_ratio < TEMP_HOT_WARM_THRESH)
2413 {
2414 364 priv->temp_current = FP_TEMPERATURE_WARM;
2415
2/2
✓ Branch 13 → 20 taken 275 times.
✓ Branch 13 → 21 taken 89 times.
480 next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_COLD_THRESH;
2416 }
2417
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 19 taken 4 times.
4 else if (priv->temp_current_ratio < TEMP_WARM_HOT_THRESH)
2418 {
2419 /* Keep HOT until we reach TEMP_HOT_WARM_THRESH */
2420 if (priv->temp_current != FP_TEMPERATURE_HOT)
2421 priv->temp_current = FP_TEMPERATURE_WARM;
2422
2423 next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_HOT_WARM_THRESH;
2424 }
2425 else
2426 {
2427 4 priv->temp_current = FP_TEMPERATURE_HOT;
2428
2/2
✓ Branch 19 → 18 taken 2 times.
✓ Branch 19 → 21 taken 2 times.
4 next_threshold = is_active ? -1.0 : TEMP_HOT_WARM_THRESH;
2429 }
2430
2431
1/2
✓ Branch 22 → 23 taken 1055 times.
✗ Branch 22 → 30 not taken.
1055 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2432 {
2433 2110 g_autofree char *old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
2434 2110 g_autofree char *new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
2435
2436 1055 g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
2437 passed_seconds,
2438 old_ratio,
2439 priv->temp_current_ratio,
2440 priv->temp_last_active,
2441 is_active,
2442 old_temp_str,
2443 new_temp_str);
2444 }
2445
2446
2/2
✓ Branch 30 → 31 taken 94 times.
✓ Branch 30 → 32 taken 961 times.
1055 if (priv->temp_current != old_temp)
2447 94 g_object_notify (G_OBJECT (device), "temperature");
2448
2449 /* If the device is HOT, then do an internal cancellation of long running tasks. */
2450
2/2
✓ Branch 32 → 33 taken 4 times.
✓ Branch 32 → 38 taken 1051 times.
1055 if (priv->temp_current == FP_TEMPERATURE_HOT)
2451 {
2452 4 if (priv->current_action == FPI_DEVICE_ACTION_ENROLL ||
2453 priv->current_action == FPI_DEVICE_ACTION_VERIFY ||
2454
2/2
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 38 taken 3 times.
4 priv->current_action == FPI_DEVICE_ACTION_IDENTIFY ||
2455 priv->current_action == FPI_DEVICE_ACTION_CAPTURE)
2456 {
2457
1/2
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 37 not taken.
1 if (!priv->current_cancellation_reason)
2458 1 priv->current_cancellation_reason = fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT);
2459
2460 1 g_cancellable_cancel (priv->current_cancellable);
2461 }
2462 }
2463
2464
2/2
✓ Branch 38 → 39 taken 400 times.
✓ Branch 38 → 40 taken 655 times.
1055 g_clear_pointer (&priv->temp_timeout, g_source_destroy);
2465
2466
2/2
✓ Branch 40 → 41 taken 482 times.
✓ Branch 40 → 46 taken 573 times.
1055 if (next_threshold < 0)
2467 return;
2468
2469 /* Set passed_seconds to the time until the next update is needed */
2470
2/2
✓ Branch 41 → 42 taken 205 times.
✓ Branch 41 → 43 taken 277 times.
482 if (is_active)
2471 205 passed_seconds = -priv->temp_hot_seconds * log ((next_threshold - 1.0) / (priv->temp_current_ratio - 1.0));
2472 else
2473 277 passed_seconds = -priv->temp_cold_seconds * log (next_threshold / priv->temp_current_ratio);
2474
2475 482 passed_seconds += TEMP_DELAY_SECONDS;
2476
2477 482 priv->temp_timeout = fpi_device_add_timeout (device,
2478 482 passed_seconds * 1000,
2479 update_temp_timeout,
2480 NULL, NULL);
2481 }
2482