GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.9% 802 / 0 / 854
Functions: 98.3% 58 / 0 / 59
Branches: 76.5% 375 / 0 / 490

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