GCC Code Coverage Report


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