GCC Code Coverage Report


Directory: ./
File: libfprint/fpi-device.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 799 851 93.9%
Functions: 58 59 98.3%
Branches: 374 489 76.5%

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