From 8a5bec6619d14770520bd90bab0336276756c45a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 25 Jun 2021 16:13:13 +0200 Subject: [PATCH] device: Add API to update features during probe This allows updating the supported feature bitfield during probe. --- doc/libfprint-2-sections.txt | 1 + libfprint/fp-device-private.h | 17 +++--- libfprint/fp-device.c | 29 ++++++---- libfprint/fpi-device.c | 23 ++++++++ libfprint/fpi-device.h | 4 ++ tests/test-device-fake.c | 2 + tests/test-device-fake.h | 25 ++++---- tests/test-fpi-device.c | 105 +++++++++++++++------------------- 8 files changed, 116 insertions(+), 90 deletions(-) diff --git a/doc/libfprint-2-sections.txt b/doc/libfprint-2-sections.txt index f705f6a..eba3d81 100644 --- a/doc/libfprint-2-sections.txt +++ b/doc/libfprint-2-sections.txt @@ -159,6 +159,7 @@ fpi_device_action_is_cancelled fpi_device_add_timeout fpi_device_set_nr_enroll_stages fpi_device_set_scan_type +fpi_device_update_features fpi_device_remove fpi_device_report_finger_status fpi_device_report_finger_status_changes diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h index 47230cc..3f8bf0f 100644 --- a/libfprint/fp-device-private.h +++ b/libfprint/fp-device-private.h @@ -34,17 +34,18 @@ typedef struct gchar *hidraw_path; } udev_data; - gboolean is_removed; - gboolean is_open; + gboolean is_removed; + gboolean is_open; - gchar *device_id; - gchar *device_name; - FpScanType scan_type; + gchar *device_id; + gchar *device_name; + FpScanType scan_type; + FpDeviceFeature features; - guint64 driver_data; + guint64 driver_data; - gint nr_enroll_stages; - GSList *sources; + gint nr_enroll_stages; + GSList *sources; /* We always make sure that only one task is run at a time. */ FpiDeviceAction current_action; diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 509e052..eeaa875 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -147,6 +147,7 @@ fp_device_constructed (GObject *object) if (cls->nr_enroll_stages) priv->nr_enroll_stages = cls->nr_enroll_stages; priv->scan_type = cls->scan_type; + priv->features = cls->features; priv->device_name = g_strdup (cls->full_name); priv->device_id = g_strdup ("0"); @@ -628,10 +629,11 @@ gboolean fp_device_supports_identify (FpDevice *device) { FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); - return cls->identify && !!(cls->features & FP_DEVICE_FEATURE_IDENTIFY); + return cls->identify && !!(priv->features & FP_DEVICE_FEATURE_IDENTIFY); } /** @@ -647,10 +649,11 @@ gboolean fp_device_supports_capture (FpDevice *device) { FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); - return cls->capture && !!(cls->features & FP_DEVICE_FEATURE_CAPTURE); + return cls->capture && !!(priv->features & FP_DEVICE_FEATURE_CAPTURE); } /** @@ -666,11 +669,11 @@ fp_device_supports_capture (FpDevice *device) gboolean fp_device_has_storage (FpDevice *device) { - FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); - return !!(cls->features & FP_DEVICE_FEATURE_STORAGE); + return !!(priv->features & FP_DEVICE_FEATURE_STORAGE); } /** @@ -980,7 +983,7 @@ fp_device_verify (FpDevice *device, return; } - if (!cls->verify || !(cls->features & FP_DEVICE_FEATURE_VERIFY)) + if (!cls->verify || !(priv->features & FP_DEVICE_FEATURE_VERIFY)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1099,7 +1102,7 @@ fp_device_identify (FpDevice *device, return; } - if (!cls->identify || !(cls->features & FP_DEVICE_FEATURE_IDENTIFY)) + if (!cls->identify || !(priv->features & FP_DEVICE_FEATURE_IDENTIFY)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1216,7 +1219,7 @@ fp_device_capture (FpDevice *device, return; } - if (!cls->capture || !(cls->features & FP_DEVICE_FEATURE_CAPTURE)) + if (!cls->capture || !(priv->features & FP_DEVICE_FEATURE_CAPTURE)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1300,7 +1303,7 @@ fp_device_delete_print (FpDevice *device, } /* Succeed immediately if delete is not implemented. */ - if (!cls->delete || !(cls->features & FP_DEVICE_FEATURE_STORAGE_DELETE)) + if (!cls->delete || !(priv->features & FP_DEVICE_FEATURE_STORAGE_DELETE)) { g_task_return_boolean (task, TRUE); return; @@ -1377,7 +1380,7 @@ fp_device_list_prints (FpDevice *device, return; } - if (!cls->list || !(cls->features & FP_DEVICE_FEATURE_STORAGE)) + if (!cls->list || !(priv->features & FP_DEVICE_FEATURE_STORAGE)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1454,7 +1457,7 @@ fp_device_clear_storage (FpDevice *device, return; } - if (!(cls->features & FP_DEVICE_FEATURE_STORAGE)) + if (!(priv->features & FP_DEVICE_FEATURE_STORAGE)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1462,7 +1465,7 @@ fp_device_clear_storage (FpDevice *device, return; } - if (!(cls->features & FP_DEVICE_FEATURE_STORAGE_CLEAR)) + if (!(priv->features & FP_DEVICE_FEATURE_STORAGE_CLEAR)) { g_task_return_error (task, fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, @@ -1805,9 +1808,11 @@ fp_device_clear_storage_sync (FpDevice *device, FpDeviceFeature fp_device_get_features (FpDevice *device) { + FpDevicePrivate *priv = fp_device_get_instance_private (device); + g_return_val_if_fail (FP_IS_DEVICE (device), FP_DEVICE_FEATURE_NONE); - return FP_DEVICE_GET_CLASS (device)->features; + return priv->features; } /** diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index a526a51..d91fc94 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -277,6 +277,29 @@ fpi_device_set_scan_type (FpDevice *device, g_object_notify (G_OBJECT (device), "scan-type"); } +/** + * fpi_device_update_features: + * @device: The #FpDevice + * @update: The feature flags to update + * @value: The value to set the flags to + * + * Updates the feature flags for the device. This can be used + * to runtime detect features that are supported by the device. + */ +void +fpi_device_update_features (FpDevice *device, + FpDeviceFeature update, + FpDeviceFeature value) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE); + g_return_if_fail ((value & update) == value); + + priv->features = (priv->features & ~update) | (value & update); +} + typedef struct { GSource source; diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h index 4412c78..eb8b8fe 100644 --- a/libfprint/fpi-device.h +++ b/libfprint/fpi-device.h @@ -249,6 +249,10 @@ void fpi_device_set_nr_enroll_stages (FpDevice *device, void fpi_device_set_scan_type (FpDevice *device, FpScanType scan_type); +void fpi_device_update_features (FpDevice *device, + FpDeviceFeature update, + FpDeviceFeature value); + void fpi_device_action_error (FpDevice *device, GError *error); diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c index 2a7d936..4dd90e5 100644 --- a/tests/test-device-fake.c +++ b/tests/test-device-fake.c @@ -38,6 +38,8 @@ fpi_device_fake_probe (FpDevice *device) fake_dev->last_called_function = fpi_device_fake_probe; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); + fpi_device_update_features (device, fake_dev->probe_features_update, fake_dev->probe_features_value); + if (fake_dev->return_action_error) { fpi_device_action_error (device, fake_dev->ret_error); diff --git a/tests/test-device-fake.h b/tests/test-device-fake.h index e828b55..fa8b9b9 100644 --- a/tests/test-device-fake.h +++ b/tests/test-device-fake.h @@ -27,18 +27,21 @@ G_DECLARE_FINAL_TYPE (FpiDeviceFake, fpi_device_fake, FPI, DEVICE_FAKE, FpDevice struct _FpiDeviceFake { - FpDevice parent; + FpDevice parent; - gpointer last_called_function; - gboolean return_action_error; + gpointer last_called_function; + gboolean return_action_error; - GError *ret_error; - FpPrint *ret_print; - FpPrint *ret_match; - FpiMatchResult ret_result; - FpImage *ret_image; - GPtrArray *ret_list; + GError *ret_error; + FpPrint *ret_print; + FpPrint *ret_match; + FpiMatchResult ret_result; + FpImage *ret_image; + GPtrArray *ret_list; - gpointer action_data; - gpointer user_data; + gpointer action_data; + gpointer user_data; + + FpDeviceFeature probe_features_update; + FpDeviceFeature probe_features_value; }; diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index e6b7bbe..b7c9f0a 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -509,67 +509,49 @@ test_driver_get_driver_data (void) } static void -driver_feature_changes_check (FpDevice *device, gboolean add) -{ - g_autoptr(GFlagsClass) features_class = g_type_class_ref (FP_TYPE_DEVICE_FEATURE); - FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); - guint expected_features; - guint initial_value; - guint i; - - if (add) - initial_value = FP_DEVICE_FEATURE_NONE; - else - initial_value = features_class->mask; - - g_assert_cmpuint (fp_device_get_features (device), ==, initial_value); - - for (i = 0, expected_features = initial_value; i < features_class->n_values; ++i) - { - FpDeviceFeature feature = features_class->values[i].value; - FpDeviceFeature added_feature = add ? feature : FP_DEVICE_FEATURE_NONE; - FpDeviceFeature removed_feature = add ? FP_DEVICE_FEATURE_NONE : feature; - - dev_class->features |= added_feature; - dev_class->features &= ~removed_feature; - - expected_features |= added_feature; - expected_features &= ~removed_feature; - - g_assert_cmpuint (fp_device_get_features (device), ==, expected_features); - - if (added_feature != FP_DEVICE_FEATURE_NONE) - g_assert_true (fp_device_has_feature (device, added_feature)); - else if (dev_class->features != FP_DEVICE_FEATURE_NONE) - g_assert_false (fp_device_has_feature (device, added_feature)); - else - g_assert_true (fp_device_has_feature (device, added_feature)); - - if (removed_feature != FP_DEVICE_FEATURE_NONE) - g_assert_false (fp_device_has_feature (device, removed_feature)); - else if (dev_class->features != FP_DEVICE_FEATURE_NONE) - g_assert_false (fp_device_has_feature (device, removed_feature)); - else - g_assert_true (fp_device_has_feature (device, removed_feature)); - - g_assert_true (fp_device_has_feature (device, expected_features)); - } - - if (add) - g_assert_cmpuint (fp_device_get_features (device), ==, features_class->mask); - else - g_assert_cmpuint (fp_device_get_features (device), ==, FP_DEVICE_FEATURE_NONE); -} - -static void -test_driver_features (void) +test_driver_features_probe_updates (void) { g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); - g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev; - dev_class->features = FP_DEVICE_FEATURE_NONE; - driver_feature_changes_check (device, TRUE); - driver_feature_changes_check (device, FALSE); + g_assert_cmpuint (dev_class->features, !=, FP_DEVICE_FEATURE_NONE); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_CAPTURE); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_IDENTIFY); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_VERIFY); + g_assert_false (dev_class->features & FP_DEVICE_FEATURE_DUPLICATES_CHECK); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE_LIST); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE_DELETE); + g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE_CLEAR); + + /* Effectively clears FP_DEVICE_FEATURE_STORAGE_DELETE */ + fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->probe_features_update = FP_DEVICE_FEATURE_STORAGE_LIST | FP_DEVICE_FEATURE_STORAGE_DELETE; + fake_dev->probe_features_value = FP_DEVICE_FEATURE_STORAGE_LIST; + + g_async_initable_init_async (G_ASYNC_INITABLE (device), + G_PRIORITY_DEFAULT, NULL, NULL, NULL); + while (g_main_context_iteration (NULL, FALSE)) + continue; + + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_CAPTURE)); + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_IDENTIFY)); + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_VERIFY)); + g_assert_false (fp_device_has_feature (device, FP_DEVICE_FEATURE_DUPLICATES_CHECK)); + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_STORAGE)); + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_STORAGE_LIST)); + g_assert_false (fp_device_has_feature (device, FP_DEVICE_FEATURE_STORAGE_DELETE)); + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_STORAGE_CLEAR)); + + g_assert_cmpuint (fp_device_get_features (device), + ==, + FP_DEVICE_FEATURE_CAPTURE | + FP_DEVICE_FEATURE_IDENTIFY | + FP_DEVICE_FEATURE_VERIFY | + FP_DEVICE_FEATURE_STORAGE | + FP_DEVICE_FEATURE_STORAGE_LIST | + FP_DEVICE_FEATURE_STORAGE_CLEAR); } static void @@ -588,6 +570,11 @@ test_driver_initial_features (void) g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE_DELETE); g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE_CLEAR); + g_async_initable_init_async (G_ASYNC_INITABLE (device), + G_PRIORITY_DEFAULT, NULL, NULL, NULL); + while (g_main_context_iteration (NULL, FALSE)) + continue; + g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_CAPTURE)); g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_IDENTIFY)); g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_VERIFY)); @@ -2849,7 +2836,7 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/get_usb_device", test_driver_get_usb_device); g_test_add_func ("/driver/get_virtual_env", test_driver_get_virtual_env); g_test_add_func ("/driver/get_driver_data", test_driver_get_driver_data); - g_test_add_func ("/driver/features", test_driver_features); + g_test_add_func ("/driver/features/probe_updates", test_driver_features_probe_updates); g_test_add_func ("/driver/initial_features", test_driver_initial_features); g_test_add_func ("/driver/initial_features/none", test_driver_initial_features_none); g_test_add_func ("/driver/initial_features/no_capture", test_driver_initial_features_no_capture);