From 5fb3b8b43a2b7a2a86b583d87e6db70218c8bbea Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 14 Feb 2022 17:47:33 +0100 Subject: [PATCH 01/86] tests: Avoid -Wdangling-pointer warning The code is correct, but gcc thinks the pointer is still NULL after the call. As obvious workaround don't seem to work, just disable the warning for now. --- tests/test-fpi-device.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index ff658e97..f1c42753 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -29,6 +29,10 @@ #include "test-device-fake.h" #include "fp-print-private.h" +/* gcc 12.0.1 is complaining about dangling pointers in the auto_close* functions */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-pointer" + /* Utility functions */ typedef FpDevice FpAutoCloseDevice; @@ -65,6 +69,8 @@ auto_close_fake_device_free (FpAutoCloseDevice *device) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpAutoCloseDevice, auto_close_fake_device_free) +#pragma GCC diagnostic pop + typedef FpDeviceClass FpAutoResetClass; static FpAutoResetClass default_fake_dev_class = {0}; From f1a61c060ff1a89a7cf31dc56fa7b234f5ec7809 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 17 Feb 2022 10:20:55 +0100 Subject: [PATCH 02/86] device: Clear the critical section source on destruction --- libfprint/fp-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 82f309e8..23c7aaee 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -225,6 +225,7 @@ fp_device_finalize (GObject *object) g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy); + g_clear_pointer (&priv->critical_section_flush_source, g_source_destroy); g_clear_pointer (&priv->device_id, g_free); g_clear_pointer (&priv->device_name, g_free); From 2b760dfa380ceff152ff8105a2aad76d85ec1ddc Mon Sep 17 00:00:00 2001 From: ArronYen Date: Wed, 2 Mar 2022 10:43:20 +0800 Subject: [PATCH 03/86] elanmoc: add PID 0x0c82 --- data/autosuspend.hwdb | 1 + libfprint/drivers/elanmoc/elanmoc.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 91a14ebd..d55ed3e2 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -144,6 +144,7 @@ usb:v04F3p0C58* # Supported by libfprint driver elanmoc usb:v04F3p0C7D* usb:v04F3p0C7E* +usb:v04F3p0C82* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 69700a0c..3185ee7a 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -27,6 +27,7 @@ G_DEFINE_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FP_TYPE_DEVICE) static const FpIdEntry id_table[] = { { .vid = 0x04f3, .pid = 0x0c7d, }, { .vid = 0x04f3, .pid = 0x0c7e, }, + { .vid = 0x04f3, .pid = 0x0c82, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; From da1a56a600d286ffb507d1541b59220d28dc620b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 10 Apr 2022 13:58:58 +0200 Subject: [PATCH 04/86] context: Log version number at startup Having this should at least give us a slightly better idea about the version that the user has installed. Obviously it is still not very accurate (maybe a git hash would be good if available?), but it should still be helpful overall. --- libfprint/fp-context.c | 2 ++ meson.build | 1 + 2 files changed, 3 insertions(+) diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 1f322157..42607dcb 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -361,6 +361,8 @@ fp_context_init (FpContext *self) FpContextPrivate *priv = fp_context_get_instance_private (self); guint i; + g_debug ("Initializing FpContext (libfprint version " LIBFPRINT_VERSION ")"); + priv->drivers = fpi_get_driver_types (); if (get_drivers_whitelist_env ()) diff --git a/meson.build b/meson.build index c937d281..3167fff3 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,7 @@ project('libfprint', [ 'c', 'cpp' ], gnome = import('gnome') libfprint_conf = configuration_data() +libfprint_conf.set_quoted('LIBFPRINT_VERSION', meson.project_version()) cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') From 5ba7ff8be9c510e180db54d788d84c5f6ffcf5bc Mon Sep 17 00:00:00 2001 From: Aris Lin Date: Wed, 6 Apr 2022 14:17:34 +0800 Subject: [PATCH 05/86] synaptics: Add new PID 0x0168 --- data/autosuspend.hwdb | 1 + libfprint/drivers/synaptics/synaptics.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index d55ed3e2..cb1a9067 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -188,6 +188,7 @@ usb:v06CBp0103* usb:v06CBp0123* usb:v06CBp0126* usb:v06CBp0129* +usb:v06CBp0168* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 7a2c6ebe..b89989b2 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -42,6 +42,7 @@ static const FpIdEntry id_table[] = { { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, }, + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; From eda8d13927564bd1bd324fb9aedb9011df5193e3 Mon Sep 17 00:00:00 2001 From: Josh Chen Date: Wed, 13 Apr 2022 14:48:29 +0800 Subject: [PATCH 06/86] elan: add PID 0x0c4b --- data/autosuspend.hwdb | 2 +- libfprint/drivers/elan.h | 1 + libfprint/fprint-list-udev-hwdb.c | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index cb1a9067..9acfb950 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -133,6 +133,7 @@ usb:v04F3p0C32* usb:v04F3p0C33* usb:v04F3p0C3D* usb:v04F3p0C42* +usb:v04F3p0C4B* usb:v04F3p0C4D* usb:v04F3p0C4F* usb:v04F3p0C63* @@ -258,7 +259,6 @@ usb:v138Ap0091* # Known unsupported devices usb:v04F3p036B* usb:v04F3p0C00* -usb:v04F3p0C4B* usb:v04F3p0C4C* usb:v04F3p0C57* usb:v04F3p0C5E* diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index 33f3aefd..7d089945 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -215,6 +215,7 @@ static const FpIdEntry elan_id_table[] = { {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, + {.vid = ELAN_VEND_ID, .pid = 0x0c4b, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV}, diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index ad9cdd07..5244cc6a 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -31,7 +31,6 @@ static const FpIdEntry whitelist_id_table[] = { */ { .vid = 0x04f3, .pid = 0x036b }, { .vid = 0x04f3, .pid = 0x0c00 }, - { .vid = 0x04f3, .pid = 0x0c4b }, { .vid = 0x04f3, .pid = 0x0c4c }, { .vid = 0x04f3, .pid = 0x0c57 }, { .vid = 0x04f3, .pid = 0x0c5e }, From e7d041d2580a71314db9c71c69c64cb775b300bc Mon Sep 17 00:00:00 2001 From: Matthew Mirvish Date: Sun, 8 May 2022 18:32:29 -0400 Subject: [PATCH 07/86] elanspi: add 04f3:241f Reported as working with this config in https://github.com/mincrmatt12/elan-spi-fingerprint/issues/11. --- libfprint/drivers/elanspi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/drivers/elanspi.h b/libfprint/drivers/elanspi.h index ffe34160..a8d73194 100644 --- a/libfprint/drivers/elanspi.h +++ b/libfprint/drivers/elanspi.h @@ -348,6 +348,7 @@ static const FpIdEntry elanspi_id_table[] = { {.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE}, {.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE}, {.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE}, + {.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x241f}, .driver_data = ELANSPI_NO_ROTATE}, {.udev_types = 0} }; From 0fd5a617ab75026601cf17dc7d80f3d68a8027d5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 14 Mar 2022 20:15:17 +0100 Subject: [PATCH 08/86] device: Do not update sysfs attributes if value is correct This avoids spurious warnings on e.g. SELinux enabled systems. --- libfprint/fpi-device.c | 78 ++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 89504dab..9209204a 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1550,6 +1550,47 @@ fpi_device_list_complete (FpDevice *device, fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } +static int +update_attr (const char *attr, const char *value) +{ + int fd, err; + gssize r; + char buf[50] = { 0 }; + + fd = open (attr, O_RDONLY); + err = -errno; + if (fd < 0) + return -err; + + r = read (fd, buf, sizeof (buf) - 1); + err = errno; + close (fd); + if (r < 0) + return -err; + + g_strchomp (buf); + if (g_strcmp0 (buf, value) == 0) + return 0; + + /* O_TRUNC makes things work in the umockdev environment */ + fd = open (attr, O_WRONLY | O_TRUNC); + err = errno; + if (fd < 0) + return -err; + + r = write (fd, value, strlen (value)); + err = -errno; + close (fd); + if (r < 0) + { + /* Write failures are weird, and are worth a warning */ + g_warning ("Could not write %s to %s", value, attr); + return -err; + } + + return 0; +} + void fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) { @@ -1565,8 +1606,7 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) guint8 bus, port; g_autofree gchar *sysfs_wakeup = NULL; g_autofree gchar *sysfs_persist = NULL; - gssize r; - int fd; + int res; ports = g_string_new (NULL); bus = g_usb_device_get_bus (priv->usb_device); @@ -1582,20 +1622,9 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) g_string_set_size (ports, ports->len - 1); sysfs_wakeup = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/wakeup", bus, ports->str); - fd = open (sysfs_wakeup, O_WRONLY); - - if (fd < 0) - { - /* Wakeup not existing appears to be relatively normal. */ - g_debug ("Failed to open %s", sysfs_wakeup); - } - else - { - r = write (fd, wakeup_command, strlen (wakeup_command)); - if (r < 0) - g_warning ("Could not configure wakeup to %s by writing %s", wakeup_command, sysfs_wakeup); - close (fd); - } + res = update_attr (sysfs_wakeup, wakeup_command); + if (res < 0) + g_debug ("Failed to set %s to %s", sysfs_wakeup, wakeup_command); /* Persist means that the kernel tries to keep the USB device open * in case it is "replugged" due to suspend. @@ -1603,20 +1632,9 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) * state. Instead, seeing an unplug and a new device makes more sense. */ sysfs_persist = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/persist", bus, ports->str); - fd = open (sysfs_persist, O_WRONLY); - - if (fd < 0) - { - g_warning ("Failed to open %s", sysfs_persist); - return; - } - else - { - r = write (fd, "0", 1); - if (r < 0) - g_message ("Could not disable USB persist by writing to %s", sysfs_persist); - close (fd); - } + res = update_attr (sysfs_persist, "0"); + if (res < 0) + g_warning ("Failed to disable USB persist by writing to %s", sysfs_persist); break; } From 7b0093b4c6703e04ffec89be4c190b9a00ad5b9a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 14 Mar 2022 20:15:51 +0100 Subject: [PATCH 09/86] tests: Reset the USB device before testing The kernel caches URBs to get descriptor values. Doing a reset before starting the record ensures that we will see any descriptor reads in the usbmon trace and can therefore correctly replay them (possibly not true if they happen multiple times). --- tests/create-driver-test.py.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/create-driver-test.py.in b/tests/create-driver-test.py.in index 3eabb78d..8173271f 100755 --- a/tests/create-driver-test.py.in +++ b/tests/create-driver-test.py.in @@ -105,6 +105,11 @@ process.wait() # Run capture # https://osqa-ask.wireshark.org/questions/53919/how-can-i-precisely-specify-a-usb-device-to-capture-with-tshark/ +print(f'### Reseting USB port (as descriptors could be missing in the dump otherwise)') +usb_device.open() +usb_device.reset() +usb_device.close() + print(f'### Starting USB capture on usbmon{bus_num}') capture_pid = os.fork() assert(capture_pid >= 0) From 1f925fef7cc42dcb9fa8e5ef9fa6ac99afb6a9f2 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 14 Mar 2022 20:18:17 +0100 Subject: [PATCH 10/86] tests: Test suspend/resume and sysfs attributes in synaptics --- tests/synaptics/custom.pcapng | Bin 42080 -> 31328 bytes tests/synaptics/custom.py | 41 ++++- tests/synaptics/device | 294 +++++++++++++++++----------------- 3 files changed, 186 insertions(+), 149 deletions(-) diff --git a/tests/synaptics/custom.pcapng b/tests/synaptics/custom.pcapng index 44e161cac646030dd8f9e9dbf87e3867226e935b..f6dc26ef7f1ca0fc74806632d63d687ec9088430 100644 GIT binary patch literal 31328 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 E02)AJK>z>% literal 42080 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 P_Lu9Md0PAjA+qs*a7xc- diff --git a/tests/synaptics/custom.py b/tests/synaptics/custom.py index 3e48341d..0a88ef80 100755 --- a/tests/synaptics/custom.py +++ b/tests/synaptics/custom.py @@ -1,10 +1,14 @@ #!/usr/bin/python3 +import os import gi gi.require_version('FPrint', '2.0') from gi.repository import FPrint, GLib -ctx = GLib.main_context_default() +import sys +import traceback +sys.excepthook = lambda *args : (traceback.print_exception(*args), sys.exit(1)) + c = FPrint.Context() c.enumerate() @@ -13,6 +17,24 @@ devices = c.get_devices() d = devices[0] del devices +usb_device = d.get_property('fpi-usb-device') +bus_num = usb_device.get_bus() +port = [] +while True: + parent = usb_device.get_parent() + if parent is None: + break + port.append(str(usb_device.get_port_number())) + usb_device = parent +port = '.'.join(port) + +persist = f'/sys/bus/usb/devices/{bus_num}-{port}/power/persist' +wakeup = f'/sys/bus/usb/devices/{bus_num}-{port}/power/wakeup' + +# may not have written anything +assert open(persist).read().strip() == "0" +assert open(wakeup).read().strip() == "disabled" + assert d.get_driver() == "synaptics" assert not d.has_feature(FPrint.DeviceFeature.CAPTURE) assert d.has_feature(FPrint.DeviceFeature.IDENTIFY) @@ -29,7 +51,7 @@ d.clear_storage_sync() template = FPrint.Print.new(d) def enroll_progress(*args): - assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED + #assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED print('enroll progress: ' + str(args)) # List, enroll, list, verify, delete, list @@ -41,6 +63,21 @@ print("enroll done") print("verifying") assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE + +# Inject a suspend/resume cycle into the verify +def suspend_resume(): + d.suspend_sync() + assert open(persist).read().strip() == "0" + assert open(wakeup).read().strip() == "enabled" + + assert open(persist, 'w').write('0\n') + d.resume_sync() + # This tests that libfprint doesn't write if the value is correct + # (i.e. the trailing \ would be lost inside umockdev if written) + assert open(persist).read() == "0\n" + assert open(wakeup).read().strip() == "disabled" + +GLib.idle_add(suspend_resume, priority=GLib.PRIORITY_HIGH) verify_res, verify_print = d.verify_sync(p) assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE print("verify done") diff --git a/tests/synaptics/device b/tests/synaptics/device index e56e37d9..f11a0dd2 100644 --- a/tests/synaptics/device +++ b/tests/synaptics/device @@ -1,14 +1,14 @@ P: /devices/pci0000:00/0000:00:14.0/usb1/1-9 -N: bus/usb/001/005 -E: DEVNAME=/dev/bus/usb/001/005 +N: bus/usb/001/004=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 +E: DEVNAME=/dev/bus/usb/001/004 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=6cb/bd/0 E: TYPE=255/16/255 E: BUSNUM=001 -E: DEVNUM=005 +E: DEVNUM=004 E: MAJOR=189 -E: MINOR=4 +E: MINOR=3 E: SUBSYSTEM=usb E: ID_VENDOR=06cb E: ID_VENDOR_ENC=06cb @@ -24,82 +24,82 @@ E: ID_USB_INTERFACES=:ff0000: E: ID_VENDOR_FROM_DATABASE=Synaptics, Inc. E: ID_AUTOSUSPEND=1 E: ID_MODEL_FROM_DATABASE=Prometheus MIS Touch Fingerprint Reader +E: ID_PERSIST=0 E: ID_PATH=pci-0000:00:14.0-usb-0:9 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_9 -E: LIBFPRINT_DRIVER=Synaptics Sensors -A: authorized=1\n -A: avoid_reset_quirk=0\n -A: bConfigurationValue=1\n -A: bDeviceClass=ff\n -A: bDeviceProtocol=ff\n -A: bDeviceSubClass=10\n -A: bMaxPacketSize0=8\n -A: bMaxPower=100mA\n -A: bNumConfigurations=1\n -A: bNumInterfaces= 1\n -A: bcdDevice=0000\n -A: bmAttributes=a0\n -A: busnum=1\n +A: authorized=1 +A: avoid_reset_quirk=0 +A: bConfigurationValue=1 +A: bDeviceClass=ff +A: bDeviceProtocol=ff +A: bDeviceSubClass=10 +A: bMaxPacketSize0=8 +A: bMaxPower=100mA +A: bNumConfigurations=1 +A: bNumInterfaces= 1 +A: bcdDevice=0000 +A: bmAttributes=a0 +A: busnum=1 A: configuration= H: descriptors=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 -A: dev=189:4\n -A: devnum=5\n -A: devpath=9\n +A: dev=189:3 +A: devnum=4 +A: devpath=9 L: driver=../../../../../bus/usb/drivers/usb L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d/device:28 -A: idProduct=00bd\n -A: idVendor=06cb\n -A: ltm_capable=no\n -A: maxchild=0\n +A: idProduct=00bd +A: idVendor=06cb +A: ltm_capable=no +A: maxchild=0 L: port=../1-0:1.0/usb1-port9 -A: power/active_duration=82065\n -A: power/autosuspend=2\n -A: power/autosuspend_delay_ms=2000\n -A: power/connected_duration=4271349\n -A: power/control=auto\n -A: power/level=auto\n -A: power/persist=1\n -A: power/runtime_active_time=82975\n -A: power/runtime_status=suspended\n -A: power/runtime_suspended_time=4186597\n -A: power/wakeup=disabled\n -A: power/wakeup_abort_count=\n -A: power/wakeup_active=\n -A: power/wakeup_active_count=\n -A: power/wakeup_count=\n -A: power/wakeup_expire_count=\n -A: power/wakeup_last_time_ms=\n -A: power/wakeup_max_time_ms=\n -A: power/wakeup_total_time_ms=\n -A: quirks=0x0\n -A: removable=fixed\n -A: rx_lanes=1\n -A: serial=c087f7d72126\n -A: speed=12\n -A: tx_lanes=1\n -A: urbnum=618\n -A: version= 2.00\n +A: power/active_duration=9424964 +A: power/autosuspend=2 +A: power/autosuspend_delay_ms=2000 +A: power/connected_duration=866169213 +A: power/control=auto +A: power/level=auto +A: power/persist=0 +A: power/runtime_active_time=9431408 +A: power/runtime_status=active +A: power/runtime_suspended_time=856661633 +A: power/wakeup=disabled +A: power/wakeup_abort_count= +A: power/wakeup_active= +A: power/wakeup_active_count= +A: power/wakeup_count= +A: power/wakeup_expire_count= +A: power/wakeup_last_time_ms= +A: power/wakeup_max_time_ms= +A: power/wakeup_total_time_ms= +A: quirks=0x0 +A: removable=fixed +A: rx_lanes=1 +A: serial=c087f7d72126 +A: speed=12 +A: tx_lanes=1 +A: urbnum=8945 +A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0/usb1 -N: bus/usb/001/001=12010002090001406B1D020012050302010109021900010100E0000904000001090000000705810304000C +N: bus/usb/001/001=12010002090001406B1D020016050302010109021900010100E0000904000001090000000705810304000C E: DEVNAME=/dev/bus/usb/001/001 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=1d6b/2/512 +E: PRODUCT=1d6b/2/516 E: TYPE=9/0/1 E: BUSNUM=001 E: DEVNUM=001 E: MAJOR=189 E: MINOR=0 E: SUBSYSTEM=usb -E: ID_VENDOR=Linux_5.12.9-300.fc34.x86_64_xhci-hcd -E: ID_VENDOR_ENC=Linux\x205.12.9-300.fc34.x86_64\x20xhci-hcd +E: ID_VENDOR=Linux_5.16.8-200.fc35.x86_64_xhci-hcd +E: ID_VENDOR_ENC=Linux\x205.16.8-200.fc35.x86_64\x20xhci-hcd E: ID_VENDOR_ID=1d6b E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_ID=0002 -E: ID_REVISION=0512 -E: ID_SERIAL=Linux_5.12.9-300.fc34.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 +E: ID_REVISION=0516 +E: ID_SERIAL=Linux_5.16.8-200.fc35.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_BUS=usb E: ID_USB_INTERFACES=:090000: @@ -111,60 +111,60 @@ E: ID_PATH_TAG=pci-0000_00_14_0 E: ID_FOR_SEAT=usb-pci-0000_00_14_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: -A: authorized=1\n -A: authorized_default=1\n -A: avoid_reset_quirk=0\n -A: bConfigurationValue=1\n -A: bDeviceClass=09\n -A: bDeviceProtocol=01\n -A: bDeviceSubClass=00\n -A: bMaxPacketSize0=64\n -A: bMaxPower=0mA\n -A: bNumConfigurations=1\n -A: bNumInterfaces= 1\n -A: bcdDevice=0512\n -A: bmAttributes=e0\n -A: busnum=1\n +A: authorized=1 +A: authorized_default=1 +A: avoid_reset_quirk=0 +A: bConfigurationValue=1 +A: bDeviceClass=09 +A: bDeviceProtocol=01 +A: bDeviceSubClass=00 +A: bMaxPacketSize0=64 +A: bMaxPower=0mA +A: bNumConfigurations=1 +A: bNumInterfaces= 1 +A: bcdDevice=0516 +A: bmAttributes=e0 +A: busnum=1 A: configuration= -H: descriptors=12010002090001406B1D020012050302010109021900010100E0000904000001090000000705810304000C -A: dev=189:0\n -A: devnum=1\n -A: devpath=0\n +H: descriptors=12010002090001406B1D020016050302010109021900010100E0000904000001090000000705810304000C +A: dev=189:0 +A: devnum=1 +A: devpath=0 L: driver=../../../../bus/usb/drivers/usb L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d -A: idProduct=0002\n -A: idVendor=1d6b\n -A: interface_authorized_default=1\n -A: ltm_capable=no\n -A: manufacturer=Linux 5.12.9-300.fc34.x86_64 xhci-hcd\n -A: maxchild=12\n -A: power/active_duration=4270585\n -A: power/autosuspend=0\n -A: power/autosuspend_delay_ms=0\n -A: power/connected_duration=4272308\n -A: power/control=auto\n -A: power/level=auto\n -A: power/runtime_active_time=4270770\n -A: power/runtime_status=active\n -A: power/runtime_suspended_time=0\n -A: power/wakeup=disabled\n -A: power/wakeup_abort_count=\n -A: power/wakeup_active=\n -A: power/wakeup_active_count=\n -A: power/wakeup_count=\n -A: power/wakeup_expire_count=\n -A: power/wakeup_last_time_ms=\n -A: power/wakeup_max_time_ms=\n -A: power/wakeup_total_time_ms=\n -A: product=xHCI Host Controller\n -A: quirks=0x0\n -A: removable=unknown\n -A: rx_lanes=1\n -A: serial=0000:00:14.0\n -A: speed=480\n -A: tx_lanes=1\n -A: urbnum=463\n -A: version= 2.00\n +A: idProduct=0002 +A: idVendor=1d6b +A: interface_authorized_default=1 +A: ltm_capable=no +A: manufacturer=Linux 5.16.8-200.fc35.x86_64 xhci-hcd +A: maxchild=12 +A: power/active_duration=865968060 +A: power/autosuspend=0 +A: power/autosuspend_delay_ms=0 +A: power/connected_duration=866169920 +A: power/control=auto +A: power/level=auto +A: power/runtime_active_time=866093998 +A: power/runtime_status=active +A: power/runtime_suspended_time=0 +A: power/wakeup=disabled +A: power/wakeup_abort_count= +A: power/wakeup_active= +A: power/wakeup_active_count= +A: power/wakeup_count= +A: power/wakeup_expire_count= +A: power/wakeup_last_time_ms= +A: power/wakeup_max_time_ms= +A: power/wakeup_total_time_ms= +A: product=xHCI Host Controller +A: quirks=0x0 +A: removable=unknown +A: rx_lanes=1 +A: serial=0000:00:14.0 +A: speed=480 +A: tx_lanes=1 +A: urbnum=9372 +A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd @@ -180,44 +180,44 @@ E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: ID_AUTOSUSPEND=1 E: ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller -A: ari_enabled=0\n -A: broken_parity_status=0\n -A: class=0x0c0330\n -H: config=8680ED9D060490021130030C00008000040022EA000000000000000000000000000000000000000000000000AA179222000000007000000000000000FF010000 -A: consistent_dma_mask_bits=64\n -A: d3cold_allowed=1\n -A: dbc=disabled\n -A: device=0x9ded\n -A: dma_mask_bits=64\n +A: ari_enabled=0 +A: broken_parity_status=0 +A: class=0x0c0330 +H: config=8680ED9D060490021130030C00008000040022EA000000000000000000000000000000000000000000000000AA179222000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F0000000060069A2400000000316000000000000000000000000000000180C2C108000000000000000000000005908700D802E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000000000000000000008000000040000000000000000000000000000000000000000000000000000000800000004000000000000000000000000000000000000000000000000000000B50F320112000000 +A: consistent_dma_mask_bits=64 +A: d3cold_allowed=1 +A: dbc=disabled +A: device=0x9ded +A: dma_mask_bits=64 L: driver=../../../bus/pci/drivers/xhci_hcd -A: driver_override=(null)\n -A: enable=1\n +A: driver_override=(null) +A: enable=1 L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c -A: irq=128\n -A: local_cpulist=0-7\n -A: local_cpus=ff\n -A: modalias=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30\n -A: msi_bus=1\n -A: msi_irqs/128=msi\n -A: numa_node=-1\n -A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 9 12 2112 12\nxHCI ring segments 40 50 4096 50\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 6 32 128 1\nbuffer-32 0 0 32 0\n -A: power/control=auto\n -A: power/runtime_active_time=4271635\n -A: power/runtime_status=active\n -A: power/runtime_suspended_time=0\n -A: power/wakeup=enabled\n -A: power/wakeup_abort_count=0\n -A: power/wakeup_active=0\n -A: power/wakeup_active_count=0\n -A: power/wakeup_count=0\n -A: power/wakeup_expire_count=0\n -A: power/wakeup_last_time_ms=0\n -A: power/wakeup_max_time_ms=0\n -A: power/wakeup_total_time_ms=0\n -A: power_state=D0\n -A: resource=0x00000000ea220000 0x00000000ea22ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n -A: revision=0x11\n -A: subsystem_device=0x2292\n -A: subsystem_vendor=0x17aa\n -A: vendor=0x8086\n +A: irq=126 +A: local_cpulist=0-7 +A: local_cpus=ff +A: modalias=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30 +A: msi_bus=1 +A: msi_irqs/126=msi +A: numa_node=-1 +A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 21 24 2112 24\nxHCI ring segments 68 80 4096 80\nbuffer-2048 0 38 2048 19\nbuffer-512 0 0 512 0\nbuffer-128 18 32 128 1\nbuffer-32 0 128 32 1 +A: power/control=auto +A: power/runtime_active_time=866094158 +A: power/runtime_status=active +A: power/runtime_suspended_time=0 +A: power/wakeup=enabled +A: power/wakeup_abort_count=0 +A: power/wakeup_active=0 +A: power/wakeup_active_count=2 +A: power/wakeup_count=0 +A: power/wakeup_expire_count=2 +A: power/wakeup_last_time_ms=476219021 +A: power/wakeup_max_time_ms=103 +A: power/wakeup_total_time_ms=207 +A: power_state=D0 +A: resource=0x00000000ea220000 0x00000000ea22ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 +A: revision=0x11 +A: subsystem_device=0x2292 +A: subsystem_vendor=0x17aa +A: vendor=0x8086 From bfbe24b1720195ea68c655c545a73bd4e916792d Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 17 May 2022 20:20:52 +0200 Subject: [PATCH 11/86] synaptics: Correctly handle critical section during interrupt resubmit We re-aquire the critical section at the start of the callback, however, it needs to be dropped again (or not taken) if the interrupt transfer is resubmitted. --- libfprint/drivers/synaptics/synaptics.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index b89989b2..1c6243fd 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -225,6 +225,7 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer, } else { + fpi_device_critical_leave (device); fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), 0, NULL, From 54a98bb2860ee7d352ddf1e8876d73bf81bed5a1 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 17 May 2022 20:23:26 +0200 Subject: [PATCH 12/86] device: Run critical section flushing with a high priority These delayed calls are pushed into the mainloop for consistency. However, they should run immediately and not be delayed, as such, it makes sense to run them at a higher priority. This actually solves an issue inside the CI where an URB reply is played back even though it should be cancelled by the client. --- libfprint/fpi-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 9209204a..4fe89080 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -912,6 +912,7 @@ fpi_device_critical_leave (FpDevice *device) return; priv->critical_section_flush_source = g_idle_source_new (); + g_source_set_priority (priv->critical_section_flush_source, G_PRIORITY_HIGH); g_source_set_callback (priv->critical_section_flush_source, (GSourceFunc) fpi_device_critical_section_flush_idle_cb, device, From 56ae75d2b240da9d13cbb945e4d93f99b25669d0 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 17 May 2022 20:26:17 +0200 Subject: [PATCH 13/86] device: Fully re-evaluate suspend/resume logic when delayed If we delayed the suspend(/resume) call, then the circumstances may have changed. In particular, an active action may have completed already which means that the driver handler should not be called anymore. --- libfprint/fp-device-private.h | 3 + libfprint/fp-device.c | 89 +--------------------------- libfprint/fpi-device.c | 105 +++++++++++++++++++++++++++++++++- 3 files changed, 108 insertions(+), 89 deletions(-) diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h index 99eba410..9b2ea27c 100644 --- a/libfprint/fp-device-private.h +++ b/libfprint/fp-device-private.h @@ -130,6 +130,9 @@ typedef struct void match_data_free (FpMatchData *match_data); +void fpi_device_suspend (FpDevice *device); +void fpi_device_resume (FpDevice *device); + void fpi_device_configure_wakeup (FpDevice *device, gboolean enabled); void fpi_device_update_temp (FpDevice *device, diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 23c7aaee..b94f7d80 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -949,16 +949,6 @@ fp_device_close_finish (FpDevice *device, return g_task_propagate_boolean (G_TASK (result), error); } -static void -complete_suspend_resume_task (FpDevice *device) -{ - FpDevicePrivate *priv = fp_device_get_instance_private (device); - - g_assert (priv->suspend_resume_task); - - g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE); -} - /** * fp_device_suspend: * @device: a #FpDevice @@ -1009,48 +999,7 @@ fp_device_suspend (FpDevice *device, priv->suspend_resume_task = g_steal_pointer (&task); - /* If the device is currently idle, just complete immediately. - * For long running tasks, call the driver handler right away, for short - * tasks, wait for completion and then return the task. - */ - switch (priv->current_action) - { - case FPI_DEVICE_ACTION_NONE: - fpi_device_suspend_complete (device, NULL); - break; - - case FPI_DEVICE_ACTION_ENROLL: - case FPI_DEVICE_ACTION_VERIFY: - case FPI_DEVICE_ACTION_IDENTIFY: - case FPI_DEVICE_ACTION_CAPTURE: - if (FP_DEVICE_GET_CLASS (device)->suspend) - { - if (priv->critical_section) - priv->suspend_queued = TRUE; - else - FP_DEVICE_GET_CLASS (device)->suspend (device); - } - else - { - fpi_device_suspend_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); - } - break; - - default: - case FPI_DEVICE_ACTION_PROBE: - case FPI_DEVICE_ACTION_OPEN: - case FPI_DEVICE_ACTION_CLOSE: - case FPI_DEVICE_ACTION_DELETE: - case FPI_DEVICE_ACTION_LIST: - case FPI_DEVICE_ACTION_CLEAR_STORAGE: - g_signal_connect_object (priv->current_task, - "notify::completed", - G_CALLBACK (complete_suspend_resume_task), - device, - G_CONNECT_SWAPPED); - - break; - } + fpi_device_suspend (device); } /** @@ -1115,41 +1064,7 @@ fp_device_resume (FpDevice *device, priv->suspend_resume_task = g_steal_pointer (&task); - switch (priv->current_action) - { - case FPI_DEVICE_ACTION_NONE: - fpi_device_resume_complete (device, NULL); - break; - - case FPI_DEVICE_ACTION_ENROLL: - case FPI_DEVICE_ACTION_VERIFY: - case FPI_DEVICE_ACTION_IDENTIFY: - case FPI_DEVICE_ACTION_CAPTURE: - if (FP_DEVICE_GET_CLASS (device)->resume) - { - if (priv->critical_section) - priv->resume_queued = TRUE; - else - FP_DEVICE_GET_CLASS (device)->resume (device); - } - else - { - fpi_device_resume_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); - } - break; - - default: - case FPI_DEVICE_ACTION_PROBE: - case FPI_DEVICE_ACTION_OPEN: - case FPI_DEVICE_ACTION_CLOSE: - case FPI_DEVICE_ACTION_DELETE: - case FPI_DEVICE_ACTION_LIST: - case FPI_DEVICE_ACTION_CLEAR_STORAGE: - /* cannot happen as we make sure these tasks complete before suspend */ - g_assert_not_reached (); - complete_suspend_resume_task (device); - break; - } + fpi_device_resume (device); } /** diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 4fe89080..af775542 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -866,16 +866,16 @@ fpi_device_critical_section_flush_idle_cb (FpDevice *device) if (priv->suspend_queued) { - cls->suspend (device); priv->suspend_queued = FALSE; + fpi_device_suspend (device); return G_SOURCE_CONTINUE; } if (priv->resume_queued) { - cls->resume (device); priv->resume_queued = FALSE; + fpi_device_resume (device); return G_SOURCE_CONTINUE; } @@ -1592,6 +1592,107 @@ update_attr (const char *attr, const char *value) return 0; } +static void +complete_suspend_resume_task (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_assert (priv->suspend_resume_task); + + g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE); +} + +void +fpi_device_suspend (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + /* If the device is currently idle, just complete immediately. + * For long running tasks, call the driver handler right away, for short + * tasks, wait for completion and then return the task. + */ + switch (priv->current_action) + { + case FPI_DEVICE_ACTION_NONE: + fpi_device_suspend_complete (device, NULL); + break; + + case FPI_DEVICE_ACTION_ENROLL: + case FPI_DEVICE_ACTION_VERIFY: + case FPI_DEVICE_ACTION_IDENTIFY: + case FPI_DEVICE_ACTION_CAPTURE: + if (FP_DEVICE_GET_CLASS (device)->suspend) + { + if (priv->critical_section) + priv->suspend_queued = TRUE; + else + FP_DEVICE_GET_CLASS (device)->suspend (device); + } + else + { + fpi_device_suspend_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); + } + break; + + default: + case FPI_DEVICE_ACTION_PROBE: + case FPI_DEVICE_ACTION_OPEN: + case FPI_DEVICE_ACTION_CLOSE: + case FPI_DEVICE_ACTION_DELETE: + case FPI_DEVICE_ACTION_LIST: + case FPI_DEVICE_ACTION_CLEAR_STORAGE: + g_signal_connect_object (priv->current_task, + "notify::completed", + G_CALLBACK (complete_suspend_resume_task), + device, + G_CONNECT_SWAPPED); + + break; + } +} + +void +fpi_device_resume (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + switch (priv->current_action) + { + case FPI_DEVICE_ACTION_NONE: + fpi_device_resume_complete (device, NULL); + break; + + case FPI_DEVICE_ACTION_ENROLL: + case FPI_DEVICE_ACTION_VERIFY: + case FPI_DEVICE_ACTION_IDENTIFY: + case FPI_DEVICE_ACTION_CAPTURE: + if (FP_DEVICE_GET_CLASS (device)->resume) + { + if (priv->critical_section) + priv->resume_queued = TRUE; + else + FP_DEVICE_GET_CLASS (device)->resume (device); + } + else + { + fpi_device_resume_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); + } + break; + + default: + case FPI_DEVICE_ACTION_PROBE: + case FPI_DEVICE_ACTION_OPEN: + case FPI_DEVICE_ACTION_CLOSE: + case FPI_DEVICE_ACTION_DELETE: + case FPI_DEVICE_ACTION_LIST: + case FPI_DEVICE_ACTION_CLEAR_STORAGE: + /* cannot happen as we make sure these tasks complete before suspend */ + g_assert_not_reached (); + complete_suspend_resume_task (device); + break; + } +} + void fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) { From e86c45c9883157640be0360d34efa3bb41abfe29 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 18 May 2022 09:09:48 +0200 Subject: [PATCH 14/86] device: Add missing errno.h include This made the flatpak build fail. --- libfprint/fpi-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index af775542..c9157eb3 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -21,6 +21,7 @@ #define FP_COMPONENT "device" #include #include +#include #include "fpi-log.h" From 82d0f4288aff1c0bc285753c5c6ed876786d809d Mon Sep 17 00:00:00 2001 From: Aris Lin Date: Mon, 23 May 2022 21:06:23 +0800 Subject: [PATCH 15/86] synaptics: Add new PID 0x015F --- data/autosuspend.hwdb | 1 + libfprint/drivers/synaptics/synaptics.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 9acfb950..abab4ab1 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -190,6 +190,7 @@ usb:v06CBp0123* usb:v06CBp0126* usb:v06CBp0129* usb:v06CBp0168* +usb:v06CBp015F* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 1c6243fd..3f35291c 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -43,6 +43,7 @@ static const FpIdEntry id_table[] = { { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, }, + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x015F, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; From 8b8dc0fec22fdf9d90d7ce6d2fa3d8fe7750b484 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 24 May 2022 14:32:46 +0200 Subject: [PATCH 16/86] hwdb: Sync with wiki to add more unknown devices --- data/autosuspend.hwdb | 5 +++++ libfprint/fprint-list-udev-hwdb.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index abab4ab1..6e3fd396 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -258,6 +258,7 @@ usb:v138Ap0091* ID_PERSIST=0 # Known unsupported devices +usb:v04E8p730B* usb:v04F3p036B* usb:v04F3p0C00* usb:v04F3p0C4C* @@ -280,6 +281,7 @@ usb:v06CBp00C9* usb:v06CBp00D8* usb:v06CBp00DA* usb:v06CBp00DC* +usb:v06CBp00E4* usb:v06CBp00E7* usb:v06CBp00E9* usb:v06CBp00FD* @@ -295,6 +297,7 @@ usb:v0A5Cp5845* usb:v0BDAp5812* usb:v10A5p0007* usb:v10A5p9200* +usb:v10A5p9800* usb:v1188p9545* usb:v138Ap0007* usb:v138Ap003A* @@ -316,6 +319,7 @@ usb:v1C7Ap0576* usb:v27C6p5042* usb:v27C6p5110* usb:v27C6p5117* +usb:v27C6p5125* usb:v27C6p5201* usb:v27C6p521D* usb:v27C6p5301* @@ -327,6 +331,7 @@ usb:v27C6p5385* usb:v27C6p538C* usb:v27C6p538D* usb:v27C6p5395* +usb:v27C6p5503* usb:v27C6p5584* usb:v27C6p55A2* usb:v27C6p55A4* diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index 5244cc6a..16b6d18f 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -29,6 +29,7 @@ static const FpIdEntry whitelist_id_table[] = { * You can generate this list from the wiki page using e.g.: * gio cat https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md | sed -n 's!|.*\([0-9a-fA-F]\{4\}\):\([0-9a-fA-F]\{4\}\).*|.*! { .vid = 0x\1, .pid = 0x\2 },!p' */ + { .vid = 0x04e8, .pid = 0x730b }, { .vid = 0x04f3, .pid = 0x036b }, { .vid = 0x04f3, .pid = 0x0c00 }, { .vid = 0x04f3, .pid = 0x0c4c }, @@ -51,6 +52,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x06cb, .pid = 0x00d8 }, { .vid = 0x06cb, .pid = 0x00da }, { .vid = 0x06cb, .pid = 0x00dc }, + { .vid = 0x06cb, .pid = 0x00e4 }, { .vid = 0x06cb, .pid = 0x00e7 }, { .vid = 0x06cb, .pid = 0x00e9 }, { .vid = 0x06cb, .pid = 0x00fd }, @@ -66,6 +68,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x0bda, .pid = 0x5812 }, { .vid = 0x10a5, .pid = 0x0007 }, { .vid = 0x10a5, .pid = 0x9200 }, + { .vid = 0x10a5, .pid = 0x9800 }, { .vid = 0x1188, .pid = 0x9545 }, { .vid = 0x138a, .pid = 0x0007 }, { .vid = 0x138a, .pid = 0x003a }, @@ -87,6 +90,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x5042 }, { .vid = 0x27c6, .pid = 0x5110 }, { .vid = 0x27c6, .pid = 0x5117 }, + { .vid = 0x27c6, .pid = 0x5125 }, { .vid = 0x27c6, .pid = 0x5201 }, { .vid = 0x27c6, .pid = 0x521d }, { .vid = 0x27c6, .pid = 0x5301 }, @@ -98,6 +102,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x538c }, { .vid = 0x27c6, .pid = 0x538d }, { .vid = 0x27c6, .pid = 0x5395 }, + { .vid = 0x27c6, .pid = 0x5503 }, { .vid = 0x27c6, .pid = 0x5584 }, { .vid = 0x27c6, .pid = 0x55a2 }, { .vid = 0x27c6, .pid = 0x55a4 }, From f20b8bc3112d1ae240df79fd9b648ded99b74e06 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 24 May 2022 14:30:40 +0200 Subject: [PATCH 17/86] Release 1.94.4 --- NEWS | 11 +++++++++++ meson.build | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2e0a2c6a..e244ffb8 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,17 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +2022-05-24: v1.94.4 release + +Highlights: + * synaptics: New PIDs 0x0168, 0x015f + * elan: New PID 0x0c4b + * elanspi: New PID 0x241f + * synaptics: Minor fix to interrupt transfer resubmission + * Avoid sysfs writes if value is already expected + * Improvements to the testing setup + * Fixes to the internal critical section API + 2021-11-02: v1.94.3 release Highlights: diff --git a/meson.build b/meson.build index 3167fff3..823728c7 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '1.94.3', + version: '1.94.4', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', From 9c12b762a7c53d3637fe950805af31457bda1baa Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Jun 2022 15:35:14 +0200 Subject: [PATCH 18/86] print: Fix indentation --- libfprint/fpi-print.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h index fb388097..f3e72b40 100644 --- a/libfprint/fpi-print.h +++ b/libfprint/fpi-print.h @@ -42,9 +42,9 @@ gboolean fpi_print_add_from_image (FpPrint *print, FpImage *image, GError **error); -FpiMatchResult fpi_print_bz3_match (FpPrint * template, - FpPrint * print, - gint bz3_threshold, +FpiMatchResult fpi_print_bz3_match (FpPrint *temp, + FpPrint *print, + gint bz3_threshold, GError **error); /* Helpers to encode metadata into user ID strings. */ From d1fbf34fdf06f3182e0dfc84e7902c658b22d333 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Jun 2022 15:30:03 +0200 Subject: [PATCH 19/86] scripts: Update uncrustify configuration The mod_full_brace_if_chain option needs an integer (we want method 1) rather than a boolean. --- scripts/uncrustify.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/uncrustify.cfg b/scripts/uncrustify.cfg index 1dbd3bad..34b9a358 100644 --- a/scripts/uncrustify.cfg +++ b/scripts/uncrustify.cfg @@ -120,7 +120,7 @@ nl_multi_line_cond true # Not clear what to do about that... mod_full_brace_for Remove mod_full_brace_if Remove -mod_full_brace_if_chain True +mod_full_brace_if_chain 1 mod_full_brace_while Remove mod_full_brace_do Remove mod_full_brace_nl 3 From 7899bf4240819a28f3e29bd40d4e36aa432343b6 Mon Sep 17 00:00:00 2001 From: ArronYen Date: Mon, 20 Jun 2022 14:03:05 +0800 Subject: [PATCH 20/86] elanmoc: add PID 0x0c88 --- data/autosuspend.hwdb | 1 + libfprint/drivers/elanmoc/elanmoc.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 6e3fd396..52125630 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -146,6 +146,7 @@ usb:v04F3p0C58* usb:v04F3p0C7D* usb:v04F3p0C7E* usb:v04F3p0C82* +usb:v04F3p0C88* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 3185ee7a..ad23e93e 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -28,6 +28,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x04f3, .pid = 0x0c7d, }, { .vid = 0x04f3, .pid = 0x0c7e, }, { .vid = 0x04f3, .pid = 0x0c82, }, + { .vid = 0x04f3, .pid = 0x0c88, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; From 42c9003f49d32dd08fc2735a6cd3c75c4ea45964 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 14 Jun 2022 15:32:56 +0200 Subject: [PATCH 21/86] goodix: Lower poor capture warnings to debug message It is completely fine for a capture to have a low quality or fail. No need to warn about this. Main reason to remove it though is so that recordings that contain such a message do not trigger a failure. --- libfprint/drivers/goodixmoc/goodix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 4eeb7215..e892b707 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -661,7 +661,7 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self, /* */ if (resp->result >= GX_FAILED) { - fp_warn ("Capture sample failed, result: 0x%x", resp->result); + fp_info ("Capture sample failed, result: 0x%x", resp->result); fpi_device_enroll_progress (FP_DEVICE (self), self->enroll_stage, NULL, @@ -675,7 +675,7 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self, if ((resp->capture_data_resp.img_quality < self->sensorcfg->config[4]) || (resp->capture_data_resp.img_coverage < self->sensorcfg->config[5])) { - fp_warn ("Capture sample poor quality(%d): %d or coverage(%d): %d", + fp_info ("Capture sample poor quality(%d): %d or coverage(%d): %d", self->sensorcfg->config[4], resp->capture_data_resp.img_quality, self->sensorcfg->config[5], From 8552290becac51a89c9ff54dc82e6b2b896d4015 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jun 2022 16:05:18 +0200 Subject: [PATCH 22/86] goodix: Reset device if storage listing fails When opening the device, query the stored prints. This should usually always succeed (and it should be fast). If it fails, then we are very likely dealing with a corrupted template storage on the device. In that case, emit the command to clear the storage in order to reset the device and get it back into a usable state. --- libfprint/drivers/goodixmoc/goodix.c | 65 +++++++++++++++++++++++++++ libfprint/drivers/goodixmoc/goodix.h | 2 + tests/goodixmoc/custom.pcapng | Bin 61764 -> 73120 bytes tests/goodixmoc/custom.py | 3 ++ tests/goodixmoc/device | 57 +++++++++++------------ 5 files changed, 99 insertions(+), 28 deletions(-) diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index e892b707..cfc69c94 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1041,6 +1041,47 @@ fp_init_config_cb (FpiDeviceGoodixMoc *self, fpi_ssm_next_state (self->task_ssm); } +static void +fp_init_cb_reset_or_complete (FpiDeviceGoodixMoc *self, + gxfp_cmd_response_t *resp, + GError *error) +{ + if (error) + { + fp_warn ("Template storage appears to have been corrupted! Error was: %s", error->message); + fp_warn ("A known reason for this to happen is a firmware bug triggered by another storage area being initialized."); + fpi_ssm_jump_to_state (self->task_ssm, FP_INIT_RESET_DEVICE); + } + else + { + fpi_ssm_mark_completed (self->task_ssm); + } +} + +static void +fp_init_reset_device_cb (FpiDeviceGoodixMoc *self, + gxfp_cmd_response_t *resp, + GError *error) +{ + if (error) + { + fp_warn ("Reset failed: %s", error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) + { + fp_warn ("Reset failed, device reported: 0x%x", resp->result); + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Failed clear storage, result: 0x%x", + resp->result)); + return; + } + + fp_warn ("Reset completed"); + fpi_ssm_mark_completed (self->task_ssm); +} static void fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device) @@ -1065,6 +1106,30 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device) sizeof (gxfp_sensor_cfg_t), fp_init_config_cb); break; + + case FP_INIT_TEMPLATE_LIST: + /* List prints to check whether the template DB was corrupted. + * As of 2022-06-13 there is a known firmware issue that can cause the + * stored templates for Linux to be corrupted when the Windows storage + * area is initialized. + * In that case, we'll get a protocol failure trying to retrieve the + * list of prints. + */ + goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, + FALSE, + (const guint8 *) &dummy, + 1, + fp_init_cb_reset_or_complete); + break; + + case FP_INIT_RESET_DEVICE: + fp_warn ("Resetting device storage, you will need to enroll all prints again!"); + goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL, + FALSE, + NULL, + 0, + fp_init_reset_device_cb); + break; } diff --git a/libfprint/drivers/goodixmoc/goodix.h b/libfprint/drivers/goodixmoc/goodix.h index 23e142ac..56b2d171 100644 --- a/libfprint/drivers/goodixmoc/goodix.h +++ b/libfprint/drivers/goodixmoc/goodix.h @@ -35,6 +35,8 @@ typedef enum { typedef enum { FP_INIT_VERSION = 0, FP_INIT_CONFIG, + FP_INIT_TEMPLATE_LIST, + FP_INIT_RESET_DEVICE, FP_INIT_NUM_STATES, } FpInitState; diff --git a/tests/goodixmoc/custom.pcapng b/tests/goodixmoc/custom.pcapng index eb58d865e5516dc652fdbe299dc5ebd94f377d79..b5e2d89c75a7253571360a9e064bb31259834e2d 100644 GIT binary patch literal 73120 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

L4zz?BJ>h*kk0r(^u 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 QJ9pd8@{S6L6%17Se}dI!Qvd(} literal 61764 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 XA9BL*ba>_@+GdQ={*Uef)B^oq$y{Nf diff --git a/tests/goodixmoc/custom.py b/tests/goodixmoc/custom.py index 1fb513a1..38fdd26c 100755 --- a/tests/goodixmoc/custom.py +++ b/tests/goodixmoc/custom.py @@ -25,6 +25,9 @@ assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR) d.open_sync() +# 1. verify clear storage command, 2. make sure later asserts are good +d.clear_storage_sync() + template = FPrint.Print.new(d) def enroll_progress(*args): diff --git a/tests/goodixmoc/device b/tests/goodixmoc/device index 9fb39e59..1e209a1d 100644 --- a/tests/goodixmoc/device +++ b/tests/goodixmoc/device @@ -1,14 +1,14 @@ P: /devices/pci0000:00/0000:00:14.0/usb1/1-3 -N: bus/usb/001/053=12010002EF000040C627966400010102030109022000010103A0320904000002FF0000040705830240000007050102400000 -E: DEVNAME=/dev/bus/usb/001/053 +N: bus/usb/001/023=12010002EF000040C627966400010102030109022000010103A0320904000002FF0000040705830240000007050102400000 +E: DEVNAME=/dev/bus/usb/001/023 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=27c6/6496/100 E: TYPE=239/0/0 E: BUSNUM=001 -E: DEVNUM=053 +E: DEVNUM=023 E: MAJOR=189 -E: MINOR=52 +E: MINOR=22 E: SUBSYSTEM=usb E: ID_VENDOR=Goodix_Technology_Co.__Ltd. E: ID_VENDOR_ENC=Goodix\x20Technology\x20Co.\x2c\x20Ltd. @@ -23,6 +23,7 @@ E: ID_BUS=usb E: ID_USB_INTERFACES=:ff0000: E: ID_VENDOR_FROM_DATABASE=Shenzhen Goodix Technology Co.,Ltd. E: ID_AUTOSUSPEND=1 +E: ID_PERSIST=0 E: ID_PATH=pci-0000:00:14.0-usb-0:3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3 A: authorized=1\n @@ -40,8 +41,8 @@ A: bmAttributes=a0\n A: busnum=1\n A: configuration=XXXX_MOC_B0\n H: descriptors=12010002EF000040C627966400010102030109022000010103A0320904000002FF0000040705830240000007050102400000 -A: dev=189:52\n -A: devnum=53\n +A: dev=189:22\n +A: devnum=23\n A: devpath=3\n L: driver=../../../../../bus/usb/drivers/usb L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d/device:20 @@ -51,16 +52,16 @@ A: ltm_capable=no\n A: manufacturer=Goodix Technology Co., Ltd.\n A: maxchild=0\n L: port=../1-0:1.0/usb1-port3 -A: power/active_duration=29262\n +A: power/active_duration=22667\n A: power/autosuspend=2\n A: power/autosuspend_delay_ms=2000\n -A: power/connected_duration=57399\n +A: power/connected_duration=917616\n A: power/control=auto\n A: power/level=auto\n A: power/persist=1\n -A: power/runtime_active_time=29308\n +A: power/runtime_active_time=22809\n A: power/runtime_status=active\n -A: power/runtime_suspended_time=27850\n +A: power/runtime_suspended_time=894564\n A: power/wakeup=disabled\n A: power/wakeup_abort_count=\n A: power/wakeup_active=\n @@ -77,29 +78,29 @@ A: rx_lanes=1\n A: serial=XXXX_MOC_B0\n A: speed=12\n A: tx_lanes=1\n -A: urbnum=394\n +A: urbnum=298\n A: version= 2.00\n P: /devices/pci0000:00/0000:00:14.0/usb1 -N: bus/usb/001/001=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C +N: bus/usb/001/001=12010002090001406B1D020017050302010109021900010100E0000904000001090000000705810304000C E: DEVNAME=/dev/bus/usb/001/001 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=1d6b/2/513 +E: PRODUCT=1d6b/2/517 E: TYPE=9/0/1 E: BUSNUM=001 E: DEVNUM=001 E: MAJOR=189 E: MINOR=0 E: SUBSYSTEM=usb -E: ID_VENDOR=Linux_5.13.15-200.fc34.x86_64_xhci-hcd -E: ID_VENDOR_ENC=Linux\x205.13.15-200.fc34.x86_64\x20xhci-hcd +E: ID_VENDOR=Linux_5.17.12-300.fc36.x86_64_xhci-hcd +E: ID_VENDOR_ENC=Linux\x205.17.12-300.fc36.x86_64\x20xhci-hcd E: ID_VENDOR_ID=1d6b E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_ID=0002 -E: ID_REVISION=0513 -E: ID_SERIAL=Linux_5.13.15-200.fc34.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 +E: ID_REVISION=0517 +E: ID_SERIAL=Linux_5.17.12-300.fc36.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_BUS=usb E: ID_USB_INTERFACES=:090000: @@ -122,11 +123,11 @@ A: bMaxPacketSize0=64\n A: bMaxPower=0mA\n A: bNumConfigurations=1\n A: bNumInterfaces= 1\n -A: bcdDevice=0513\n +A: bcdDevice=0517\n A: bmAttributes=e0\n A: busnum=1\n A: configuration=\n -H: descriptors=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C +H: descriptors=12010002090001406B1D020017050302010109021900010100E0000904000001090000000705810304000C A: dev=189:0\n A: devnum=1\n A: devpath=0\n @@ -136,15 +137,15 @@ A: idProduct=0002\n A: idVendor=1d6b\n A: interface_authorized_default=1\n A: ltm_capable=no\n -A: manufacturer=Linux 5.13.15-200.fc34.x86_64 xhci-hcd\n +A: manufacturer=Linux 5.17.12-300.fc36.x86_64 xhci-hcd\n A: maxchild=12\n -A: power/active_duration=219578717\n +A: power/active_duration=164289796\n A: power/autosuspend=0\n A: power/autosuspend_delay_ms=0\n -A: power/connected_duration=219649620\n +A: power/connected_duration=164360220\n A: power/control=auto\n A: power/level=auto\n -A: power/runtime_active_time=219589127\n +A: power/runtime_active_time=164331876\n A: power/runtime_status=active\n A: power/runtime_suspended_time=0\n A: power/wakeup=disabled\n @@ -163,14 +164,14 @@ A: rx_lanes=1\n A: serial=0000:00:14.0\n A: speed=480\n A: tx_lanes=1\n -A: urbnum=4325\n +A: urbnum=2097\n A: version= 2.00\n P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd E: PCI_CLASS=C0330 E: PCI_ID=8086:9DED -E: PCI_SUBSYS_ID=17AA:2292\n +E: PCI_SUBSYS_ID=17AA:2292 E: PCI_SLOT_NAME=0000:00:14.0 E: MODALIAS=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30 E: SUBSYSTEM=pci @@ -183,7 +184,7 @@ E: ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller A: ari_enabled=0\n A: broken_parity_status=0\n A: class=0x0c0330\n -H: config=8680ED9D060490021130030C00008000040022EA000000000000000000000000000000000000000000000000AA179222000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F000000004C084B0100000000316000000000000000000000000000000180C2C1080000000000000000000000059087001803E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000000000000000000008000000040000000000000000000000000000000000000000000000000000000800000004000000000000000000000000000000000000000000000000000000B50F320112000000 +H: config=8680ED9D060490021130030C00008000040022EA000000000000000000000000000000000000000000000000AA179222000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F00000000F507312600000000316000000000000000000000000000000180C2C1080000000000000000000000059087001803E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000000000000000000008000000040000000000000000000000000000000000000000000000000000000800000004000000000000000000000000000000000000000000000000000000B50F320112000000 A: consistent_dma_mask_bits=64\n A: d3cold_allowed=1\n A: dbc=disabled\n @@ -201,8 +202,8 @@ A: msi_bus=1\n A: msi_irqs/128=msi\n A: numa_node=-1\n A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 46 50 4096 50\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 6 32 128 1\nbuffer-32 0 0 32 0\n -A: power/control=on\n -A: power/runtime_active_time=219589302\n +A: power/control=auto\n +A: power/runtime_active_time=164332777\n A: power/runtime_status=active\n A: power/runtime_suspended_time=0\n A: power/wakeup=enabled\n From 08da0eb1e196c9b62ef4151c3d0408d77179823a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 22 Jun 2022 17:37:26 +0200 Subject: [PATCH 23/86] goodix: Make fingerlist parse error non-fatal Otherwise we cannot recover from the error by doing a device reset. --- libfprint/drivers/goodixmoc/goodix_proto.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libfprint/drivers/goodixmoc/goodix_proto.c b/libfprint/drivers/goodixmoc/goodix_proto.c index b615dbaa..72511a88 100644 --- a/libfprint/drivers/goodixmoc/goodix_proto.c +++ b/libfprint/drivers/goodixmoc/goodix_proto.c @@ -393,10 +393,8 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_c fingerid_length, &presp->finger_list_resp.finger_list[num]) != 0) { - g_error ("parse fingerlist error"); - presp->finger_list_resp.finger_num = 0; - presp->result = GX_FAILED; - break; + g_warning ("Failed to parse finger list"); + return -1; } offset += fingerid_length; } From 61f0f86904ebeb4f5495bac92a8e2d0950542853 Mon Sep 17 00:00:00 2001 From: Sam James Date: Thu, 23 Jun 2022 05:57:46 +0100 Subject: [PATCH 24/86] nbis: fix build on musl Drop re-definition of stderr. There's no need for this anywhere (including glibc). This breaks in particular on musl because stderr (and stdin) are both const, and macros unlike in glibc. Bug: https://bugs.gentoo.org/853811 --- libfprint/nbis/fix-musl-build.patch | 31 +++++++++++++++++++++++++++++ libfprint/nbis/include/bozorth.h | 2 -- libfprint/nbis/update-from-nbis.sh | 3 +++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 libfprint/nbis/fix-musl-build.patch diff --git a/libfprint/nbis/fix-musl-build.patch b/libfprint/nbis/fix-musl-build.patch new file mode 100644 index 00000000..e27a8fa7 --- /dev/null +++ b/libfprint/nbis/fix-musl-build.patch @@ -0,0 +1,31 @@ +From 2584d440afc87d463cb8dc809d48c660e091c2c4 Mon Sep 17 00:00:00 2001 +From: Sam James +Date: Thu, 23 Jun 2022 05:57:46 +0100 +Subject: [PATCH] nbis: fix build on musl + +Drop re-definition of stderr. There's no need for this anywhere +(including glibc). This breaks in particular on musl because +stderr (and stdin) are both const, and macros unlike in glibc. + +Bug: https://bugs.gentoo.org/853811 +--- + nbis/include/bozorth.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/nbis/include/bozorth.h b/nbis/include/bozorth.h +index a705da98..fd8975bf 100644 +--- a/nbis/include/bozorth.h ++++ b/nbis/include/bozorth.h +@@ -217,8 +217,6 @@ struct xytq_struct { + /**************************************************************************/ + /* Globals supporting command line options */ + extern int verbose_threshold; +-/* Global supporting error reporting */ +-extern FILE *stderr; + + /**************************************************************************/ + /* In: BZ_GBLS.C */ +-- +GitLab + + diff --git a/libfprint/nbis/include/bozorth.h b/libfprint/nbis/include/bozorth.h index a705da98..fd8975bf 100644 --- a/libfprint/nbis/include/bozorth.h +++ b/libfprint/nbis/include/bozorth.h @@ -217,8 +217,6 @@ struct xytq_struct { /**************************************************************************/ /* Globals supporting command line options */ extern int verbose_threshold; -/* Global supporting error reporting */ -extern FILE *stderr; /**************************************************************************/ /* In: BZ_GBLS.C */ diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh index f7ec0eeb..9bbaf790 100755 --- a/libfprint/nbis/update-from-nbis.sh +++ b/libfprint/nbis/update-from-nbis.sh @@ -198,3 +198,6 @@ patch -p0 < fix-scan-build-reports.patch # Add pass to remove perimeter points patch -p0 < remove-perimeter-pts.patch + +# Fix build on musl by dropping unnecessary redeclaration of stderr +patch -p0 < fix-musl-build.patch From 24e7e1f1001ebe071c48d77d4b6dcdcf401eb8aa Mon Sep 17 00:00:00 2001 From: hermanlin Date: Thu, 30 Jun 2022 15:52:46 +0800 Subject: [PATCH 25/86] elanmoc: Make sure sensor in the right mode at identity Signed-off-by: hermanlin --- libfprint/drivers/elanmoc/elanmoc.c | 8 ++ tests/elanmoc/custom.pcapng | Bin 19368 -> 17540 bytes tests/elanmoc/device | 136 +++++++++++++++------------- 3 files changed, 80 insertions(+), 64 deletions(-) diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index ad23e93e..5bcfce27 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -759,6 +759,7 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id, } enum identify_states { + IDENTIFY_SET_MODE, IDENTIFY_WAIT_FINGER, IDENTIFY_NUM_STATES, }; @@ -794,6 +795,13 @@ elan_identify_run_state (FpiSsm *ssm, FpDevice *dev) fp_info ("elanmoc %s ", __func__); switch (fpi_ssm_get_cur_state (ssm)) { + case IDENTIFY_SET_MODE: + fp_info ("elanmoc %s IDENTIFY_SET_MODE", __func__); + cmd_buf = elanmoc_compose_cmd (&elanmoc_set_mod_cmd); + cmd_buf[3] = 0x03; + elanmoc_get_cmd (dev, cmd_buf, elanmoc_set_mod_cmd.cmd_len, elanmoc_set_mod_cmd.resp_len, 0, elanmoc_cmd_ack_cb); + break; + case IDENTIFY_WAIT_FINGER: fp_info ("elanmoc %s VERIFY_WAIT_FINGER", __func__); cmd_buf = elanmoc_compose_cmd (&elanmoc_verify_cmd); diff --git a/tests/elanmoc/custom.pcapng b/tests/elanmoc/custom.pcapng index a41ac1626fe77062bf0bbfe81773715dd8a9a222..c839c37e922c91f8834f24fc326307a377ff36a9 100644 GIT binary patch literal 17540 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 QnE!q=SN$Uy0ZttM1Ehp|k^lez diff --git a/tests/elanmoc/device b/tests/elanmoc/device index ef3400dd..34751f2d 100644 --- a/tests/elanmoc/device +++ b/tests/elanmoc/device @@ -1,63 +1,67 @@ -P: /devices/pci0000:00/0000:00:14.0/usb1/1-1 -N: bus/usb/001/010=1201000200000040F3047E0C05030102000109025300010103A0320904000008FF0000000921100100012215000705810240000107050102400001070582024000010705020240000107058302400001070503024000010705840240000107050402400001 -E: DEVNAME=/dev/bus/usb/001/010 +P: /devices/pci0000:00/0000:00:14.0/usb1/1-9 +N: bus/usb/001/003=1201000200000008F304880C04800102000109025300010100A0320904000008FF0000000921100100012215000705810240000107050102400001070582024000010705020240000107058302400001070503024000010705840240000107050402400001 +E: DEVNAME=/dev/bus/usb/001/003 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=4f3/c7e/305 +E: PRODUCT=4f3/c88/8004 E: TYPE=0/0/0 E: BUSNUM=001 -E: DEVNUM=010 +E: DEVNUM=003 E: MAJOR=189 -E: MINOR=9 +E: MINOR=2 E: SUBSYSTEM=usb E: ID_VENDOR=ELAN E: ID_VENDOR_ENC=ELAN E: ID_VENDOR_ID=04f3 E: ID_MODEL=ELAN:ARM-M4 E: ID_MODEL_ENC=ELAN:ARM-M4 -E: ID_MODEL_ID=0c7e -E: ID_REVISION=0305 +E: ID_MODEL_ID=0c88 +E: ID_REVISION=8004 E: ID_SERIAL=ELAN_ELAN:ARM-M4 E: ID_BUS=usb E: ID_USB_INTERFACES=:ff0000: E: ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp. -E: ID_PATH=pci-0000:00:14.0-usb-0:1 -E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1 +E: ID_PATH=pci-0000:00:14.0-usb-0:9 +E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_9 +E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_9 +E: TAGS=:seat: +E: CURRENT_TAGS=:seat: A: authorized=1\n A: avoid_reset_quirk=0\n A: bConfigurationValue=1\n A: bDeviceClass=00\n A: bDeviceProtocol=00\n A: bDeviceSubClass=00\n -A: bMaxPacketSize0=64\n +A: bMaxPacketSize0=8\n A: bMaxPower=100mA\n A: bNumConfigurations=1\n A: bNumInterfaces= 1\n -A: bcdDevice=0305\n +A: bcdDevice=8004\n A: bmAttributes=a0\n A: busnum=1\n -A: configuration=add909c9-e67e-4126-a6f7-1e31179e27d9\n -H: descriptors=1201000200000040F3047E0C05030102000109025300010103A0320904000008FF0000000921100100012215000705810240000107050102400001070582024000010705020240000107058302400001070503024000010705840240000107050402400001 -A: dev=189:9\n -A: devnum=10\n -A: devpath=1\n +A: configuration= +H: descriptors=1201000200000008F304880C04800102000109025300010100A0320904000008FF0000000921100100012215000705810240000107050102400001070582024000010705020240000107058302400001070503024000010705840240000107050402400001 +A: dev=189:2\n +A: devnum=3\n +A: devpath=9\n L: driver=../../../../../bus/usb/drivers/usb -A: idProduct=0c7e\n +L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:3d/device:3e/device:47 +A: idProduct=0c88\n A: idVendor=04f3\n A: ltm_capable=no\n A: manufacturer=ELAN\n A: maxchild=0\n -L: port=../1-0:1.0/usb1-port1 -A: power/active_duration=94712\n +L: port=../1-0:1.0/usb1-port9 +A: power/active_duration=35269124\n A: power/async=enabled\n A: power/autosuspend=2\n A: power/autosuspend_delay_ms=2000\n -A: power/connected_duration=94712\n +A: power/connected_duration=35283788\n A: power/control=on\n A: power/level=on\n -A: power/persist=1\n +A: power/persist=0\n A: power/runtime_active_kids=0\n -A: power/runtime_active_time=94436\n +A: power/runtime_active_time=35276624\n A: power/runtime_enabled=forbidden\n A: power/runtime_status=active\n A: power/runtime_suspended_time=0\n @@ -77,38 +81,40 @@ A: removable=removable\n A: rx_lanes=1\n A: speed=12\n A: tx_lanes=1\n -A: urbnum=12\n +A: urbnum=2773\n A: version= 2.00\n P: /devices/pci0000:00/0000:00:14.0/usb1 -N: bus/usb/001/001=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C +N: bus/usb/001/001=12010002090001406B1D020015050302010109021900010100E0000904000001090000000705810304000C E: DEVNAME=/dev/bus/usb/001/001 E: DEVTYPE=usb_device E: DRIVER=usb -E: PRODUCT=1d6b/2/504 +E: PRODUCT=1d6b/2/515 E: TYPE=9/0/1 E: BUSNUM=001 E: DEVNUM=001 E: MAJOR=189 E: MINOR=0 E: SUBSYSTEM=usb -E: ID_VENDOR=Linux_5.4.0-42-generic_xhci-hcd -E: ID_VENDOR_ENC=Linux\x205.4.0-42-generic\x20xhci-hcd +E: ID_VENDOR=Linux_5.15.0-39-generic_xhci-hcd +E: ID_VENDOR_ENC=Linux\x205.15.0-39-generic\x20xhci-hcd E: ID_VENDOR_ID=1d6b E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_ID=0002 -E: ID_REVISION=0504 -E: ID_SERIAL=Linux_5.4.0-42-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 +E: ID_REVISION=0515 +E: ID_SERIAL=Linux_5.15.0-39-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_BUS=usb E: ID_USB_INTERFACES=:090000: E: ID_VENDOR_FROM_DATABASE=Linux Foundation +E: ID_AUTOSUSPEND=1 E: ID_MODEL_FROM_DATABASE=2.0 root hub E: ID_PATH=pci-0000:00:14.0 E: ID_PATH_TAG=pci-0000_00_14_0 E: ID_FOR_SEAT=usb-pci-0000_00_14_0 E: TAGS=:seat: +E: CURRENT_TAGS=:seat: A: authorized=1\n A: authorized_default=1\n A: avoid_reset_quirk=0\n @@ -120,30 +126,31 @@ A: bMaxPacketSize0=64\n A: bMaxPower=0mA\n A: bNumConfigurations=1\n A: bNumInterfaces= 1\n -A: bcdDevice=0504\n +A: bcdDevice=0515\n A: bmAttributes=e0\n A: busnum=1\n -A: configuration=\n -H: descriptors=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C +A: configuration= +H: descriptors=12010002090001406B1D020015050302010109021900010100E0000904000001090000000705810304000C A: dev=189:0\n A: devnum=1\n A: devpath=0\n L: driver=../../../../bus/usb/drivers/usb +L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:3d/device:3e A: idProduct=0002\n A: idVendor=1d6b\n A: interface_authorized_default=1\n A: ltm_capable=no\n -A: manufacturer=Linux 5.4.0-42-generic xhci-hcd\n -A: maxchild=12\n -A: power/active_duration=74604360\n +A: manufacturer=Linux 5.15.0-39-generic xhci-hcd\n +A: maxchild=14\n +A: power/active_duration=35270364\n A: power/async=enabled\n A: power/autosuspend=0\n A: power/autosuspend_delay_ms=0\n -A: power/connected_duration=74606456\n +A: power/connected_duration=35284300\n A: power/control=auto\n A: power/level=auto\n -A: power/runtime_active_kids=4\n -A: power/runtime_active_time=74605838\n +A: power/runtime_active_kids=2\n +A: power/runtime_active_time=35277420\n A: power/runtime_enabled=enabled\n A: power/runtime_status=active\n A: power/runtime_suspended_time=0\n @@ -164,62 +171,63 @@ A: rx_lanes=1\n A: serial=0000:00:14.0\n A: speed=480\n A: tx_lanes=1\n -A: urbnum=490\n +A: urbnum=549\n A: version= 2.00\n P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd E: PCI_CLASS=C0330 -E: PCI_ID=8086:9DED -E: PCI_SUBSYS_ID=103C:85EF +E: PCI_ID=8086:8C31 +E: PCI_SUBSYS_ID=1043:201F E: PCI_SLOT_NAME=0000:00:14.0 -E: MODALIAS=pci:v00008086d00009DEDsv0000103Csd000085EFbc0Csc03i30 +E: MODALIAS=pci:v00008086d00008C31sv00001043sd0000201Fbc0Csc03i30 E: SUBSYSTEM=pci E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_VENDOR_FROM_DATABASE=Intel Corporation -E: ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller +E: ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI A: ari_enabled=0\n A: broken_parity_status=0\n A: class=0x0c0330\n -H: config=8680ED9D060490023030030C00008000040030A10000000000000000000000000000000000000000000000003C10EF85000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F00000000181C030400000000316000000000000000000000000000000180C2C1080000000000000000000000059087007802E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000B50F300112000000 +H: config=8680318C060490020530030C000000000400A0F700000000000000000000000000000000000000000000000043101F200000000070000000000000000B010000FD01368089C60F8000000000000000009F6E8807000000000000000000000000302000000000000000000000000000000180C2C1080000000000000000000000050087000410E0FE000000002F00000000000000000000000000000000000000400100000000000000000000000000000F000100000000000000000000000000030420C0030C3000030C300000000000FF1A0000FF1A00003F0000003F000000A00000000000000000000000D8D8D8080000000000000000B10F060800000000 A: consistent_dma_mask_bits=64\n A: d3cold_allowed=1\n -A: dbc=disabled\n -A: device=0x9ded\n +A: device=0x8c31\n A: dma_mask_bits=64\n L: driver=../../../bus/pci/drivers/xhci_hcd A: driver_override=(null)\n A: enable=1\n -A: irq=124\n +L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:3d +A: irq=31\n A: local_cpulist=0-3\n A: local_cpus=f\n -A: modalias=pci:v00008086d00009DEDsv0000103Csd000085EFbc0Csc03i30\n +A: modalias=pci:v00008086d00008C31sv00001043sd0000201Fbc0Csc03i30\n A: msi_bus=1\n -A: msi_irqs/124=msi\n +A: msi_irqs/31=msi\n A: numa_node=-1\n -A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 54 54 4096 54\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 9 32 128 1\nbuffer-32 0 0 32 0\n +A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 5 6 2112 6\nxHCI ring segments 24 24 4096 24\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 3 32 128 1\nbuffer-32 0 0 32 0\n A: power/async=enabled\n -A: power/control=auto\n +A: power/control=on\n A: power/runtime_active_kids=1\n -A: power/runtime_active_time=74606194\n -A: power/runtime_enabled=enabled\n +A: power/runtime_active_time=35278060\n +A: power/runtime_enabled=forbidden\n A: power/runtime_status=active\n A: power/runtime_suspended_time=0\n -A: power/runtime_usage=0\n +A: power/runtime_usage=1\n A: power/wakeup=enabled\n A: power/wakeup_abort_count=0\n A: power/wakeup_active=0\n -A: power/wakeup_active_count=0\n +A: power/wakeup_active_count=5\n A: power/wakeup_count=0\n -A: power/wakeup_expire_count=0\n -A: power/wakeup_last_time_ms=0\n -A: power/wakeup_max_time_ms=0\n -A: power/wakeup_total_time_ms=0\n -A: resource=0x00000000a1300000 0x00000000a130ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n -A: revision=0x30\n -A: subsystem_device=0x85ef\n -A: subsystem_vendor=0x103c\n +A: power/wakeup_expire_count=5\n +A: power/wakeup_last_time_ms=12694896\n +A: power/wakeup_max_time_ms=103\n +A: power/wakeup_total_time_ms=518\n +A: power_state=D0\n +A: resource=0x00000000f7a00000 0x00000000f7a0ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n +A: revision=0x05\n +A: subsystem_device=0x201f\n +A: subsystem_vendor=0x1043\n A: vendor=0x8086\n From f03d9361e3af4924b2e460e7cf6158c9db8e6cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 14 Jul 2022 21:12:51 +0200 Subject: [PATCH 26/86] fpi-device: Improve documentation for identify/verify report and complete We still mentioned variables that are not accepted anymore since we switched to match reporting API. --- libfprint/fpi-device.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index c9157eb3..36f8ccad 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1312,12 +1312,14 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) * @device: The #FpDevice * @error: A #GError if result is %FPI_MATCH_ERROR * - * Finish an ongoing verify operation. The returned print should be - * representing the new scan and not the one passed for verification. + * Finish an ongoing verify operation. * * Note that @error should only be set for actual errors. In the case * of retry errors, report these using fpi_device_verify_report() * and then call this function without any error argument. + * + * If @error is not set, we expect that a result (and print, in case) + * have been already reported via fpi_device_verify_report(). */ void fpi_device_verify_complete (FpDevice *device, @@ -1375,9 +1377,14 @@ fpi_device_verify_complete (FpDevice *device, * @device: The #FpDevice * @error: The #GError or %NULL on success * - * Finish an ongoing identify operation. The match that was identified is - * returned in @match. The @print parameter returns the newly created scan - * that was used for matching. + * Finish an ongoing identify operation. + * + * Note that @error should only be set for actual errors. In the case + * of retry errors, report these using fpi_device_identify_report() + * and then call this function without any error argument. + * + * If @error is not set, we expect that a match and / or a print have been + * already reported via fpi_device_identify_report() */ void fpi_device_identify_complete (FpDevice *device, From 7f6ab61292ac7950e68aa58664956d97fe0e23f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 14 Jul 2022 21:14:29 +0200 Subject: [PATCH 27/86] fp-device: Return an error if prints are invalid We'd crash later otherwise, while it's better to return an error. --- libfprint/fp-device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index b94f7d80..0d79fae1 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -1400,6 +1400,14 @@ fp_device_identify (FpDevice *device, return; } + if (prints == NULL) + { + g_task_return_error (task, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID, + "Invalid gallery array")); + return; + } + priv->current_action = FPI_DEVICE_ACTION_IDENTIFY; priv->current_task = g_steal_pointer (&task); setup_task_cancellable (device); From fb9e054637c4fd136b959349454ce581e39f083f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 14 Jul 2022 21:35:30 +0200 Subject: [PATCH 28/86] test-fp-device: Add few tests to check identification init errors --- tests/test-fp-device.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/test-fp-device.c b/tests/test-fp-device.c index a633eb91..dbaec9b2 100644 --- a/tests/test-fp-device.c +++ b/tests/test-fp-device.c @@ -232,6 +232,36 @@ test_device_has_storage (void) G_GNUC_END_IGNORE_DEPRECATIONS } +static void +test_device_identify_cancelled (void) +{ + g_autoptr(GCancellable) cancellable = NULL; + g_autoptr(GPtrArray) prints = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); + + fp_device_open_sync (tctx->device, NULL, NULL); + + prints = g_ptr_array_new (); + cancellable = g_cancellable_new (); + g_cancellable_cancel (cancellable); + g_assert_false (fp_device_identify_sync (tctx->device, prints, cancellable, + NULL, NULL, NULL, NULL, &error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); +} + +static void +test_device_identify_null_prints (void) +{ + g_autoptr(GError) error = NULL; + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE); + + fp_device_open_sync (tctx->device, NULL, NULL); + g_assert_false (fp_device_identify_sync (tctx->device, NULL, NULL, NULL, + NULL, NULL, NULL, &error)); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); +} + int main (int argc, char *argv[]) { @@ -252,6 +282,8 @@ main (int argc, char *argv[]) g_test_add_func ("/device/sync/supports_identify", test_device_supports_identify); g_test_add_func ("/device/sync/supports_capture", test_device_supports_capture); g_test_add_func ("/device/sync/has_storage", test_device_has_storage); + g_test_add_func ("/device/sync/identify/cancelled", test_device_identify_cancelled); + g_test_add_func ("/device/sync/identify/null-prints", test_device_identify_null_prints); return g_test_run (); } From 15bee898b8da6ca92c701a14997aef45e5dba113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 14 Jul 2022 22:13:11 +0200 Subject: [PATCH 29/86] ci: Use junit test reports They can be used to show test failure logs directly in the MR's pipelines page. --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca8587e0..27d71d10 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -69,6 +69,8 @@ test: - ninja -C _build coverage - cat _build/meson-logs/coverage.txt artifacts: + reports: + junit: "_build/meson-logs/testlog.junit.xml" expose_as: 'Coverage Report' when: always paths: @@ -87,6 +89,8 @@ test_valgrind: - ninja -C _build - meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind artifacts: + reports: + junit: "_build/meson-logs/testlog.junit.xml" expose_as: 'Valgrind test logs' when: always paths: From 489332c07da4092adf75e28d86e1c9dad744af7a Mon Sep 17 00:00:00 2001 From: yangdi Date: Tue, 19 Jul 2022 11:37:09 +0800 Subject: [PATCH 30/86] goodixmoc: add PID 0x659A --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 52125630..c1ac670e 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -168,6 +168,7 @@ usb:v27C6p6584* usb:v27C6p658C* usb:v27C6p6592* usb:v27C6p6594* +usb:v27C6p659A* usb:v27C6p659C* usb:v27C6p6A94* ID_AUTOSUSPEND=1 diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index cfc69c94..a68b398c 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1365,6 +1365,7 @@ gx_fp_probe (FpDevice *device) case 0x63BC: case 0x63CC: case 0x6A94: + case 0x659A: self->max_enroll_stage = 12; break; @@ -1606,6 +1607,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x658C, }, { .vid = 0x27c6, .pid = 0x6592, }, { .vid = 0x27c6, .pid = 0x6594, }, + { .vid = 0x27c6, .pid = 0x659A, }, { .vid = 0x27c6, .pid = 0x659C, }, { .vid = 0x27c6, .pid = 0x6A94, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ From f007161bcd70699ff4f6c0f1a15ed8e18001ee6a Mon Sep 17 00:00:00 2001 From: Marcus Pfeffer Date: Wed, 22 Jun 2022 10:05:25 +0200 Subject: [PATCH 31/86] goodixmoc: add PID 0x6384 Closes: #489 --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index c1ac670e..60f3d0bc 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -159,6 +159,7 @@ usb:v1C7Ap0603* usb:v27C6p5840* usb:v27C6p609C* usb:v27C6p60A2* +usb:v27C6p6384* usb:v27C6p639C* usb:v27C6p63AC* usb:v27C6p63BC* diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index a68b398c..5dd57edd 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1360,6 +1360,7 @@ gx_fp_probe (FpDevice *device) case 0x6496: case 0x60A2: case 0x609C: + case 0x6384: case 0x639C: case 0x63AC: case 0x63BC: @@ -1598,6 +1599,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x5840, }, { .vid = 0x27c6, .pid = 0x609C, }, { .vid = 0x27c6, .pid = 0x60A2, }, + { .vid = 0x27c6, .pid = 0x6384, }, { .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x63AC, }, { .vid = 0x27c6, .pid = 0x63BC, }, From fb63c39750f0cdabb8447761bb8d4a50842927c5 Mon Sep 17 00:00:00 2001 From: Johnny Li Date: Mon, 25 Jul 2022 14:11:37 +0800 Subject: [PATCH 32/86] elanmoc: add PID 0x0c8c & 0x0c8d --- data/autosuspend.hwdb | 2 ++ libfprint/drivers/elanmoc/elanmoc.c | 27 ++++++++++++++++++++++++--- libfprint/drivers/elanmoc/elanmoc.h | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 60f3d0bc..d755744e 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -147,6 +147,8 @@ usb:v04F3p0C7D* usb:v04F3p0C7E* usb:v04F3p0C82* usb:v04F3p0C88* +usb:v04F3p0C8C* +usb:v04F3p0C8D* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 5bcfce27..77e22f25 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -29,6 +29,8 @@ static const FpIdEntry id_table[] = { { .vid = 0x04f3, .pid = 0x0c7e, }, { .vid = 0x04f3, .pid = 0x0c82, }, { .vid = 0x04f3, .pid = 0x0c88, }, + { .vid = 0x04f3, .pid = 0x0c8c, }, + { .vid = 0x04f3, .pid = 0x0c8d, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; @@ -377,9 +379,9 @@ elanmoc_enroll_cb (FpiDeviceElanmoc *self, enroll_status_report (self, ENROLL_RSP_RETRY, self->num_frames, NULL); } - if (self->num_frames == ELAN_MOC_ENROLL_TIMES && buffer_in[1] == ELAN_MSG_OK) + if (self->num_frames == self->max_moc_enroll_time && buffer_in[1] == ELAN_MSG_OK) fpi_ssm_next_state (self->task_ssm); - else if (self->num_frames < ELAN_MOC_ENROLL_TIMES) + else if (self->num_frames < self->max_moc_enroll_time) fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER); else fpi_ssm_mark_failed (self->task_ssm, error); @@ -442,7 +444,7 @@ elan_enroll_run_state (FpiSsm *ssm, FpDevice *dev) case MOC_ENROLL_WAIT_FINGER: cmd_buf = elanmoc_compose_cmd (&elanmoc_enroll_cmd); cmd_buf[3] = self->curr_enrolled; - cmd_buf[4] = ELAN_MOC_ENROLL_TIMES; + cmd_buf[4] = self->max_moc_enroll_time; cmd_buf[5] = self->num_frames; elanmoc_get_cmd (dev, cmd_buf, elanmoc_enroll_cmd.cmd_len, elanmoc_enroll_cmd.resp_len, 1, elanmoc_enroll_cb); break; @@ -1069,6 +1071,7 @@ elanmoc_open (FpDevice *device) { FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); GError *error = NULL; + gint productid = 0; if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) goto error; @@ -1076,6 +1079,24 @@ elanmoc_open (FpDevice *device) if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) goto error; + productid = g_usb_device_get_pid (fpi_device_get_usb_device (device)); + switch (productid) + { + case 0x0c8c: + self->max_moc_enroll_time = 11; + break; + + case 0x0c8d: + self->max_moc_enroll_time = 17; + break; + + default: + self->max_moc_enroll_time = ELAN_MOC_ENROLL_TIMES; + break; + } + + fpi_device_set_nr_enroll_stages (device, self->max_moc_enroll_time); + self->task_ssm = fpi_ssm_new (FP_DEVICE (self), dev_init_handler, DEV_INIT_STATES); fpi_ssm_start (self->task_ssm, task_ssm_init_done); return; diff --git a/libfprint/drivers/elanmoc/elanmoc.h b/libfprint/drivers/elanmoc/elanmoc.h index 312a4b42..a948d401 100644 --- a/libfprint/drivers/elanmoc/elanmoc.h +++ b/libfprint/drivers/elanmoc/elanmoc.h @@ -188,6 +188,7 @@ struct _FpiDeviceElanmoc unsigned char y_trace; int num_frames; int curr_enrolled; + int max_moc_enroll_time; int cancel_result; int cmd_retry_cnt; int list_index; From 9ca1564e2de953d8e2f8a489f4ae4f53b84b5254 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:20:17 +0200 Subject: [PATCH 33/86] hwdb: Add Lenovo ThinkPad E15 fingerprint reader To the unsupported list. --- data/autosuspend.hwdb | 1 + libfprint/fprint-list-udev-hwdb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index d755744e..4d9e2c46 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -337,6 +337,7 @@ usb:v27C6p538C* usb:v27C6p538D* usb:v27C6p5395* usb:v27C6p5503* +usb:v27C6p550A* usb:v27C6p5584* usb:v27C6p55A2* usb:v27C6p55A4* diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index 16b6d18f..3322cea6 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -103,6 +103,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x538d }, { .vid = 0x27c6, .pid = 0x5395 }, { .vid = 0x27c6, .pid = 0x5503 }, + { .vid = 0x27c6, .pid = 0x550a }, { .vid = 0x27c6, .pid = 0x5584 }, { .vid = 0x27c6, .pid = 0x55a2 }, { .vid = 0x27c6, .pid = 0x55a4 }, From ac3b0d07ba69c28adf24eb20a0c6e0640e232da8 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:21:10 +0200 Subject: [PATCH 34/86] hwdb: Add FT9201Fingerprint reader To the unsupported list. --- data/autosuspend.hwdb | 1 + libfprint/fprint-list-udev-hwdb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 4d9e2c46..f5884d16 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -345,6 +345,7 @@ usb:v27C6p55B4* usb:v27C6p5740* usb:v27C6p5E0A* usb:v2808p9338* +usb:v2808p93A9* usb:v298Dp2020* usb:v298Dp2033* usb:v3538p0930* diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index 3322cea6..e7f85c55 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -111,6 +111,7 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x5740 }, { .vid = 0x27c6, .pid = 0x5e0a }, { .vid = 0x2808, .pid = 0x9338 }, + { .vid = 0x2808, .pid = 0x93a9 }, { .vid = 0x298d, .pid = 0x2020 }, { .vid = 0x298d, .pid = 0x2033 }, { .vid = 0x3538, .pid = 0x0930 }, From c3e88f6e46c3cc4327be411861f264d16b655bc7 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 16:08:43 +0200 Subject: [PATCH 35/86] context: Fix race when shutting down context Fix possible race which would happen when freeing the devices array before cancelling the initialisation: (/builds/libfprint/libfprint/_build/tests/test-fp-context:1449): GLib-CRITICAL **: 14:00:19.640: g_ptr_array_add: assertion 'rarray' failed --- libfprint/fp-context.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 42607dcb..34fcdda8 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -291,11 +291,10 @@ fp_context_finalize (GObject *object) FpContext *self = (FpContext *) object; FpContextPrivate *priv = fp_context_get_instance_private (self); - g_clear_pointer (&priv->devices, g_ptr_array_unref); - g_cancellable_cancel (priv->cancellable); g_clear_object (&priv->cancellable); g_clear_pointer (&priv->drivers, g_array_unref); + g_clear_pointer (&priv->devices, g_ptr_array_unref); g_slist_free_full (g_steal_pointer (&priv->sources), (GDestroyNotify) g_source_destroy); From e782de374792a3e23bf16a6fa20b1259d0f2981d Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:31:13 +0200 Subject: [PATCH 36/86] tests: Fix umockdev version detection Traceback (most recent call last): File "/builds/libfprint/libfprint/tests/umockdev-test.py", line 17, in version = tuple(int(_) for _ in umockdev_version.split(b'.')) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/builds/libfprint/libfprint/tests/umockdev-test.py", line 17, in version = tuple(int(_) for _ in umockdev_version.split(b'.')) ^^^^^^ ValueError: invalid literal for int() with base 10: b'g9049374\n' --- tests/umockdev-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py index b70f3ee2..66ab0f57 100755 --- a/tests/umockdev-test.py +++ b/tests/umockdev-test.py @@ -14,7 +14,7 @@ if len(sys.argv) != 2: # Check that umockdev is available try: umockdev_version = subprocess.check_output(['umockdev-run', '--version']) - version = tuple(int(_) for _ in umockdev_version.split(b'.')) + version = tuple(int(_) for _ in umockdev_version.split(b'.')[:3]) if version < (0, 13, 2): print('umockdev is too old for test to be reliable, expect random failures!') print('Please update umockdev to at least 0.13.2.') From 3b3fc573da9c734fd4a1071ecc5c6f762cd95ccc Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 16:47:18 +0200 Subject: [PATCH 37/86] test-generated-hwdb: Add more debug on error --- tests/test-generated-hwdb.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test-generated-hwdb.sh b/tests/test-generated-hwdb.sh index 87c08bbf..a35bcf8a 100755 --- a/tests/test-generated-hwdb.sh +++ b/tests/test-generated-hwdb.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash set -e -[ -x "$UDEV_HWDB" ] || exit 1 +if [ ! -x "$UDEV_HWDB" ]; then + echo "E: UDEV_HWDB (${UDEV_HWDB}) unset or not executable." + exit 1 +fi if [ "$UDEV_HWDB_CHECK_CONTENTS" == 1 ]; then generated_rules=$(mktemp "${TMPDIR:-/tmp}/libfprint-XXXXXX.hwdb") @@ -10,6 +13,10 @@ else fi $UDEV_HWDB > "$generated_rules" +if [ $? != 0 ]; then + echo "E: UDEV_HWDB (${UDEV_HWDB}) failed to run without error." + exit 1 +fi if [ "$UDEV_HWDB_CHECK_CONTENTS" != 1 ]; then exit 77 From 96013a03c5ac5e5da3794837ba430e8d709bb83f Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 17:02:24 +0200 Subject: [PATCH 38/86] test-generated-hwdb: Add missing test dep E: UDEV_HWDB (/run/build/libfprint/_flatpak_build/libfprint/fprint-list-udev-hwdb) unset or not executable. --- tests/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/meson.build b/tests/meson.build index 9b90a753..f01d8069 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -206,6 +206,7 @@ envs.set('UDEV_HWDB', udev_hwdb.full_path()) envs.set('UDEV_HWDB_CHECK_CONTENTS', default_drivers_are_enabled ? '1' : '0') test('udev-hwdb', find_program('test-generated-hwdb.sh'), + depends: udev_hwdb, env: envs) gdb = find_program('gdb', required: false) From b10baf02ea8b27a06198ce2ee6fc2b923fe20189 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:11:44 +0200 Subject: [PATCH 39/86] flatpak: Build Flatpak using GNOME 42 So the old meson in the 3.36 runtime doesn't choke on: tests/meson.build:46:7: ERROR: Unknown method "project_source_root" in object. --- .gitlab-ci.yml | 3 ++- demo/org.freedesktop.libfprint.Demo.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 27d71d10..04121464 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -136,7 +136,8 @@ test_unsupported_list: flatpak: stage: flatpak extends: .flatpak - image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36 + # From https://gitlab.gnome.org/GNOME/gnome-runtime-images/container_registry + image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:42 variables: MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json" FLATPAK_MODULE: "libfprint" diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index b6ab165d..9fc6dbe8 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -1,7 +1,7 @@ { "app-id": "org.freedesktop.libfprint.Demo", "runtime": "org.gnome.Platform", - "runtime-version": "3.36", + "runtime-version": "42", "sdk": "org.gnome.Sdk", "command": "gtk-libfprint-test", "finish-args": [ From fc6403899ec774d909a028bbac99c8f044367563 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:58:05 +0200 Subject: [PATCH 40/86] flatpak: Only require X11 access on X11 --- demo/org.freedesktop.libfprint.Demo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index 9fc6dbe8..11d3b036 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -6,7 +6,7 @@ "command": "gtk-libfprint-test", "finish-args": [ /* X11 + XShm access */ - "--share=ipc", "--socket=x11", + "--share=ipc", "--socket=fallback-x11", /* Wayland access */ "--socket=wayland", /* OpenGL access */ From f74b3f7794268496773a3b85dc61c4bf0a08a575 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 15:58:21 +0200 Subject: [PATCH 41/86] flatpak: Update libusb module --- demo/org.freedesktop.libfprint.Demo.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index 11d3b036..4172a400 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -18,7 +18,7 @@ "modules": [ { "name": "libusb", - "config-opts": [ "--disable-static", "--disable-udev" ], + "config-opts": [ "--disable-static" ], "cleanup": [ "/lib/*.la", "/lib/pkgconfig", @@ -26,13 +26,13 @@ ], "sources": [ { - "type": "archive", - "url": "https://github.com/libusb/libusb/archive/v1.0.22.tar.gz", - "sha256": "3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48" + "type": "archive", + "url": "https://github.com/libusb/libusb/releases/download/v1.0.26/libusb-1.0.26.tar.bz2", + "sha256": "12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5" } ], "post-install": [ - "install -Dm644 COPYING /app/share/licenses/libgusb/COPYING" + "install -Dm644 COPYING /app/share/licenses/libusb/COPYING" ] }, { From 3176eb8821815f7fc6b7417a7b08799720cc28f3 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 16:25:16 +0200 Subject: [PATCH 42/86] flatpak: Remove obsolete option See 256c7cea074de05d74f1aba9b4a5b4d8f315f1d1 --- demo/org.freedesktop.libfprint.Demo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index 4172a400..78a5fbef 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -62,7 +62,7 @@ { "name": "libfprint", "buildsystem": "meson", - "config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ], + "config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dgtk-examples=true", "-Ddrivers=all" ], "sources": [ { "type": "git", From 08a90e911e6b7aa8abd3663d3252c55c2a4e3363 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Aug 2022 16:53:02 +0200 Subject: [PATCH 43/86] flatpak: Remove obsolete libfprint branch --- demo/org.freedesktop.libfprint.Demo.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index 78a5fbef..8fd52f56 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -66,8 +66,7 @@ "sources": [ { "type": "git", - "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git", - "branch": "wip/benzea/v2" + "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git" } ] } From 3a8299158600e06b126e72238ebd9156c7f59fc4 Mon Sep 17 00:00:00 2001 From: mahaosen Date: Sat, 13 Aug 2022 17:28:37 +0800 Subject: [PATCH 44/86] goodixmoc: add PID 0x631C --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index f5884d16..f5578223 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -161,6 +161,7 @@ usb:v1C7Ap0603* usb:v27C6p5840* usb:v27C6p609C* usb:v27C6p60A2* +usb:v27C6p631C* usb:v27C6p6384* usb:v27C6p639C* usb:v27C6p63AC* diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 5dd57edd..6d288d86 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1360,6 +1360,7 @@ gx_fp_probe (FpDevice *device) case 0x6496: case 0x60A2: case 0x609C: + case 0x631C: case 0x6384: case 0x639C: case 0x63AC: @@ -1599,6 +1600,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x5840, }, { .vid = 0x27c6, .pid = 0x609C, }, { .vid = 0x27c6, .pid = 0x60A2, }, + { .vid = 0x27c6, .pid = 0x631C, }, { .vid = 0x27c6, .pid = 0x6384, }, { .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x63AC, }, From 89a0d5f958c66c078d5c616d91ae4b8190d44ba7 Mon Sep 17 00:00:00 2001 From: Aris Lin Date: Sun, 7 Aug 2022 09:29:51 +0800 Subject: [PATCH 45/86] synaptics: Add new PID 0x0104 --- data/autosuspend.hwdb | 1 + libfprint/drivers/synaptics/synaptics.c | 1 + 2 files changed, 2 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index f5578223..9dc9a380 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -197,6 +197,7 @@ usb:v06CBp0126* usb:v06CBp0129* usb:v06CBp0168* usb:v06CBp015F* +usb:v06CBp0104* ID_AUTOSUSPEND=1 ID_PERSIST=0 diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 3f35291c..f13b820b 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -44,6 +44,7 @@ static const FpIdEntry id_table[] = { { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x015F, }, + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0104, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; From 151551b52b006e541e62949706cf491561af9ea1 Mon Sep 17 00:00:00 2001 From: mahaosen Date: Fri, 26 Aug 2022 16:46:16 +0800 Subject: [PATCH 46/86] goodixmoc: add PID 0x634C --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 9dc9a380..11fb240d 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -162,6 +162,7 @@ usb:v27C6p5840* usb:v27C6p609C* usb:v27C6p60A2* usb:v27C6p631C* +usb:v27C6p634C* usb:v27C6p6384* usb:v27C6p639C* usb:v27C6p63AC* diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 6d288d86..2f7f140f 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1361,6 +1361,7 @@ gx_fp_probe (FpDevice *device) case 0x60A2: case 0x609C: case 0x631C: + case 0x634C: case 0x6384: case 0x639C: case 0x63AC: @@ -1601,6 +1602,7 @@ static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x609C, }, { .vid = 0x27c6, .pid = 0x60A2, }, { .vid = 0x27c6, .pid = 0x631C, }, + { .vid = 0x27c6, .pid = 0x634C, }, { .vid = 0x27c6, .pid = 0x6384, }, { .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x63AC, }, From 114097718a59734bfcb6440fe8fbc5cda6472e82 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 26 Aug 2022 11:48:32 +0200 Subject: [PATCH 47/86] build: Fix run_command() warning WARNING: You should add the boolean check kwarg to the run_command call. It currently defaults to false, but it will default to true in future releases of meson. See also: https://github.com/mesonbuild/meson/issues/9300 --- tests/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/meson.build b/tests/meson.build index f01d8069..11942fa6 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -66,7 +66,7 @@ if get_option('introspection') base_args = files(vdtest + '.py') suite = ['virtual-driver'] - r = run_command(unittest_inspector, files(vdtest + '.py')) + r = run_command(unittest_inspector, files(vdtest + '.py'), check: true) unit_tests = r.stdout().strip().split('\n') if r.returncode() == 0 and unit_tests.length() > 0 From beac7f934da7b7f6d40f59031059ad55da5cadef Mon Sep 17 00:00:00 2001 From: hermanlin Date: Fri, 26 Aug 2022 18:44:22 +0800 Subject: [PATCH 48/86] elanmoc: Fixed unreachable code ISSUE=503 Signed-off-by: hermanlin --- libfprint/drivers/elanmoc/elanmoc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 77e22f25..748a9fbe 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -1010,6 +1010,12 @@ elanmoc_get_status_cb (FpiDeviceElanmoc *self, } if (buffer_in[1] != 0x03 && self->cmd_retry_cnt != 0) + { + self->cmd_retry_cnt--; + cmd_buf = elanmoc_compose_cmd (&cal_status_cmd); + elanmoc_get_cmd (FP_DEVICE (self), cmd_buf, cal_status_cmd.cmd_len, cal_status_cmd.resp_len, 0, elanmoc_get_status_cb); + } + else { if(self->cmd_retry_cnt == 0) { @@ -1018,12 +1024,6 @@ elanmoc_get_status_cb (FpiDeviceElanmoc *self, "Sensor not ready")); return; } - self->cmd_retry_cnt--; - cmd_buf = elanmoc_compose_cmd (&cal_status_cmd); - elanmoc_get_cmd (FP_DEVICE (self), cmd_buf, cal_status_cmd.cmd_len, cal_status_cmd.resp_len, 0, elanmoc_get_status_cb); - } - else - { fpi_ssm_next_state (self->task_ssm); } } From c74a1ab6d1b9e6c45706232012da0991499cea78 Mon Sep 17 00:00:00 2001 From: "Paulo E. Castro" Date: Mon, 18 Jul 2022 19:32:23 +0100 Subject: [PATCH 49/86] goodixmoc: add PID 6094 --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 11fb240d..8378f30b 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -159,6 +159,7 @@ usb:v1C7Ap0603* # Supported by libfprint driver goodixmoc usb:v27C6p5840* +usb:v27C6p6094* usb:v27C6p609C* usb:v27C6p60A2* usb:v27C6p631C* diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 2f7f140f..2eeceecb 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1359,6 +1359,7 @@ gx_fp_probe (FpDevice *device) { case 0x6496: case 0x60A2: + case 0x6094: case 0x609C: case 0x631C: case 0x634C: @@ -1599,6 +1600,7 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x5840, }, + { .vid = 0x27c6, .pid = 0x6094, }, { .vid = 0x27c6, .pid = 0x609C, }, { .vid = 0x27c6, .pid = 0x60A2, }, { .vid = 0x27c6, .pid = 0x631C, }, From 2acd3ca571c18d381f4217d5853846d63b9d326a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 26 Sep 2022 23:43:26 +0200 Subject: [PATCH 50/86] ci: Rebuild the image in case deps changed --- .gitlab-ci.yml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04121464..2ae98e84 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,6 +15,7 @@ variables: LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" stages: + - image-build - check-source - build - test @@ -158,11 +159,12 @@ flatpak: allow_failure: true # CONTAINERS creation stage -container_fedora_build: +.container_fedora_build_base: extends: .fdo.container-build@fedora + stage: image-build only: variables: - - $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES" + - $CI_PIPELINE_SOURCE == "never" variables: GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image FDO_FORCE_REBUILD: 1 @@ -177,3 +179,26 @@ container_fedora_build: cd umockdev && \ meson _build --prefix=/usr && \ ninja -C _build && ninja -C _build install + +container_fedora_build_schedule: + extends: .container_fedora_build_base + only: + variables: + - $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES" + +container_fedora_build_manual: + extends: .container_fedora_build_base + only: + variables: + - $LIBFPRINT_CI_ACTION == "build-image" + +container_fedora_build_on_deps_changed: + extends: .container_fedora_build_base + only: + variables: + - $CI_PROJECT_NAMESPACE == "libfprint" + refs: + - branches + - merge_requests + changes: + - .gitlab-ci/libfprint-templates.yaml From 012d77ac4120c14c30189e1583a6351da4932348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 26 Sep 2022 23:54:36 +0200 Subject: [PATCH 51/86] libfprint-templates: Include exec commands --- .gitlab-ci.yml | 5 +---- .gitlab-ci/libfprint-templates.yaml | 6 ++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ae98e84..bb2e559b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -175,10 +175,7 @@ flatpak: libpcap-devel libudev-devel FDO_DISTRIBUTION_EXEC: | - git clone https://github.com/martinpitt/umockdev.git && \ - cd umockdev && \ - meson _build --prefix=/usr && \ - ninja -C _build && ninja -C _build install + $LIBFPRINT_EXEC container_fedora_build_schedule: extends: .container_fedora_build_base diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index ace3f7b4..7aa71d0d 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -27,3 +27,9 @@ valgrind clang-analyzer diffutils + + LIBFPRINT_EXEC: | + git clone https://github.com/martinpitt/umockdev.git && \ + cd umockdev && \ + meson _build --prefix=/usr && \ + ninja -C _build && ninja -C _build install From c512a47e8aed58172d0604d186a9ec5613cacb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 26 Sep 2022 23:30:52 +0200 Subject: [PATCH 52/86] ci: Install debuginfo packages for better valgrind debugging Related-to: https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/507 --- .gitlab-ci/libfprint-templates.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index 7aa71d0d..43edc245 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -1,6 +1,7 @@ .libfprint_common_variables: LIBFPRINT_DEPENDENCIES: doxygen + dnf-plugins-core flatpak-builder gcc gcc-c++ @@ -29,6 +30,11 @@ diffutils LIBFPRINT_EXEC: | + dnf debuginfo-install -y \ + glib2 \ + glibc \ + libgusb + git clone https://github.com/martinpitt/umockdev.git && \ cd umockdev && \ meson _build --prefix=/usr && \ From 34e8655a084d4f919b83ad459a1c1313674c72d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 00:35:30 +0200 Subject: [PATCH 53/86] ci: Use versioned image tags --- .gitlab-ci.yml | 5 +++-- .gitlab-ci/libfprint-image-variables.yaml | 2 ++ .gitlab-ci/libfprint-templates.yaml | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .gitlab-ci/libfprint-image-variables.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb2e559b..5a76327d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,5 @@ include: + - local: '.gitlab-ci/libfprint-image-variables.yaml' - local: '.gitlab-ci/libfprint-templates.yaml' - project: 'freedesktop/ci-templates' ref: master @@ -7,7 +8,7 @@ include: variables: extends: .libfprint_common_variables - FDO_DISTRIBUTION_TAG: latest + FDO_DISTRIBUTION_TAG: $LIBFPRINT_IMAGE_TAG FDO_DISTRIBUTION_VERSION: rawhide FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME" FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG" @@ -198,4 +199,4 @@ container_fedora_build_on_deps_changed: - branches - merge_requests changes: - - .gitlab-ci/libfprint-templates.yaml + - .gitlab-ci/libfprint-image-variables.yaml diff --git a/.gitlab-ci/libfprint-image-variables.yaml b/.gitlab-ci/libfprint-image-variables.yaml new file mode 100644 index 00000000..2090e6fa --- /dev/null +++ b/.gitlab-ci/libfprint-image-variables.yaml @@ -0,0 +1,2 @@ +variables: + LIBFPRINT_IMAGE_TAG: v1 diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index 43edc245..a4ef62ac 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -1,3 +1,6 @@ +# Bump image version on .gitlab-ci/libfprint-image-variables.yaml to trigger +# a rebuild on changes to this file + .libfprint_common_variables: LIBFPRINT_DEPENDENCIES: doxygen From 7ea2e557930dd4219bac6521b57bc80d0d732172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 01:38:26 +0200 Subject: [PATCH 54/86] ci: Check for uncrustify changes in a safer way --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5a76327d..8854628c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -124,7 +124,7 @@ test_indent: script: - scripts/uncrustify.sh - git diff - - "! git status -s | grep -q ." + - git diff-index --name-only --exit-code HEAD test_unsupported_list: stage: check-source From 06abc256a44fd4e69dd81c9dcc67c1de943b8b28 Mon Sep 17 00:00:00 2001 From: mbv06 Date: Mon, 26 Sep 2022 10:38:17 +0000 Subject: [PATCH 55/86] upek: add PID 0x2017 --- libfprint/drivers/upektc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c index 115e6b60..3f7b6a68 100644 --- a/libfprint/drivers/upektc.c +++ b/libfprint/drivers/upektc.c @@ -431,6 +431,7 @@ dev_deinit (FpImageDevice *dev) static const FpIdEntry id_table[] = { { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 }, + { .vid = 0x0483, .pid = 0x2017, .driver_data = UPEKTC_2015 }, { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 }, { .vid = 0, .pid = 0, .driver_data = 0 }, }; From 1e55a066dcfa96e8886977cd131a3a468655df56 Mon Sep 17 00:00:00 2001 From: mbv06 Date: Tue, 27 Sep 2022 08:59:49 +0000 Subject: [PATCH 56/86] Update autosuspend.hwdb --- data/autosuspend.hwdb | 1 + 1 file changed, 1 insertion(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 8378f30b..6680d0aa 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -212,6 +212,7 @@ usb:v147Ep1001* # Supported by libfprint driver upektc usb:v0483p2015* +usb:v0483p2017* usb:v147Ep3001* ID_AUTOSUSPEND=1 ID_PERSIST=0 From c429052e5ea5e359280d2388c06ae3e79366541e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 12:52:38 +0200 Subject: [PATCH 57/86] tests: Do not use deprecated declarations in virtual device tests --- tests/virtual-device.py | 10 ++++++---- tests/virtual-image.py | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/virtual-device.py b/tests/virtual-device.py index e15b4327..ed18611e 100644 --- a/tests/virtual-device.py +++ b/tests/virtual-device.py @@ -235,10 +235,11 @@ class VirtualDeviceBase(unittest.TestCase): self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) self.assertEqual(self._enrolled.get_device_stored(), - self.dev.has_storage()) + bool(self.dev.get_features() & FPrint.DeviceFeature.STORAGE)) self.assertEqual(self._enrolled.props.driver, self.dev.get_driver()) self.assertEqual(self._enrolled.props.device_id, self.dev.get_device_id()) - self.assertEqual(self._enrolled.props.device_stored, self.dev.has_storage()) + self.assertEqual(self._enrolled.props.device_stored, + bool(self.dev.get_features() & FPrint.DeviceFeature.STORAGE)) self.assertEqual(self._enrolled.props.fpi_data.unpack(), nick) self.assertIsNone(self._enrolled.props.image) @@ -322,7 +323,8 @@ class VirtualDeviceBase(unittest.TestCase): else: self.assertFalse(match) - if isinstance(scan_nick, str) and not self.dev.has_storage(): + if (isinstance(scan_nick, str) and not + self.dev.get_features() & FPrint.DeviceFeature.STORAGE): self.assertEqual(self._verify_fp.props.fpi_data.get_string(), scan_nick) @@ -592,7 +594,7 @@ class VirtualDevice(VirtualDeviceBase): self.send_command('SCAN', 'another-id') verify_match, verify_fp = self.dev.verify_sync(enrolled) self.assertFalse(verify_match) - if self.dev.has_storage(): + if self.dev.get_features() & FPrint.DeviceFeature.STORAGE: self.assertIsNone(verify_fp) else: self.assertFalse(verify_fp.equal(enrolled)) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index e4a464eb..cd2764d2 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -234,7 +234,8 @@ class VirtualImage(unittest.TestCase): self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) self.assertEqual(self._enrolled.props.driver, self.dev.get_driver()) self.assertEqual(self._enrolled.props.device_id, self.dev.get_device_id()) - self.assertEqual(self._enrolled.props.device_stored, self.dev.has_storage()) + self.assertEqual(self._enrolled.props.device_stored, + bool(self.dev.get_features() & FPrint.DeviceFeature.STORAGE)) self.assertIsNone(self._enrolled.get_image()) return self._enrolled From 4d74838c50597e0f9e54d5d729b61e7a26075c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 12:53:02 +0200 Subject: [PATCH 58/86] ci: Generate Cobertura XML and use it to feed gitlab for MR integration gitlab has coverage integration in MRs, but we need a cobertura formatted XML files (each must be less than 10 MB) to show it, since meson generates it already via gcovr, we can just inform gitlab about it See https://docs.gitlab.com/ee/ci/testing/test_coverage_visualization.html --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8854628c..1e63c1af 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,6 +73,9 @@ test: artifacts: reports: junit: "_build/meson-logs/testlog.junit.xml" + coverage_report: + coverage_format: cobertura + path: _build/meson-logs/coverage.xml expose_as: 'Coverage Report' when: always paths: From ca481cce50ee27878759c03caa8fde76e632b1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 11:31:23 +0200 Subject: [PATCH 59/86] fprint-list-udev-hwdb: Update devices from wiki --- data/autosuspend.hwdb | 10 ++++++++++ libfprint/fprint-list-udev-hwdb.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 6680d0aa..4070cc66 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -274,7 +274,13 @@ usb:v04F3p0C00* usb:v04F3p0C4C* usb:v04F3p0C57* usb:v04F3p0C5E* +usb:v04F3p0C5A* +usb:v04F3p0C70* +usb:v04F3p0C72* usb:v04F3p2706* +usb:v04F3p3057* +usb:v04F3p3104* +usb:v04F3p310D* usb:v06CBp0081* usb:v06CBp0088* usb:v06CBp008A* @@ -329,12 +335,14 @@ usb:v1C7Ap0576* usb:v27C6p5042* usb:v27C6p5110* usb:v27C6p5117* +usb:v27C6p5120* usb:v27C6p5125* usb:v27C6p5201* usb:v27C6p521D* usb:v27C6p5301* usb:v27C6p530C* usb:v27C6p532D* +usb:v27C6p5335* usb:v27C6p533C* usb:v27C6p5381* usb:v27C6p5385* @@ -343,12 +351,14 @@ usb:v27C6p538D* usb:v27C6p5395* usb:v27C6p5503* usb:v27C6p550A* +usb:v27C6p550C* usb:v27C6p5584* usb:v27C6p55A2* usb:v27C6p55A4* usb:v27C6p55B4* usb:v27C6p5740* usb:v27C6p5E0A* +usb:v27C6p581A* usb:v2808p9338* usb:v2808p93A9* usb:v298Dp2020* diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index e7f85c55..cf1c4ecf 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -35,7 +35,13 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x04f3, .pid = 0x0c4c }, { .vid = 0x04f3, .pid = 0x0c57 }, { .vid = 0x04f3, .pid = 0x0c5e }, + { .vid = 0x04f3, .pid = 0x0c5a }, + { .vid = 0x04f3, .pid = 0x0c70 }, + { .vid = 0x04f3, .pid = 0x0c72 }, { .vid = 0x04f3, .pid = 0x2706 }, + { .vid = 0x04f3, .pid = 0x3057 }, + { .vid = 0x04f3, .pid = 0x3104 }, + { .vid = 0x04f3, .pid = 0x310d }, { .vid = 0x06cb, .pid = 0x0081 }, { .vid = 0x06cb, .pid = 0x0088 }, { .vid = 0x06cb, .pid = 0x008a }, @@ -90,12 +96,14 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x5042 }, { .vid = 0x27c6, .pid = 0x5110 }, { .vid = 0x27c6, .pid = 0x5117 }, + { .vid = 0x27c6, .pid = 0x5120 }, { .vid = 0x27c6, .pid = 0x5125 }, { .vid = 0x27c6, .pid = 0x5201 }, { .vid = 0x27c6, .pid = 0x521d }, { .vid = 0x27c6, .pid = 0x5301 }, { .vid = 0x27c6, .pid = 0x530c }, { .vid = 0x27c6, .pid = 0x532d }, + { .vid = 0x27c6, .pid = 0x5335 }, { .vid = 0x27c6, .pid = 0x533c }, { .vid = 0x27c6, .pid = 0x5381 }, { .vid = 0x27c6, .pid = 0x5385 }, @@ -104,12 +112,14 @@ static const FpIdEntry whitelist_id_table[] = { { .vid = 0x27c6, .pid = 0x5395 }, { .vid = 0x27c6, .pid = 0x5503 }, { .vid = 0x27c6, .pid = 0x550a }, + { .vid = 0x27c6, .pid = 0x550c }, { .vid = 0x27c6, .pid = 0x5584 }, { .vid = 0x27c6, .pid = 0x55a2 }, { .vid = 0x27c6, .pid = 0x55a4 }, { .vid = 0x27c6, .pid = 0x55b4 }, { .vid = 0x27c6, .pid = 0x5740 }, { .vid = 0x27c6, .pid = 0x5e0a }, + { .vid = 0x27c6, .pid = 0x581a }, { .vid = 0x2808, .pid = 0x9338 }, { .vid = 0x2808, .pid = 0x93a9 }, { .vid = 0x298d, .pid = 0x2020 }, From 70dc61d647b3dfb73893e8e67311bffb41c3abd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 14:05:53 +0200 Subject: [PATCH 60/86] libfprint: Add top-level sync-udev-hwdb target for updating DB --- libfprint/meson.build | 4 +++- tests/test-generated-hwdb.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libfprint/meson.build b/libfprint/meson.build index 25ed10f3..1a62a5f4 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -330,7 +330,7 @@ if install_udev_rules ) endif -custom_target('sync-udev-hwdb', +sync_udev_udb = custom_target('sync-udev-hwdb', depends: udev_hwdb_generator, output: 'sync-udev-hwdb', install: false, @@ -341,6 +341,8 @@ custom_target('sync-udev-hwdb', ] ) +alias_target('sync-udev-hwdb', sync_udev_udb) + supported_devices = executable('fprint-list-supported-devices', 'fprint-list-supported-devices.c', dependencies: libfprint_private_dep, diff --git a/tests/test-generated-hwdb.sh b/tests/test-generated-hwdb.sh index a35bcf8a..7e1af144 100755 --- a/tests/test-generated-hwdb.sh +++ b/tests/test-generated-hwdb.sh @@ -24,7 +24,7 @@ fi if ! diff -u "$MESON_SOURCE_ROOT/data/autosuspend.hwdb" "$generated_rules"; then echo "E: Autosuspend file needs to be re-generated!" - echo " ninja -C $MESON_BUILD_ROOT libfprint/sync-udev-hwdb" + echo " ninja -C $MESON_BUILD_ROOT sync-udev-hwdb" exit 1 fi From 4012a4fe6fe43da3f85fb564f0d01a08e5cfa3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 15 Jul 2022 22:51:11 +0200 Subject: [PATCH 61/86] fpi-device: Clarify identify prints gallery usage in drivers docs --- libfprint/fpi-device.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 36f8ccad..b5ccb4c7 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -622,7 +622,14 @@ fpi_device_get_verify_data (FpDevice *device, * @device: The #FpDevice * @prints: (out) (transfer none) (element-type FpPrint): The gallery of prints * - * Get data for identify. + * Get prints gallery for identification. + * + * The @prints array is always non-%NULL and may contain a list of #FpPrint's + * that the device should match against. + * + * Note that @prints can be an empty array, in such case the device is expected + * to report the scanned print matching the one in its internal storage, if any. + * */ void fpi_device_get_identify_data (FpDevice *device, @@ -2009,12 +2016,26 @@ fpi_device_verify_report (FpDevice *device, * fpi_device_identify_report: * @device: The #FpDevice * @match: (transfer none): The #FpPrint from the gallery that matched - * @print: (transfer floating): The scanned #FpPrint - * @error: A #GError if result is %FPI_MATCH_ERROR + * @print: (transfer floating): The scanned #FpPrint, set in the absence + * of an error. + * @error: A #GError of %FP_DEVICE_RETRY type if @match and @print are unset. * - * Report the result of a identify operation. Note that the passed @error must be - * a retry error with the %FP_DEVICE_RETRY domain. For all other error cases, - * the error should passed to fpi_device_identify_complete(). + * Report the results of an identify operation. + * + * In case of successful identification @match is expected to be set to a + * #FpPrint that matches one from the provided gallery, while @print + * represents the scanned print and will be different. + * + * If there are no errors, it's expected that the device always reports the + * recognized @print even if there is no @match with the provided gallery (that + * can be potentially empty). This is required for application logic further + * up in the stack, such as for enroll-duplicate checking. @print needs to be + * sufficiently filled to do a comparison. + * + * In case of error, both @match and @print are expected to be %NULL. + * Note that the passed @error must be a retry error from the %FP_DEVICE_RETRY + * domain. For all other error cases, the error should passed to + * fpi_device_identify_complete(). */ void fpi_device_identify_report (FpDevice *device, From 446cedbcfc5fbfd43ef0e73731e657833636f4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 12:22:53 +0200 Subject: [PATCH 62/86] fpi-compat: Add definition for g_memdup2 when not available or deprecated It's suggested to use g_memdup2 everywhere, but since we've a max-glib version set we'd get a "deprecation" warning. Avoid it this by re-defininig it through a macro in both cases. --- libfprint/fpi-compat.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libfprint/fpi-compat.h b/libfprint/fpi-compat.h index 5480eb52..6582fb5a 100644 --- a/libfprint/fpi-compat.h +++ b/libfprint/fpi-compat.h @@ -39,6 +39,17 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref); G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free); #endif +#if !GLIB_CHECK_VERSION (2, 68, 0) +#define g_memdup2(data, size) g_memdup ((data), (size)) +#else +#define g_memdup2(data, size) \ + (G_GNUC_EXTENSION ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_memdup2 ((data), (size)); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + })) +#endif + #if __GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 1) #define FP_GNUC_ACCESS(m, p, s) __attribute__((access (m, p, s))) #else From 171e65f73f1f0ebae3bbd2149b1dad824435222b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 12:26:33 +0200 Subject: [PATCH 63/86] libfprint: Use g_memdup2 everywhere It's just safer when available. --- libfprint/drivers/elan.c | 2 +- libfprint/drivers/elanmoc/elanmoc.c | 2 +- libfprint/drivers/uru4000.c | 2 +- libfprint/drivers/vfs301_proto.c | 2 +- libfprint/fp-image.c | 3 ++- libfprint/fpi-byte-reader.c | 2 +- libfprint/fpi-byte-reader.h | 3 ++- libfprint/fpi-byte-writer.c | 2 +- libfprint/fpi-print.c | 2 +- 9 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 51daac7d..1b5d1e70 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -357,7 +357,7 @@ elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev, if (transfer->endpoint & FPI_USB_ENDPOINT_IN) { /* just finished receiving */ - self->last_read = g_memdup (transfer->buffer, transfer->actual_length); + self->last_read = g_memdup2 (transfer->buffer, transfer->actual_length); elan_cmd_done (ssm); } else diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 748a9fbe..471189fd 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -509,7 +509,7 @@ create_print_from_response (FpiDeviceElanmoc *self, return NULL; } - userid = g_memdup (&buffer_in[5], userid_len); + userid = g_memdup2 (&buffer_in[5], userid_len); userid_safe = g_strndup ((const char *) &buffer_in[5], userid_len); print = fp_print_new (FP_DEVICE (self)); uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, userid, userid_len, 1); diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 138673c8..dbb62132 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -551,7 +551,7 @@ image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev, } else { - self->img_data = g_memdup (transfer->buffer, sizeof (struct uru4k_image)); + self->img_data = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image)); self->img_data_actual_length = transfer->actual_length; fpi_ssm_next_state (ssm); } diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c index 4431efd6..122a889a 100644 --- a/libfprint/drivers/vfs301_proto.c +++ b/libfprint/drivers/vfs301_proto.c @@ -432,7 +432,7 @@ img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int l usb_send (dev, data, len, NULL); \ } -#define RAW_DATA(x) g_memdup (x, sizeof (x)), sizeof (x) +#define RAW_DATA(x) g_memdup2 (x, sizeof (x)), sizeof (x) #define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe)) diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c index 51732c1b..f19c5dfd 100644 --- a/libfprint/fp-image.c +++ b/libfprint/fp-image.c @@ -20,6 +20,7 @@ #define FP_COMPONENT "image" +#include "fpi-compat.h" #include "fpi-image.h" #include "fpi-log.h" @@ -295,7 +296,7 @@ fp_image_detect_minutiae_thread_func (GTask *task, data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED); - lfsparms = g_memdup (&g_lfsparms_V2, sizeof (LFSPARMS)); + lfsparms = g_memdup2 (&g_lfsparms_V2, sizeof (LFSPARMS)); lfsparms->remove_perimeter_pts = data->flags & FPI_IMAGE_PARTIAL ? TRUE : FALSE; timer = g_timer_new (); diff --git a/libfprint/fpi-byte-reader.c b/libfprint/fpi-byte-reader.c index aecbe5bc..23bc5e7c 100644 --- a/libfprint/fpi-byte-reader.c +++ b/libfprint/fpi-byte-reader.c @@ -1181,7 +1181,7 @@ fpi_byte_reader_dup_string_utf##bits (FpiByteReader * reader, type ** str) \ *str = NULL; \ return FALSE; \ } \ - *str = g_memdup (reader->data + reader->byte, size); \ + *str = g_memdup2 (reader->data + reader->byte, size); \ reader->byte += size; \ return TRUE; \ } diff --git a/libfprint/fpi-byte-reader.h b/libfprint/fpi-byte-reader.h index 4a14ec8d..7a89a286 100644 --- a/libfprint/fpi-byte-reader.h +++ b/libfprint/fpi-byte-reader.h @@ -22,6 +22,7 @@ #pragma once #include +#include "fpi-compat.h" #include "fpi-byte-utils.h" G_BEGIN_DECLS @@ -360,7 +361,7 @@ static inline guint8 * fpi_byte_reader_dup_data_unchecked (FpiByteReader * reader, guint size) { gconstpointer data = fpi_byte_reader_get_data_unchecked (reader, size); - return (guint8 *) g_memdup (data, size); + return (guint8 *) g_memdup2 (data, size); } /* Unchecked variants that should not be used */ diff --git a/libfprint/fpi-byte-writer.c b/libfprint/fpi-byte-writer.c index 4ee67ff5..73e42cbc 100644 --- a/libfprint/fpi-byte-writer.c +++ b/libfprint/fpi-byte-writer.c @@ -211,7 +211,7 @@ fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer) data = (guint8 *) writer->parent.data; if (!writer->owned) - data = g_memdup (data, writer->parent.size); + data = g_memdup2 (data, writer->parent.size); writer->parent.data = NULL; fpi_byte_writer_reset (writer); diff --git a/libfprint/fpi-print.c b/libfprint/fpi-print.c index 16877b8b..00289b4e 100644 --- a/libfprint/fpi-print.c +++ b/libfprint/fpi-print.c @@ -50,7 +50,7 @@ fpi_print_add_print (FpPrint *print, FpPrint *add) g_return_if_fail (add->type == FPI_PRINT_NBIS); g_assert (add->prints->len == 1); - g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct))); + g_ptr_array_add (print->prints, g_memdup2 (add->prints->pdata[0], sizeof (struct xyt_struct))); } /** From 62f2f346556aedef4438309bfecc59414a45d5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 17:36:09 +0200 Subject: [PATCH 64/86] fpi-device: Fix a small leak when configuring the wakeup --- libfprint/fpi-device.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index b5ccb4c7..8f901007 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1720,7 +1720,7 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) g_autoptr(GString) ports = NULL; GUsbDevice *dev, *parent; const char *wakeup_command = enabled ? "enabled" : "disabled"; - guint8 bus, port; + guint8 bus; g_autofree gchar *sysfs_wakeup = NULL; g_autofree gchar *sysfs_persist = NULL; int res; @@ -1732,8 +1732,12 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) dev = priv->usb_device; while ((parent = g_usb_device_get_parent (dev))) { + g_autofree gchar *port_str = NULL; + guint8 port; + port = g_usb_device_get_port_number (dev); - g_string_prepend (ports, g_strdup_printf ("%d.", port)); + port_str = g_strdup_printf ("%d.", port); + g_string_prepend (ports, port_str); dev = parent; } g_string_set_size (ports, ports->len - 1); From 5d9fc8b3c83e9f48f16312832e52f37ee0e0b17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 18:17:59 +0200 Subject: [PATCH 65/86] fpi-device: Do not leak USB devices while iterating To compute the device ports we walked up through the devices using g_usb_device_get_parent(), but this is supposed to return a device with transfer full, so we need to unref it when done with it. To handle this nicely, use a mixture of autopointer's and g_set_object to ensure we're doing the right thing when passing the ownership around. --- libfprint/fpi-device.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 8f901007..e9eaa0a6 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1718,7 +1718,7 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) case FP_DEVICE_TYPE_USB: { g_autoptr(GString) ports = NULL; - GUsbDevice *dev, *parent; + g_autoptr(GUsbDevice) dev = NULL; const char *wakeup_command = enabled ? "enabled" : "disabled"; guint8 bus; g_autofree gchar *sysfs_wakeup = NULL; @@ -1729,16 +1729,20 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) bus = g_usb_device_get_bus (priv->usb_device); /* Walk up, skipping the root hub. */ - dev = priv->usb_device; - while ((parent = g_usb_device_get_parent (dev))) + g_set_object (&dev, priv->usb_device); + while (TRUE) { + g_autoptr(GUsbDevice) parent = g_usb_device_get_parent (dev); g_autofree gchar *port_str = NULL; guint8 port; + if (!parent) + break; + port = g_usb_device_get_port_number (dev); port_str = g_strdup_printf ("%d.", port); g_string_prepend (ports, port_str); - dev = parent; + g_set_object (&dev, parent); } g_string_set_size (ports, ports->len - 1); From d2a0eda56c88a484390694d6158d7557b3f55fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 28 Sep 2022 01:21:31 +0200 Subject: [PATCH 66/86] synaptics, goodix: Properly check for finger status during enroll progress It may contain other values, but for sure we finger must be neeeded --- tests/goodixmoc/custom.py | 2 +- tests/synaptics/custom.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 tests/goodixmoc/custom.py diff --git a/tests/goodixmoc/custom.py b/tests/goodixmoc/custom.py old mode 100755 new mode 100644 index 38fdd26c..73f90a53 --- a/tests/goodixmoc/custom.py +++ b/tests/goodixmoc/custom.py @@ -31,7 +31,7 @@ d.clear_storage_sync() template = FPrint.Print.new(d) def enroll_progress(*args): - assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED + assert d.get_finger_status() & FPrint.FingerStatusFlags.NEEDED print('enroll progress: ' + str(args)) def identify_done(dev, res): diff --git a/tests/synaptics/custom.py b/tests/synaptics/custom.py index 0a88ef80..5b4b1481 100755 --- a/tests/synaptics/custom.py +++ b/tests/synaptics/custom.py @@ -51,7 +51,7 @@ d.clear_storage_sync() template = FPrint.Print.new(d) def enroll_progress(*args): - #assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED + assert d.get_finger_status() & FPrint.FingerStatusFlags.NEEDED print('enroll progress: ' + str(args)) # List, enroll, list, verify, delete, list From be88884315c873469eb100bd9b665bb2458d3bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 28 Sep 2022 01:22:15 +0200 Subject: [PATCH 67/86] tests: Ensure python tests exit with error on every exception We ignored assertions happening on callbacks as they only raise exceptions that does not stop the execution. So ensure that this is happening in all the tests as synaptics was doing already --- tests/capture.py | 11 ++++++++--- tests/elanmoc/custom.py | 6 ++++++ tests/goodixmoc/custom.py | 6 ++++++ tests/virtual-device.py | 3 +++ tests/virtual-image.py | 3 +++ 5 files changed, 26 insertions(+), 3 deletions(-) mode change 100644 => 100755 tests/goodixmoc/custom.py diff --git a/tests/capture.py b/tests/capture.py index c25afbf4..d6573a81 100755 --- a/tests/capture.py +++ b/tests/capture.py @@ -1,10 +1,15 @@ #!/usr/bin/python3 -import gi -gi.require_version('FPrint', '2.0') -from gi.repository import FPrint, GLib import cairo import sys +import traceback +import gi + +gi.require_version('FPrint', '2.0') +from gi.repository import FPrint, GLib + +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) if len(sys.argv) != 2: print("Please specify exactly one argument, the output location for the capture image") diff --git a/tests/elanmoc/custom.py b/tests/elanmoc/custom.py index c64414cb..1a3b8b37 100755 --- a/tests/elanmoc/custom.py +++ b/tests/elanmoc/custom.py @@ -1,9 +1,15 @@ #!/usr/bin/python3 +import traceback +import sys import gi + gi.require_version('FPrint', '2.0') from gi.repository import FPrint, GLib +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) + ctx = GLib.main_context_default() c = FPrint.Context() diff --git a/tests/goodixmoc/custom.py b/tests/goodixmoc/custom.py old mode 100644 new mode 100755 index 73f90a53..aee43918 --- a/tests/goodixmoc/custom.py +++ b/tests/goodixmoc/custom.py @@ -1,9 +1,15 @@ #!/usr/bin/python3 +import traceback +import sys import gi + gi.require_version('FPrint', '2.0') from gi.repository import FPrint, GLib +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) + ctx = GLib.main_context_default() c = FPrint.Context() diff --git a/tests/virtual-device.py b/tests/virtual-device.py index ed18611e..4dc8e56e 100644 --- a/tests/virtual-device.py +++ b/tests/virtual-device.py @@ -22,6 +22,9 @@ except Exception as e: FPrint = None +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) + ctx = GLib.main_context_default() diff --git a/tests/virtual-image.py b/tests/virtual-image.py index cd2764d2..448c4bc1 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -21,6 +21,9 @@ except Exception as e: FPrint = None +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) + def load_image(img): png = cairo.ImageSurface.create_from_png(img) From b718f4d567c089d843c450b96de0bdca4dd26e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 28 Sep 2022 01:23:58 +0200 Subject: [PATCH 68/86] tests/meson: Avoid searching for programs multiple times --- tests/meson.build | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index 11942fa6..96db6260 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -57,12 +57,13 @@ if get_option('introspection') 'virtual-device', ] + python3 = find_program('python3') unittest_inspector = find_program('unittest_inspector.py') + umockdev_test = find_program('umockdev-test.py') foreach vdtest: virtual_devices_tests driver_name = '_'.join(vdtest.split('-')) if driver_name in drivers - python3 = find_program('python3') base_args = files(vdtest + '.py') suite = ['virtual-driver'] @@ -106,8 +107,11 @@ if get_option('introspection') if (driver_name in supported_drivers and gusb_dep.version().version_compare('>= 0.3.0')) test(driver_test, - find_program('umockdev-test.py'), - args: join_paths(meson.current_source_dir(), driver_test), + python3, + args: [ + umockdev_test.full_path(), + meson.current_source_dir() / driver_test, + ], env: driver_envs, suite: ['drivers'], timeout: 15, From 6395228bb8e1fbb30aeb32908f906159a62303b7 Mon Sep 17 00:00:00 2001 From: Lv Ying Date: Sat, 17 Sep 2022 13:59:11 +0800 Subject: [PATCH 69/86] goodixmoc: add PID 0x6014 Signed-off-by: Lv Ying --- data/autosuspend.hwdb | 1 + libfprint/drivers/goodixmoc/goodix.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 4070cc66..cd4fd4c0 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -159,6 +159,7 @@ usb:v1C7Ap0603* # Supported by libfprint driver goodixmoc usb:v27C6p5840* +usb:v27C6p6014* usb:v27C6p6094* usb:v27C6p609C* usb:v27C6p60A2* diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 2eeceecb..48dafe10 100644 --- a/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c @@ -1359,6 +1359,7 @@ gx_fp_probe (FpDevice *device) { case 0x6496: case 0x60A2: + case 0x6014: case 0x6094: case 0x609C: case 0x631C: @@ -1600,6 +1601,7 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) static const FpIdEntry id_table[] = { { .vid = 0x27c6, .pid = 0x5840, }, + { .vid = 0x27c6, .pid = 0x6014, }, { .vid = 0x27c6, .pid = 0x6094, }, { .vid = 0x27c6, .pid = 0x609C, }, { .vid = 0x27c6, .pid = 0x60A2, }, From 1d24037f14b954ba1a7887a7fe3c71f704f243d3 Mon Sep 17 00:00:00 2001 From: ElectronicsArchiver Date: Sat, 12 Mar 2022 06:46:53 -0500 Subject: [PATCH 70/86] README: Improved formatting --- README.md | 108 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 7f59b4e8..2e524034 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,86 @@ -# libfprint -libfprint is part of the fprint project: -https://fprint.freedesktop.org/ + +

+ +# LibFPrint + +*LibFPrint is part of the **[FPrint][Website]** project.* + +
+ +[![Button Website]][Website] +[![Button Documentation]][Documentation] + +[![Button Supported]][Supported] +[![Button Unsupported]][Unsupported] + +[![Button Contribute]][Contribute] +[![Button Contributors]][Contributors] + +
## History -libfprint was originally developed as part of an academic project at the -University of Manchester with the aim of hiding differences between different -consumer fingerprint scanners and providing a single uniform API to application -developers. The ultimate goal of the fprint project is to make fingerprint -scanners widely and easily usable under common Linux environments. +**LibFPrint** was originally developed as part of an +academic project at the **[University Of Manchester]**. -The academic university project runs off a codebase maintained separately -from this one, although I try to keep them as similar as possible (I'm not -hiding anything in the academic branch, it's just the open source release -contains some commits excluded from the academic project). +It aimed to hide the differences between consumer +fingerprint scanners and provide a single uniform +API to application developers. + +## Goal + +The ultimate goal of the **FPrint** project is to make +fingerprint scanners widely and easily usable under +common Linux environments. ## License -THE UNIVERSITY OF MANCHESTER DOES NOT ENDORSE THIS THIS SOFTWARE RELEASE AND -IS IN NO WAY RESPONSIBLE FOR THE CODE CONTAINED WITHIN, OR ANY DAMAGES CAUSED -BY USING OR DISTRIBUTING THE SOFTWARE. Development does not happen on -university computers and the project is not hosted at the university either. +`Section 6` of the license states that for compiled works that use +this library, such works must include **LibFPrint** copyright notices +alongside the copyright notices for the other parts of the work. -For more information on libfprint, supported devices, API documentation, etc., -see the homepage: -https://fprint.freedesktop.org/ +**LibFPrint** includes code from **NIST's** **[NBIS]** software distribution. -libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file -for the license text. +We include **Bozorth3** from the **[US Export Controlled]** +distribution, which we have determined to be fine +being shipped in an open source project. -Section 6 of the license states that for compiled works that use this -library, such works must include libfprint copyright notices alongside the -copyright notices for the other parts of the work. We have attempted to -make this process slightly easier for you by grouping these all in one place: -the AUTHORS file. +
-libfprint includes code from NIST's NBIS software distribution: -http://fingerprint.nist.gov/NBIS/index.html -We include bozorth3 from the US export controlled distribution. We have -determined that it is fine to ship bozorth3 in an open source project, -see https://fprint.freedesktop.org/us-export-control.html +
-## Historical links +[![Badge License]][License] -Older versions of libfprint are available at: -https://sourceforge.net/projects/fprint/files/ +
-Historical mailing-list archives: -http://www.reactivated.net/fprint_list_archives/ -Historical website: -http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/ + + +[Documentation]: https://fprint.freedesktop.org/libfprint-dev/ +[Contributors]: https://gitlab.freedesktop.org/libfprint/libfprint/-/graphs/master +[Unsupported]: https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices +[Supported]: https://fprint.freedesktop.org/supported-devices.html +[Website]: https://fprint.freedesktop.org/ + +[Contribute]: ./HACKING.md +[License]: ./COPYING + +[University Of Manchester]: https://www.manchester.ac.uk/ +[US Export Controlled]: https://fprint.freedesktop.org/us-export-control.html +[NBIS]: http://fingerprint.nist.gov/NBIS/index.html + + + + +[Badge License]: https://img.shields.io/badge/License-LGPL2.1-015d93.svg?style=for-the-badge&labelColor=blue + + + + +[Button Documentation]: https://img.shields.io/badge/Documentation-04ACE6?style=for-the-badge&logoColor=white&logo=BookStack +[Button Contributors]: https://img.shields.io/badge/Contributors-FF4F8B?style=for-the-badge&logoColor=white&logo=ActiGraph +[Button Unsupported]: https://img.shields.io/badge/Unsupported_Devices-EF2D5E?style=for-the-badge&logoColor=white&logo=AdBlock +[Button Contribute]: https://img.shields.io/badge/Contribute-66459B?style=for-the-badge&logoColor=white&logo=Git +[Button Supported]: https://img.shields.io/badge/Supported_Devices-428813?style=for-the-badge&logoColor=white&logo=AdGuard +[Button Website]: https://img.shields.io/badge/Homepage-3B80AE?style=for-the-badge&logoColor=white&logo=freedesktopDotOrg From cca2b6a624a738e0334dfafee9426a594532c91c Mon Sep 17 00:00:00 2001 From: Haowei Lo Date: Mon, 25 Jul 2022 15:12:11 +0800 Subject: [PATCH 71/86] fpcmoc: Support FPC moc devices Supported PID: 0xFFE0/A305/D805/DA04/D205 --- data/autosuspend.hwdb | 9 + libfprint/drivers/fpcmoc/fpc.c | 1892 ++++++++++++++++++++++++++++++++ libfprint/drivers/fpcmoc/fpc.h | 221 ++++ libfprint/meson.build | 2 + meson.build | 1 + tests/fpcmoc/custom.pcapng | Bin 0 -> 25324 bytes tests/fpcmoc/custom.py | 86 ++ tests/fpcmoc/device | 234 ++++ tests/meson.build | 1 + 9 files changed, 2446 insertions(+) create mode 100644 libfprint/drivers/fpcmoc/fpc.c create mode 100644 libfprint/drivers/fpcmoc/fpc.h create mode 100644 tests/fpcmoc/custom.pcapng create mode 100755 tests/fpcmoc/custom.py create mode 100644 tests/fpcmoc/device diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index cd4fd4c0..d476f7e1 100644 --- a/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb @@ -157,6 +157,15 @@ usb:v1C7Ap0603* ID_AUTOSUSPEND=1 ID_PERSIST=0 +# Supported by libfprint driver fpcmoc +usb:v10A5pFFE0* +usb:v10A5pA305* +usb:v10A5pDA04* +usb:v10A5pD805* +usb:v10A5pD205* + ID_AUTOSUSPEND=1 + ID_PERSIST=0 + # Supported by libfprint driver goodixmoc usb:v27C6p5840* usb:v27C6p6014* diff --git a/libfprint/drivers/fpcmoc/fpc.c b/libfprint/drivers/fpcmoc/fpc.c new file mode 100644 index 00000000..b64cc36e --- /dev/null +++ b/libfprint/drivers/fpcmoc/fpc.c @@ -0,0 +1,1892 @@ +/* + * Copyright (c) 2022 Fingerprint Cards AB + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "drivers_api.h" +#include "fpc.h" + +#define FP_COMPONENT "fpcmoc" +#define MAX_ENROLL_SAMPLES (25) +#define CTRL_TIMEOUT (1000) +#define DATA_TIMEOUT (5000) + +/* Usb port setting */ +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_IN_MAX_BUF_SIZE (2048) + +struct _FpiDeviceFpcMoc +{ + FpDevice parent; + FpiSsm *task_ssm; + FpiSsm *cmd_ssm; + gboolean cmd_suspended; + gint enroll_stage; + gint immobile_stage; + gint max_enroll_stage; + gint max_immobile_stage; + gint max_stored_prints; + guint cmd_data_timeout; + guint8 *dbid; + gboolean do_cleanup; + GCancellable *interrupt_cancellable; +}; + +G_DEFINE_TYPE (FpiDeviceFpcMoc, fpi_device_fpcmoc, FP_TYPE_DEVICE); + +typedef void (*SynCmdMsgCallback) (FpiDeviceFpcMoc *self, + void *resp, + GError *error); + +typedef struct +{ + FpcCmdType cmdtype; + guint8 request; + guint16 value; + guint16 index; + guint8 *data; + gsize data_len; + SynCmdMsgCallback callback; +} CommandData; + +static const FpIdEntry id_table[] = { + { .vid = 0x10A5, .pid = 0xFFE0, }, + { .vid = 0x10A5, .pid = 0xA305, }, + { .vid = 0x10A5, .pid = 0xDA04, }, + { .vid = 0x10A5, .pid = 0xD805, }, + { .vid = 0x10A5, .pid = 0xD205, }, + /* terminating entry */ + { .vid = 0, .pid = 0, .driver_data = 0 }, +}; + +static void +fpc_suspend_resume_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error) +{ + int ssm_state = fpi_ssm_get_cur_state (transfer->ssm); + + fp_dbg ("%s current ssm state: %d", G_STRFUNC, ssm_state); + + if (ssm_state == FP_CMD_SUSPENDED) + { + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + + fpi_device_suspend_complete (device, error); + /* The resume handler continues to the next state! */ + } + else if (ssm_state == FP_CMD_RESUME) + { + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_jump_to_state (transfer->ssm, FP_CMD_GET_DATA); + + fpi_device_resume_complete (device, error); + } +} + +static void +fpc_cmd_receive_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData *data = user_data; + int ssm_state = 0; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && (self->cmd_suspended)) + { + g_error_free (error); + fpi_ssm_jump_to_state (transfer->ssm, FP_CMD_SUSPENDED); + return; + } + + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + + if (data == NULL) + { + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + + ssm_state = fpi_ssm_get_cur_state (transfer->ssm); + fp_dbg ("%s current ssm state: %d", G_STRFUNC, ssm_state); + + if (data->cmdtype == FPC_CMDTYPE_TO_DEVICE) + { + /* It should not receive any data. */ + if (data->callback) + data->callback (self, NULL, NULL); + + fpi_ssm_mark_completed (transfer->ssm); + return; + } + else if (data->cmdtype == FPC_CMDTYPE_TO_DEVICE_EVTDATA) + { + if (ssm_state == FP_CMD_SEND) + { + fpi_ssm_next_state (transfer->ssm); + return; + } + + if (ssm_state == FP_CMD_GET_DATA) + { + fpc_cmd_response_t evt_data = {0}; + fp_dbg ("%s recv evt data length: %ld", G_STRFUNC, transfer->actual_length); + if (transfer->actual_length == 0) + { + fp_err ("%s Expect data but actual_length = 0", G_STRFUNC); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + memcpy (&evt_data, transfer->buffer, transfer->actual_length); + + if (data->callback) + data->callback (self, (guint8 *) &evt_data, NULL); + + fpi_ssm_mark_completed (transfer->ssm); + return; + } + } + else if (data->cmdtype == FPC_CMDTYPE_FROM_DEVICE) + { + if (transfer->actual_length == 0) + { + fp_err ("%s Expect data but actual_length = 0", G_STRFUNC); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + if (data->callback) + data->callback (self, transfer->buffer, NULL); + + fpi_ssm_mark_completed (transfer->ssm); + return; + } + else + { + fp_err ("%s incorrect cmdtype (%x) ", G_STRFUNC, data->cmdtype); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + /* should not run here... */ + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); +} + +static void +fpc_send_ctrl_cmd (FpDevice *dev) +{ + FpiUsbTransfer *transfer = NULL; + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + CommandData *cmd_data = fpi_ssm_get_data (self->cmd_ssm); + FpcCmdType cmdtype = FPC_CMDTYPE_UNKNOWN; + + if (!cmd_data) + { + fp_err ("%s No cmd_data is set ", G_STRFUNC); + fpi_ssm_mark_failed (self->cmd_ssm, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + + cmdtype = cmd_data->cmdtype; + + if ((cmdtype != FPC_CMDTYPE_FROM_DEVICE) && cmd_data->data_len && + (cmd_data->data == NULL)) + { + fp_err ("%s data buffer is null but len is not! ", G_STRFUNC); + fpi_ssm_mark_failed (self->cmd_ssm, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + + if (cmdtype == FPC_CMDTYPE_UNKNOWN) + { + fp_err ("%s unknown cmd type ", G_STRFUNC); + fpi_ssm_mark_failed (self->cmd_ssm, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + } + + fp_dbg ("%s CMD: 0x%x, value: 0x%x, index: %x type: %d", G_STRFUNC, + cmd_data->request, cmd_data->value, cmd_data->index, cmdtype); + + transfer = fpi_usb_transfer_new (dev); + fpi_usb_transfer_fill_control (transfer, + ((cmdtype == FPC_CMDTYPE_FROM_DEVICE) ? + (G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST) : + (G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE)), + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + cmd_data->request, + cmd_data->value, + cmd_data->index, + cmd_data->data_len); + + transfer->ssm = self->cmd_ssm; + if (cmdtype != FPC_CMDTYPE_FROM_DEVICE && + cmd_data->data != NULL && + cmd_data->data_len != 0) + memcpy (transfer->buffer, cmd_data->data, cmd_data->data_len); + + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, + fpc_cmd_receive_cb, + fpi_ssm_get_data (transfer->ssm)); +} + +static void +fpc_cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + CommandData *data = fpi_ssm_get_data (ssm); + + /* Notify about the SSM failure from here instead. */ + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + if (data->callback) + data->callback (self, NULL, error); + } + + self->cmd_ssm = NULL; +} + +static void +fpc_cmd_run_state (FpiSsm *ssm, + FpDevice *dev) +{ + FpiUsbTransfer *transfer = NULL; + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + + switch (fpi_ssm_get_cur_state (ssm)) + { + case FP_CMD_SEND: + fpc_send_ctrl_cmd (dev); + break; + + case FP_CMD_GET_DATA: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); + fpi_usb_transfer_submit (transfer, + self->cmd_data_timeout, + self->interrupt_cancellable, + fpc_cmd_receive_cb, + fpi_ssm_get_data (ssm)); + break; + + case FP_CMD_SUSPENDED: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FPC_CMD_INDICATE_S_STATE, + FPC_HOST_MS_SX, + 0, + 0); + + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, + fpc_suspend_resume_cb, NULL); + break; + + case FP_CMD_RESUME: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FPC_CMD_INDICATE_S_STATE, + FPC_HOST_MS_S0, + 0, + 0); + + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, + fpc_suspend_resume_cb, NULL); + break; + } + +} + +static void +fpc_sensor_cmd (FpiDeviceFpcMoc *self, + gboolean wait_data_delay, + CommandData *cmd_data) +{ + CommandData *data = NULL; + + g_return_if_fail (cmd_data); + g_return_if_fail (cmd_data->cmdtype != FPC_CMDTYPE_UNKNOWN); + + data = g_memdup2 (cmd_data, sizeof (CommandData)); + + if (wait_data_delay) + { + self->cmd_data_timeout = 0; + g_set_object (&self->interrupt_cancellable, g_cancellable_new ()); + } + else + { + self->cmd_data_timeout = DATA_TIMEOUT; + g_clear_object (&self->interrupt_cancellable); + } + + self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), + fpc_cmd_run_state, + FP_CMD_NUM_STATES); + + fpi_ssm_set_data (self->cmd_ssm, data, g_free); + fpi_ssm_start (self->cmd_ssm, fpc_cmd_ssm_done); +} + +static void +fpc_dev_release_interface (FpiDeviceFpcMoc *self, + GError *error) +{ + g_autoptr(GError) release_error = NULL; + + /* Release usb interface */ + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), + 0, 0, &release_error); + /* Retain passed error if set, otherwise propagate error from release. */ + if (error) + { + fpi_device_close_complete (FP_DEVICE (self), error); + return; + } + + /* Notify close complete */ + fpi_device_close_complete (FP_DEVICE (self), release_error); +} + +static gboolean +check_data (void *data, GError **error) +{ + if (*error != NULL) + return FALSE; + + if (data == NULL) + { + g_propagate_error (error, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return FALSE; + } + + return TRUE; +} + +static void +fpc_evt_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + pfpc_cmd_response_t presp = NULL; + + if (!check_data (data, &error)) + { + fp_err ("%s error: %s", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + presp = (pfpc_cmd_response_t) data; + + switch (presp->evt_hdr.cmdid) + { + case FPC_EVT_FID_DATA: + fp_dbg ("%s Enum Fids: status = %d, NumFids = %d", G_STRFUNC, + presp->evt_enum_fids.status, presp->evt_enum_fids.num_ids); + if (presp->evt_enum_fids.status || (presp->evt_enum_fids.num_ids > FPC_TEMPLATES_MAX)) + { + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID, + "Get Fids failed")); + return; + } + break; + + case FPC_EVT_INIT_RESULT: + fp_dbg ("%s INIT: status=%d, Sensor = %d, HWID = 0x%04X, WxH = %d x %d", G_STRFUNC, + presp->evt_inited.hdr.status, presp->evt_inited.sensor, + presp->evt_inited.hw_id, presp->evt_inited.img_w, presp->evt_inited.img_h); + + fp_dbg ("%s INIT: FW version: %s", G_STRFUNC, (gchar *) presp->evt_inited.fw_version); + break; + + case FPC_EVT_FINGER_DWN: + fp_dbg ("%s Got finger down event", G_STRFUNC); + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_PRESENT, + FP_FINGER_STATUS_NONE); + break; + + case FPC_EVT_IMG: + fp_dbg ("%s Got capture event", G_STRFUNC); + fpi_device_report_finger_status_changes (FP_DEVICE (self), + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_PRESENT); + break; + + default: + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Unknown Evt (0x%x)!", presp->evt_hdr.cmdid)); + return; + } + + fpi_ssm_next_state (self->task_ssm); +} + +static void +fpc_do_abort_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + fp_dbg ("%s Do abort for reasons", G_STRFUNC); + fpi_ssm_next_state (self->task_ssm); +} + +static void +fpc_do_cleanup_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + fp_dbg ("%s Do cleanup for reasons", G_STRFUNC); + self->do_cleanup = FALSE; + fpi_ssm_next_state (self->task_ssm); +} + +static void +fpc_template_delete_cb (FpiDeviceFpcMoc *self, + void *resp, + GError *error) +{ + FpDevice *device = FP_DEVICE (self); + + fpi_device_delete_complete (device, error); +} + +static gboolean +parse_print_data (GVariant *data, + guint8 *finger, + const guint8 **user_id, + gsize *user_id_len) +{ + g_autoptr(GVariant) user_id_var = NULL; + + g_return_val_if_fail (data, FALSE); + g_return_val_if_fail (finger, FALSE); + g_return_val_if_fail (user_id, FALSE); + g_return_val_if_fail (user_id_len, FALSE); + + *user_id = NULL; + *user_id_len = 0; + *finger = FPC_SUBTYPE_NOINFORMATION; + + if (!g_variant_check_format_string (data, "(y@ay)", FALSE)) + return FALSE; + + g_variant_get (data, + "(y@ay)", + finger, + &user_id_var); + + *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); + + if (*user_id_len == 0 || *user_id_len > SECURITY_MAX_SID_SIZE) + return FALSE; + + if (*user_id_len <= 0 || *user_id[0] == '\0' || *user_id[0] == ' ') + return FALSE; + + if (*finger != FPC_SUBTYPE_RESERVED) + return FALSE; + + return TRUE; +} + +/****************************************************************************** + * + * fpc_template_xxx Function + * + *****************************************************************************/ +static FpPrint * +fpc_print_from_data (FpiDeviceFpcMoc *self, fpc_fid_data_t *fid_data) +{ + FpPrint *print = NULL; + GVariant *data; + GVariant *uid; + g_autofree gchar *userid = NULL; + + userid = g_strndup ((gchar *) fid_data->identity, fid_data->identity_size); + print = fp_print_new (FP_DEVICE (self)); + + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + fid_data->identity, + fid_data->identity_size, + 1); + + data = g_variant_new ("(y@ay)", + fid_data->subfactor, + uid); + + fpi_print_set_type (print, FPI_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); + g_object_set (print, "fpi-data", data, NULL); + g_object_set (print, "description", userid, NULL); + fpi_print_fill_from_user_id (print, userid); + + return print; +} + +static void +fpc_template_list_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + g_autoptr(GPtrArray) list_result = NULL; + FpDevice *device = FP_DEVICE (self); + pfpc_cmd_response_t presp = NULL; + + if (error) + { + fpi_device_list_complete (FP_DEVICE (self), NULL, error); + return; + } + + if (data == NULL) + { + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID, + "Data is null")); + return; + } + + presp = (pfpc_cmd_response_t) data; + if (presp->evt_hdr.cmdid != FPC_EVT_FID_DATA) + { + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID, + "Recv evt is incorrect: 0x%x", + presp->evt_hdr.cmdid)); + return; + } + + if (presp->evt_enum_fids.num_ids > FPC_TEMPLATES_MAX) + { + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_FULL, + "Database is full")); + return; + } + + list_result = g_ptr_array_new_with_free_func (g_object_unref); + + if (presp->evt_enum_fids.num_ids == 0) + { + fp_info ("Database is empty"); + fpi_device_list_complete (device, + g_steal_pointer (&list_result), + NULL); + return; + } + + for (int n = 0; n < presp->evt_enum_fids.num_ids; n++) + { + FpPrint *print = NULL; + fpc_fid_data_t *fid_data = &presp->evt_enum_fids.fid_data[n]; + + if ((fid_data->subfactor != FPC_SUBTYPE_RESERVED) && + (fid_data->identity_type != FPC_IDENTITY_TYPE_RESERVED)) + { + fp_info ("Incompatible template found (0x%x, 0x%x)", + fid_data->subfactor, fid_data->identity_type); + continue; + } + + print = fpc_print_from_data (self, fid_data); + + g_ptr_array_add (list_result, g_object_ref_sink (print)); + } + + fp_info ("Query templates complete!"); + fpi_device_list_complete (device, + g_steal_pointer (&list_result), + NULL); +} + +/****************************************************************************** + * + * fpc_enroll_xxxx Function + * + *****************************************************************************/ + +static void +fpc_enroll_create_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + FPC_BEGIN_ENROL *presp = NULL; + + if (!check_data (data, &error)) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + presp = (FPC_BEGIN_ENROL *) data; + if (presp->status != 0) + { + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "End Enroll failed: %d", + presp->status); + } + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + else + { + self->do_cleanup = TRUE; + fpi_ssm_next_state (self->task_ssm); + } +} + +static void +fpc_enroll_update_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + FPC_ENROL *presp = NULL; + + if (!check_data (data, &error)) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + presp = (FPC_ENROL *) data; + fp_dbg ("Enrol Update status: %d, remaining: %d", presp->status, presp->remaining); + switch (presp->status) + { + case FPC_ENROL_STATUS_FAILED_COULD_NOT_COMPLETE: + error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); + break; + + case FPC_ENROL_STATUS_FAILED_ALREADY_ENROLED: + error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE); + break; + + case FPC_ENROL_STATUS_COMPLETED: + self->enroll_stage++; + fpi_device_enroll_progress (FP_DEVICE (self), self->enroll_stage, NULL, NULL); + fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_COMPLETE); + return; + + case FPC_ENROL_STATUS_IMAGE_TOO_SIMILAR: + fp_dbg ("Sample overlapping ratio is too High"); + /* here should tips remove finger and try again */ + if (self->max_immobile_stage) + { + if (self->immobile_stage >= self->max_immobile_stage) + { + fp_dbg ("Skip similar handle due to customer enrollment %d(%d)", + self->immobile_stage, self->max_immobile_stage); + /* Skip too similar handle, treat as normal enroll progress. */ + fpi_ssm_jump_to_state (self->task_ssm, FPC_ENROL_STATUS_PROGRESS); + break; + } + self->immobile_stage++; + } + fpi_device_enroll_progress (FP_DEVICE (self), + self->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); + break; + + case FPC_ENROL_STATUS_PROGRESS: + self->enroll_stage++; + fpi_device_enroll_progress (FP_DEVICE (self), self->enroll_stage, NULL, NULL); + /* Used for customer enrollment scheme */ + if (self->enroll_stage >= (self->max_enroll_stage - self->max_immobile_stage)) + fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_COMPLETE); + break; + + case FPC_ENROL_STATUS_IMAGE_LOW_COVERAGE: + fpi_device_enroll_progress (FP_DEVICE (self), + self->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); + break; + + case FPC_ENROL_STATUS_IMAGE_LOW_QUALITY: + fpi_device_enroll_progress (FP_DEVICE (self), + self->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT)); + break; + + default: + fp_err ("%s Unknown result code: %d ", G_STRFUNC, presp->status); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Enroll failed: %d", + presp->status); + break; + } + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + else + { + fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); + } +} + +static void +fpc_enroll_complete_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + FPC_END_ENROL *presp = NULL; + + self->do_cleanup = FALSE; + + if (check_data (data, &error)) + { + presp = (FPC_END_ENROL *) data; + if (presp->status != 0) + { + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "End Enroll failed: %d", + presp->status); + } + else + { + fp_dbg ("Enrol End status: %d, fid: 0x%x", + presp->status, presp->fid); + } + } + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + else + { + fpi_ssm_next_state (self->task_ssm); + } +} + +static void +fpc_enroll_check_duplicate_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + FPC_IDENTIFY *presp = NULL; + + if (check_data (data, &error)) + { + presp = (FPC_IDENTIFY *) data; + if ((presp->status == 0) && (presp->subfactor == FPC_SUBTYPE_RESERVED) && + (presp->identity_type == FPC_IDENTITY_TYPE_RESERVED) && + (presp->identity_size <= SECURITY_MAX_SID_SIZE)) + { + fp_info ("%s Got a duplicated template", G_STRFUNC); + error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE); + } + } + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + else + { + fpi_ssm_next_state (self->task_ssm); + } + +} + +static void +fpc_enroll_bindid_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + fpi_ssm_next_state (self->task_ssm); +} + +static void +fpc_enroll_commit_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + gint32 *result = NULL; + + if (check_data (data, &error)) + { + result = (gint32 *) data; + if (*result != 0) + { + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_FULL, + "Save DB failed: %d", + *result); + } + } + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + else + { + fpi_ssm_mark_completed (self->task_ssm); + } +} + + +static void +fpc_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData cmd_data = {0}; + gsize recv_data_len = 0; + + switch (fpi_ssm_get_cur_state (ssm)) + { + case FP_ENROLL_ENUM: + { + FPC_FID_DATA pquery_data = {0}; + gsize query_data_len = 0; + guint32 wildcard_value = FPC_IDENTITY_WILDCARD; + query_data_len = sizeof (FPC_FID_DATA); + pquery_data.identity_type = FPC_IDENTITY_TYPE_WILDCARD; + pquery_data.reserved = 16; + pquery_data.identity_size = sizeof (wildcard_value); + pquery_data.subfactor = (guint32) FPC_SUBTYPE_ANY; + memcpy (&pquery_data.data[0], + &wildcard_value, pquery_data.identity_size); + + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_ENUM; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &pquery_data; + cmd_data.data_len = query_data_len; + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_CREATE: + { + recv_data_len = sizeof (FPC_BEGIN_ENROL); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_BEGIN_ENROL; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_enroll_create_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_CAPTURE: + { + guint32 capture_id = FPC_CAPTUREID_RESERVED; + fpi_device_report_finger_status_changes (device, + FP_FINGER_STATUS_NEEDED, + FP_FINGER_STATUS_NONE); + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_ARM; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &capture_id; + cmd_data.data_len = sizeof (guint32); + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, TRUE, &cmd_data); + } + break; + + case FP_ENROLL_GET_IMG: + { + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_GET_IMG; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = 0; + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_UPDATE: + { + recv_data_len = sizeof (FPC_ENROL); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_ENROL; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_enroll_update_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_COMPLETE: + { + recv_data_len = sizeof (FPC_END_ENROL); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_END_ENROL; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_enroll_complete_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_CHECK_DUPLICATE: + { + recv_data_len = sizeof (FPC_IDENTIFY); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_IDENTIFY; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_enroll_check_duplicate_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_BINDID: + { + FPC_FID_DATA data = {0}; + gsize data_len = 0; + FpPrint *print = NULL; + GVariant *fpi_data = NULL; + GVariant *uid = NULL; + guint finger = FPC_SUBTYPE_RESERVED; + g_autofree gchar *user_id = NULL; + gssize user_id_len; + g_autofree guint8 *payload = NULL; + + fpi_device_get_enroll_data (device, &print); + + user_id = fpi_print_generate_user_id (print); + + user_id_len = strlen (user_id); + user_id_len = MIN (SECURITY_MAX_SID_SIZE, user_id_len); + + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + user_id, + user_id_len, + 1); + fpi_data = g_variant_new ("(y@ay)", + finger, + uid); + + fpi_print_set_type (print, FPI_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); + g_object_set (print, "fpi-data", fpi_data, NULL); + g_object_set (print, "description", user_id, NULL); + + fp_dbg ("user_id: %s, finger: 0x%x", user_id, finger); + + data_len = sizeof (FPC_FID_DATA); + data.identity_type = FPC_IDENTITY_TYPE_RESERVED; + data.reserved = 16; + data.identity_size = user_id_len; + data.subfactor = (guint32) finger; + memcpy (&data.data[0], + user_id, user_id_len); + + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_BIND_IDENTITY; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &data; + cmd_data.data_len = data_len; + cmd_data.callback = fpc_enroll_bindid_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_COMMIT: + { + recv_data_len = sizeof (gint32); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_STORE_DB; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_enroll_commit_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_DICARD: + { + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_ABORT; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = 0; + cmd_data.callback = fpc_do_abort_cb; + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_ENROLL_CLEANUP: + { + if (self->do_cleanup == TRUE) + { + recv_data_len = sizeof (FPC_END_ENROL); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_END_ENROL; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_do_cleanup_cb; + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + else + { + fpi_ssm_next_state (self->task_ssm); + } + } + break; + } +} + +static void +fpc_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + FpPrint *print = NULL; + + fp_info ("Enrollment complete!"); + + if (fpi_ssm_get_error (ssm)) + error = fpi_ssm_get_error (ssm); + + if (error) + { + fpi_device_enroll_complete (dev, NULL, error); + self->task_ssm = NULL; + return; + } + + fpi_device_get_enroll_data (FP_DEVICE (self), &print); + fpi_device_enroll_complete (FP_DEVICE (self), g_object_ref (print), NULL); + self->task_ssm = NULL; +} + +/****************************************************************************** + * + * fpc_verify_xxx function + * + *****************************************************************************/ + +static void +fpc_verify_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + g_autoptr(GPtrArray) templates = NULL; + FpDevice *device = FP_DEVICE (self); + gboolean found = FALSE; + FpiDeviceAction current_action; + FPC_IDENTIFY *presp = NULL; + + if (!check_data (data, &error)) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + presp = (FPC_IDENTIFY *) data; + current_action = fpi_device_get_current_action (device); + + g_assert (current_action == FPI_DEVICE_ACTION_VERIFY || + current_action == FPI_DEVICE_ACTION_IDENTIFY); + + if ((presp->status == 0) && (presp->subfactor == FPC_SUBTYPE_RESERVED) && + (presp->identity_type == FPC_IDENTITY_TYPE_RESERVED) && + (presp->identity_size <= SECURITY_MAX_SID_SIZE)) + { + FpPrint *match = NULL; + FpPrint *print = NULL; + gint cnt = 0; + fpc_fid_data_t fid_data = {0}; + + fid_data.subfactor = presp->subfactor; + fid_data.identity_type = presp->identity_type; + fid_data.identity_size = presp->identity_size; + memcpy (fid_data.identity, &presp->data[0], + fid_data.identity_size); + + match = fpc_print_from_data (self, &fid_data); + + if (current_action == FPI_DEVICE_ACTION_VERIFY) + { + templates = g_ptr_array_sized_new (1); + fpi_device_get_verify_data (device, &print); + g_ptr_array_add (templates, print); + } + else + { + fpi_device_get_identify_data (device, &templates); + g_ptr_array_ref (templates); + } + + for (cnt = 0; cnt < templates->len; cnt++) + { + print = g_ptr_array_index (templates, cnt); + + if (fp_print_equal (print, match)) + { + found = TRUE; + break; + } + } + + if (found) + { + if (current_action == FPI_DEVICE_ACTION_VERIFY) + fpi_device_verify_report (device, FPI_MATCH_SUCCESS, match, error); + else + fpi_device_identify_report (device, print, match, error); + + fpi_ssm_mark_completed (self->task_ssm); + return; + } + } + + if (!found) + { + if (current_action == FPI_DEVICE_ACTION_VERIFY) + fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error); + else + fpi_device_identify_report (device, NULL, NULL, error); + } + + /* This is the last state for verify/identify */ + fpi_ssm_mark_completed (self->task_ssm); +} + +static void +fpc_verify_sm_run_state (FpiSsm *ssm, FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData cmd_data = {0}; + + switch (fpi_ssm_get_cur_state (ssm)) + { + case FP_VERIFY_CAPTURE: + { + guint32 capture_id = FPC_CAPTUREID_RESERVED; + fpi_device_report_finger_status_changes (device, + FP_FINGER_STATUS_NEEDED, + FP_FINGER_STATUS_NONE); + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_ARM; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &capture_id; + cmd_data.data_len = sizeof (guint32); + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, TRUE, &cmd_data); + } + break; + + case FP_VERIFY_GET_IMG: + { + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_GET_IMG; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = 0; + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_VERIFY_IDENTIFY: + { + gsize recv_data_len = sizeof (FPC_IDENTIFY); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_IDENTIFY; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_verify_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + + case FP_VERIFY_CANCEL: + { + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_ABORT; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = 0; + cmd_data.callback = fpc_do_abort_cb; + fpc_sensor_cmd (self, FALSE, &cmd_data); + + } + break; + } +} + +static void +fpc_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + + fp_info ("Verify_identify complete!"); + + if (fpi_ssm_get_error (ssm)) + error = fpi_ssm_get_error (ssm); + + if (error && error->domain == FP_DEVICE_RETRY) + { + if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) + fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error)); + else + fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error)); + } + + if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) + fpi_device_verify_complete (dev, error); + else + fpi_device_identify_complete (dev, error); + + self->task_ssm = NULL; +} + +/****************************************************************************** + * + * fpc_init_xxx function + * + *****************************************************************************/ +static void +fpc_clear_storage_cb (FpiDeviceFpcMoc *self, + void *resp, + GError *error) +{ + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + fpi_ssm_next_state (self->task_ssm); + +} + +static void +fpc_clear_sm_run_state (FpiSsm *ssm, FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData cmd_data = {0}; + FPC_DB_OP data = {0}; + gsize data_len = 0; + + switch (fpi_ssm_get_cur_state (ssm)) + { + case FP_CLEAR_DELETE_DB: + { + if (self->dbid) + { + data_len = sizeof (FPC_DB_OP); + data.database_id_size = FPC_DB_ID_LEN; + data.reserved = 8; + memcpy (&data.data[0], self->dbid, FPC_DB_ID_LEN); + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_DELETE_DB; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &data; + cmd_data.data_len = data_len; + cmd_data.callback = fpc_clear_storage_cb; + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + else + { + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, + "No DBID found")); + } + + } + break; + + case FP_CLEAR_CREATE_DB: + { + if (self->dbid) + { + data_len = sizeof (FPC_DB_OP); + data.database_id_size = FPC_DB_ID_LEN; + data.reserved = 8; + memcpy (&data.data[0], self->dbid, FPC_DB_ID_LEN); + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_LOAD_DB; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &data; + cmd_data.data_len = data_len; + cmd_data.callback = fpc_clear_storage_cb; + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + else + { + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, + "No DBID found")); + } + } + break; + } +} + +static void +fpc_clear_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + + fp_info ("Clear Storage complete!"); + + if (fpi_ssm_get_error (ssm)) + error = fpi_ssm_get_error (ssm); + + fpi_device_clear_storage_complete (dev, error); + self->task_ssm = NULL; +} + +/****************************************************************************** + * + * fpc_init_xxx function + * + *****************************************************************************/ + +static void +fpc_init_load_db_cb (FpiDeviceFpcMoc *self, + void *data, + GError *error) +{ + FPC_LOAD_DB *presp = NULL; + + if (error) + { + fp_err ("%s error: %s ", G_STRFUNC, error->message); + fpi_ssm_mark_failed (self->task_ssm, error); + return; + } + + if (data == NULL) + { + fpi_ssm_mark_failed (self->task_ssm, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + presp = (FPC_LOAD_DB *) data; + if (presp->status) + { + fp_err ("%s Load DB failed: %d - Expect to create a new one", G_STRFUNC, presp->status); + fpi_ssm_next_state (self->task_ssm); + return; + } + + g_clear_pointer (&self->dbid, g_free); + self->dbid = g_memdup2 (presp->data, FPC_DB_ID_LEN); + if (self->dbid == NULL) + { + fpi_ssm_mark_failed (self->task_ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + + fp_dbg ("%s got dbid size: %d", G_STRFUNC, presp->database_id_size); + fp_dbg ("%s dbid: 0x%02x%02x%02x%02x-%02x%02x-%02x%02x-" \ + "%02x%02x-%02x%02x%02x%02x%02x%02x", + G_STRFUNC, + presp->data[0], presp->data[1], + presp->data[2], presp->data[3], + presp->data[4], presp->data[5], + presp->data[6], presp->data[7], + presp->data[8], presp->data[9], + presp->data[10], presp->data[11], + presp->data[12], presp->data[13], + presp->data[14], presp->data[15]); + fpi_ssm_mark_completed (self->task_ssm); +} + +static void +fpc_init_sm_run_state (FpiSsm *ssm, FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + guint32 session_id = FPC_SESSIONID_RESERVED; + CommandData cmd_data = {0}; + + switch (fpi_ssm_get_cur_state (ssm)) + { + case FP_INIT: + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_INIT; + cmd_data.value = 0x1; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &session_id; + cmd_data.data_len = sizeof (session_id); + cmd_data.callback = fpc_evt_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + break; + + case FP_LOAD_DB: + { + gsize recv_data_len = sizeof (FPC_LOAD_DB); + cmd_data.cmdtype = FPC_CMDTYPE_FROM_DEVICE; + cmd_data.request = FPC_CMD_LOAD_DB; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = NULL; + cmd_data.data_len = recv_data_len; + cmd_data.callback = fpc_init_load_db_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + } + break; + } +} + +static void +fpc_init_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (dev); + + if (fpi_ssm_get_error (ssm)) + error = fpi_ssm_get_error (ssm); + + fpi_device_open_complete (dev, error); + self->task_ssm = NULL; +} + +/****************************************************************************** + * + * Interface Function + * + *****************************************************************************/ + +static void +fpc_dev_probe (FpDevice *device) +{ + GUsbDevice *usb_dev; + GError *error = NULL; + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + g_autofree gchar *product = NULL; + gint product_id = 0; + + fp_dbg ("%s enter --> ", G_STRFUNC); + + /* Claim usb interface */ + usb_dev = fpi_device_get_usb_device (device); + if (!g_usb_device_open (usb_dev, &error)) + { + fp_dbg ("%s g_usb_device_open failed %s", G_STRFUNC, error->message); + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + if (!g_usb_device_reset (usb_dev, &error)) + { + fp_dbg ("%s g_usb_device_reset failed %s", G_STRFUNC, error->message); + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error)) + { + fp_dbg ("%s g_usb_device_claim_interface failed %s", G_STRFUNC, error->message); + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + product = g_usb_device_get_string_descriptor (usb_dev, + g_usb_device_get_product_index (usb_dev), + &error); + if (product) + fp_dbg ("Device name: %s", product); + + if (error) + { + fp_dbg ("%s g_usb_device_get_string_descriptor failed %s", G_STRFUNC, error->message); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), + 0, 0, NULL); + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + product_id = g_usb_device_get_pid (usb_dev); + /* Reserved for customer enroll scheme */ + self->max_immobile_stage = 0; /* By default is not customer enrollment */ + switch (product_id) + { + case 0xFFE0: + case 0xA305: + case 0xD805: + case 0xDA04: + case 0xD205: + self->max_enroll_stage = MAX_ENROLL_SAMPLES; + break; + + default: + fp_warn ("Device %x is not supported", product_id); + self->max_enroll_stage = MAX_ENROLL_SAMPLES; + break; + } + fpi_device_set_nr_enroll_stages (device, self->max_enroll_stage); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), + 0, 0, NULL); + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, product, error); +} + +static void +fpc_dev_open (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + GError *error = NULL; + + fp_dbg ("%s enter -->", G_STRFUNC); + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) + { + fpi_device_open_complete (FP_DEVICE (self), error); + return; + } + + /* Claim usb interface */ + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) + { + fpi_device_open_complete (FP_DEVICE (self), error); + return; + } + + self->task_ssm = fpi_ssm_new (device, fpc_init_sm_run_state, + FP_INIT_NUM_STATES); + + fpi_ssm_start (self->task_ssm, fpc_init_ssm_done); +} + +static void +fpc_dev_close (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + g_clear_pointer (&self->dbid, g_free); + g_clear_object (&self->interrupt_cancellable); + fpc_dev_release_interface (self, NULL); +} + +static void +fpc_dev_verify_identify (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + self->task_ssm = fpi_ssm_new_full (device, fpc_verify_sm_run_state, + FP_VERIFY_NUM_STATES, + FP_VERIFY_CANCEL, + "verify_identify"); + + fpi_ssm_start (self->task_ssm, fpc_verify_ssm_done); +} + +static void +fpc_dev_enroll (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + + self->enroll_stage = 0; + self->immobile_stage = 0; + self->task_ssm = fpi_ssm_new_full (device, fpc_enroll_sm_run_state, + FP_ENROLL_NUM_STATES, + FP_ENROLL_DICARD, + "enroll"); + + fpi_ssm_start (self->task_ssm, fpc_enroll_ssm_done); +} + +static void +fpc_dev_template_list (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData cmd_data = {0}; + FPC_FID_DATA pquery_data = {0}; + gsize query_data_len = 0; + guint32 wildcard_value = FPC_IDENTITY_WILDCARD; + + fp_dbg ("%s enter -->", G_STRFUNC); + + query_data_len = sizeof (FPC_FID_DATA); + pquery_data.identity_type = FPC_IDENTITY_TYPE_WILDCARD; + pquery_data.reserved = 16; + pquery_data.identity_size = sizeof (wildcard_value); + pquery_data.subfactor = (guint32) FPC_SUBTYPE_ANY; + memcpy (&pquery_data.data[0], + &wildcard_value, pquery_data.identity_size); + + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE_EVTDATA; + cmd_data.request = FPC_CMD_ENUM; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &pquery_data; + cmd_data.data_len = query_data_len; + cmd_data.callback = fpc_template_list_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); +} + +static void +fpc_dev_suspend (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + FpiDeviceAction action = fpi_device_get_current_action (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + + if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY) + { + fpi_device_suspend_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); + return; + } + + g_assert (self->cmd_ssm); + g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == FP_CMD_GET_DATA); + self->cmd_suspended = TRUE; + g_cancellable_cancel (self->interrupt_cancellable); +} + +static void +fpc_dev_resume (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + FpiDeviceAction action = fpi_device_get_current_action (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + + if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY) + { + g_assert_not_reached (); + fpi_device_resume_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); + return; + } + + g_assert (self->cmd_ssm); + g_assert (self->cmd_suspended); + g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == FP_CMD_SUSPENDED); + self->cmd_suspended = FALSE; + g_set_object (&self->interrupt_cancellable, g_cancellable_new ()); + fpi_ssm_jump_to_state (self->cmd_ssm, FP_CMD_RESUME); +} + +static void +fpc_dev_cancel (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + g_cancellable_cancel (self->interrupt_cancellable); +} + +static void +fpc_dev_template_delete (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + CommandData cmd_data = {0}; + FpPrint *print = NULL; + + g_autoptr(GVariant) fpi_data = NULL; + FPC_FID_DATA data = {0}; + gsize data_len = 0; + guint8 finger = FPC_SUBTYPE_NOINFORMATION; + const guint8 *user_id; + gsize user_id_len = 0; + + fp_dbg ("%s enter -->", G_STRFUNC); + + fpi_device_get_delete_data (device, &print); + + g_object_get (print, "fpi-data", &fpi_data, NULL); + + if (!parse_print_data (fpi_data, &finger, &user_id, &user_id_len)) + { + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + data_len = sizeof (FPC_FID_DATA); + data.identity_type = FPC_IDENTITY_TYPE_RESERVED; + data.reserved = 16; + data.identity_size = user_id_len; + data.subfactor = (guint32) finger; + memcpy (&data.data[0], user_id, user_id_len); + cmd_data.cmdtype = FPC_CMDTYPE_TO_DEVICE; + cmd_data.request = FPC_CMD_DELETE_TEMPLATE; + cmd_data.value = 0x0; + cmd_data.index = 0x0; + cmd_data.data = (guint8 *) &data; + cmd_data.data_len = data_len; + cmd_data.callback = fpc_template_delete_cb; + + fpc_sensor_cmd (self, FALSE, &cmd_data); + fp_dbg ("%s exit <--", G_STRFUNC); +} + +static void +fpc_dev_clear_storage (FpDevice *device) +{ + FpiDeviceFpcMoc *self = FPI_DEVICE_FPCMOC (device); + + fp_dbg ("%s enter -->", G_STRFUNC); + self->task_ssm = fpi_ssm_new_full (device, fpc_clear_sm_run_state, + FP_CLEAR_NUM_STATES, + FP_CLEAR_NUM_STATES, + "Clear storage"); + + fpi_ssm_start (self->task_ssm, fpc_clear_ssm_done); +} + +static void +fpi_device_fpcmoc_init (FpiDeviceFpcMoc *self) +{ + fp_dbg ("%s enter -->", G_STRFUNC); + G_DEBUG_HERE (); +} + +static void +fpi_device_fpcmoc_class_init (FpiDeviceFpcMocClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + + dev_class->id = FP_COMPONENT; + dev_class->full_name = "FPC MOC Fingerprint Sensor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id_table = id_table; + dev_class->nr_enroll_stages = MAX_ENROLL_SAMPLES; + dev_class->temp_hot_seconds = -1; + + dev_class->open = fpc_dev_open; + dev_class->close = fpc_dev_close; + dev_class->probe = fpc_dev_probe; + dev_class->enroll = fpc_dev_enroll; + dev_class->delete = fpc_dev_template_delete; + dev_class->list = fpc_dev_template_list; + dev_class->verify = fpc_dev_verify_identify; + dev_class->identify = fpc_dev_verify_identify; + dev_class->suspend = fpc_dev_suspend; + dev_class->resume = fpc_dev_resume; + dev_class->clear_storage = fpc_dev_clear_storage; + dev_class->cancel = fpc_dev_cancel; + + fpi_device_class_auto_initialize_features (dev_class); + dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK; +} diff --git a/libfprint/drivers/fpcmoc/fpc.h b/libfprint/drivers/fpcmoc/fpc.h new file mode 100644 index 00000000..389c63ff --- /dev/null +++ b/libfprint/drivers/fpcmoc/fpc.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 Fingerprint Cards AB + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "fpi-device.h" +#include "fpi-ssm.h" + +#include +#include + +#define TEMPLATE_ID_SIZE (32) +#define MAX_FW_VERSION_STR_LEN (16) +#define FPC_CMD_INIT (0x01) +#define FPC_CMD_ARM (0x02) +#define FPC_CMD_ABORT (0x03) +#define FPC_CMD_INDICATE_S_STATE (0x08) +#define FPC_CMD_GET_IMG (0x09) +#define FPC_CMD_GET_KPI (0x0C) +#define FPC_CMD_LOAD_DB (0x60) +#define FPC_CMD_STORE_DB (0x61) +#define FPC_CMD_DELETE_DB (0x62) +#define FPC_CMD_DELETE_TEMPLATE (0x63) +#define FPC_CMD_BEGIN_ENROL (0x67) +#define FPC_CMD_ENROL (0x68) +#define FPC_CMD_END_ENROL (0x69) +#define FPC_CMD_BIND_IDENTITY (0x6A) +#define FPC_CMD_IDENTIFY (0x6B) +#define FPC_CMD_ENUM (0x70) +#define FPC_EVT_INIT_RESULT (0x02) +#define FPC_EVT_FINGER_DWN (0x06) +#define FPC_EVT_IMG (0x08) +#define FPC_EVT_FID_DATA (0x31) +#define FPC_DB_ID_LEN (16) +#define FPC_IDENTITY_TYPE_WILDCARD (0x1) +#define FPC_IDENTITY_TYPE_RESERVED (0x3) +#define FPC_IDENTITY_WILDCARD (0x25066282) +#define FPC_SUBTYPE_ANY (0xFF) +#define FPC_SUBTYPE_RESERVED (0xF5) +#define FPC_SUBTYPE_NOINFORMATION (0x00) +#define FPC_CAPTUREID_RESERVED (0x701100F) +#define FPC_SESSIONID_RESERVED (0x0077FF12) +#define FPC_TEMPLATES_MAX (10) +#define SECURITY_MAX_SID_SIZE (68) +#define FPC_HOST_MS_S0 (0x10) +#define FPC_HOST_MS_SX (0x11) + +G_DECLARE_FINAL_TYPE (FpiDeviceFpcMoc, fpi_device_fpcmoc, FPI, + DEVICE_FPCMOC, FpDevice); + +typedef struct _FPC_FID_DATA +{ + guint32 identity_type; + guint32 reserved; + guint32 identity_size; + guint32 subfactor; + guint8 data[SECURITY_MAX_SID_SIZE]; +} FPC_FID_DATA, *PFPC_FID_DATA; + +typedef struct _FPC_LOAD_DB +{ + gint32 status; + guint32 reserved; + guint32 database_id_size; + guint8 data[FPC_DB_ID_LEN]; +} FPC_LOAD_DB, *PFPC_LOAD_DB; + +typedef union _FPC_DELETE_DB +{ + guint32 reserved; + guint32 database_id_size; + guint8 data[FPC_DB_ID_LEN]; +} FPC_DB_OP, *PFPC_DB_OP; + +typedef struct _FPC_BEGIN_ENROL +{ + gint32 status; + guint32 reserved1; + guint32 reserved2; +} FPC_BEGIN_ENROL, *PFPC_BEGIN_ENROL; + +typedef struct _FPC_ENROL +{ + gint32 status; + guint32 remaining; +} FPC_ENROL, *PFPC_ENROL; + +typedef struct _FPC_END_ENROL +{ + gint32 status; + guint32 fid; +} FPC_END_ENROL, *PFPC_END_ENROL; + +typedef struct _FPC_IDENTIFY +{ + gint32 status; + guint32 identity_type; + guint32 identity_offset; + guint32 identity_size; + guint32 subfactor; + guint8 data[SECURITY_MAX_SID_SIZE]; +} FPC_IDENTIFY, *PFPC_IDENTIFY; + +typedef struct +{ + guint32 cmdid; + guint32 length; + guint32 status; +} evt_hdr_t; + +typedef struct +{ + evt_hdr_t hdr; + guint16 sensor; + guint16 hw_id; + guint16 img_w; + guint16 img_h; + guint8 fw_version[MAX_FW_VERSION_STR_LEN]; + guint16 fw_capabilities; +} evt_initiated_t; + +typedef struct +{ + guint8 subfactor; + guint32 identity_type; + guint32 identity_size; + guint8 identity[SECURITY_MAX_SID_SIZE]; +} __attribute__((packed)) fpc_fid_data_t; + +typedef struct +{ + evt_hdr_t hdr; + gint status; + guint32 num_ids; + fpc_fid_data_t fid_data[FPC_TEMPLATES_MAX]; +} __attribute__((packed)) evt_enum_fids_t; + +typedef struct _fp_cmd_response +{ + union + { + evt_hdr_t evt_hdr; + evt_initiated_t evt_inited; + evt_enum_fids_t evt_enum_fids; + }; +} fpc_cmd_response_t, *pfpc_cmd_response_t; + +enum { + FPC_ENROL_STATUS_COMPLETED = 0, + FPC_ENROL_STATUS_PROGRESS = 1, + FPC_ENROL_STATUS_FAILED_COULD_NOT_COMPLETE = 2, + FPC_ENROL_STATUS_FAILED_ALREADY_ENROLED = 3, + FPC_ENROL_STATUS_IMAGE_LOW_COVERAGE = 4, + FPC_ENROL_STATUS_IMAGE_TOO_SIMILAR = 5, + FPC_ENROL_STATUS_IMAGE_LOW_QUALITY = 6, +}; + +typedef enum { + FPC_CMDTYPE_UNKNOWN = 0, + FPC_CMDTYPE_TO_DEVICE, + FPC_CMDTYPE_TO_DEVICE_EVTDATA, + FPC_CMDTYPE_FROM_DEVICE, +} FpcCmdType; + +typedef enum { + FP_CMD_SEND = 0, + FP_CMD_GET_DATA, + FP_CMD_SUSPENDED, + FP_CMD_RESUME, + FP_CMD_NUM_STATES, +} FpCmdState; + +typedef enum { + FP_INIT = 0, + FP_LOAD_DB, + FP_INIT_NUM_STATES, +} FpInitState; + +typedef enum { + FP_ENROLL_ENUM = 0, + FP_ENROLL_CREATE, + FP_ENROLL_CAPTURE, + FP_ENROLL_GET_IMG, + FP_ENROLL_UPDATE, + FP_ENROLL_COMPLETE, + FP_ENROLL_CHECK_DUPLICATE, + FP_ENROLL_BINDID, + FP_ENROLL_COMMIT, + FP_ENROLL_DICARD, + FP_ENROLL_CLEANUP, + FP_ENROLL_NUM_STATES, +} FpEnrollState; + +typedef enum { + FP_VERIFY_CAPTURE = 0, + FP_VERIFY_GET_IMG, + FP_VERIFY_IDENTIFY, + FP_VERIFY_CANCEL, + FP_VERIFY_NUM_STATES, +} FpVerifyState; + +typedef enum { + FP_CLEAR_DELETE_DB = 0, + FP_CLEAR_CREATE_DB, + FP_CLEAR_NUM_STATES, +} FpClearState; diff --git a/libfprint/meson.build b/libfprint/meson.build index 1a62a5f4..d3c8b034 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -139,6 +139,8 @@ driver_sources = { [ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ], 'goodixmoc' : [ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ], + 'fpcmoc' : + [ 'drivers/fpcmoc/fpc.c' ], } helper_sources = { diff --git a/meson.build b/meson.build index 823728c7..e25a1736 100644 --- a/meson.build +++ b/meson.build @@ -125,6 +125,7 @@ default_drivers = [ 'upekts', 'goodixmoc', 'nb1010', + 'fpcmoc', # SPI 'elanspi', diff --git a/tests/fpcmoc/custom.pcapng b/tests/fpcmoc/custom.pcapng new file mode 100644 index 0000000000000000000000000000000000000000..57b6f7668cf327257d70a8fdeaf7a8a62b2056d0 GIT binary patch literal 25324 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 literal 0 HcmV?d00001 diff --git a/tests/fpcmoc/custom.py b/tests/fpcmoc/custom.py new file mode 100755 index 00000000..c99dbd03 --- /dev/null +++ b/tests/fpcmoc/custom.py @@ -0,0 +1,86 @@ +#!/usr/bin/python3 + +import gi +gi.require_version('FPrint', '2.0') +from gi.repository import FPrint, GLib + +ctx = GLib.main_context_default() + +c = FPrint.Context() +c.enumerate() +devices = c.get_devices() + +d = devices[0] +del devices + +assert d.get_driver() == "fpcmoc" +assert not d.has_feature(FPrint.DeviceFeature.CAPTURE) +assert d.has_feature(FPrint.DeviceFeature.IDENTIFY) +assert d.has_feature(FPrint.DeviceFeature.VERIFY) +assert d.has_feature(FPrint.DeviceFeature.DUPLICATES_CHECK) +assert d.has_feature(FPrint.DeviceFeature.STORAGE) +assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST) +assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE) +assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR) + +d.open_sync() + +print("Clear") +d.clear_storage_sync() +print("Clear done") + +template = FPrint.Print.new(d) + +def enroll_progress(*args): + assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED + print('enroll progress: ' + str(args)) + +def identify_done(dev, res): + global identified + identified = True + identify_match, identify_print = dev.identify_finish(res) + print('indentification_done: ', identify_match, identify_print) + assert identify_match.equal(identify_print) + +# List, enroll, list, verify, identify, delete +print("enrolling") +assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE +p = d.enroll_sync(template, None, enroll_progress, None) +assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE +print("enroll done") + +print("listing") +stored = d.list_prints_sync() +print("listing done") +assert len(stored) == 1 +assert stored[0].equal(p) +print("verifying") +assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE +verify_res, verify_print = d.verify_sync(p) +assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE +print("verify done") +del p +assert verify_res == True + +identified = False +deserialized_prints = [] +for p in stored: + deserialized_prints.append(FPrint.Print.deserialize(p.serialize())) + assert deserialized_prints[-1].equal(p) +del stored + +print('async identifying') +d.identify(deserialized_prints, callback=identify_done) +del deserialized_prints + +while not identified: + ctx.iteration(True) + +print("deleting") +d.delete_print_sync(p) +print("delete done") + +d.close_sync() + +del d +del c diff --git a/tests/fpcmoc/device b/tests/fpcmoc/device new file mode 100644 index 00000000..32194633 --- /dev/null +++ b/tests/fpcmoc/device @@ -0,0 +1,234 @@ +P: /devices/pci0000:00/0000:00:14.0/usb1/1-1 +N: bus/usb/001/019=1201000200000040A510E0FF10000102000109021900010104A0320904000001FFFFFF0507058102400000 +E: DEVNAME=/dev/bus/usb/001/019 +E: DEVTYPE=usb_device +E: DRIVER=usb +E: PRODUCT=10a5/ffe0/10 +E: TYPE=0/0/0 +E: BUSNUM=001 +E: DEVNUM=019 +E: MAJOR=189 +E: MINOR=18 +E: SUBSYSTEM=usb +E: ID_VENDOR=FPC +E: ID_VENDOR_ENC=FPC +E: ID_VENDOR_ID=10a5 +E: ID_MODEL=FPC_L:0001_FW:127010 +E: ID_MODEL_ENC=FPC\x20L:0001\x20FW:127010 +E: ID_MODEL_ID=ffe0 +E: ID_REVISION=0010 +E: ID_SERIAL=FPC_FPC_L:0001_FW:127010 +E: ID_BUS=usb +E: ID_USB_INTERFACES=:ffffff: +E: ID_PATH=pci-0000:00:14.0-usb-0:1 +E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1 +E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_1 +E: TAGS=:seat: +E: CURRENT_TAGS=:seat: +A: authorized=1\n +A: avoid_reset_quirk=0\n +A: bConfigurationValue=1\n +A: bDeviceClass=00\n +A: bDeviceProtocol=00\n +A: bDeviceSubClass=00\n +A: bMaxPacketSize0=64\n +A: bMaxPower=100mA\n +A: bNumConfigurations=1\n +A: bNumInterfaces= 1\n +A: bcdDevice=0010\n +A: bmAttributes=a0\n +A: busnum=1\n +A: configuration=FPC\n +H: descriptors=1201000200000040A510E0FF10000102000109021900010104A0320904000001FFFFFF0507058102400000 +A: dev=189:18\n +A: devnum=19\n +A: devpath=1\n +L: driver=../../../../../bus/usb/drivers/usb +L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d/device:1e +A: idProduct=ffe0\n +A: idVendor=10a5\n +A: ltm_capable=no\n +A: manufacturer=FPC\n +A: maxchild=0\n +L: port=../1-0:1.0/usb1-port1 +A: power/active_duration=27204308\n +A: power/async=enabled\n +A: power/autosuspend=2\n +A: power/autosuspend_delay_ms=2000\n +A: power/connected_duration=27204308\n +A: power/control=on\n +A: power/level=on\n +A: power/persist=1\n +A: power/runtime_active_kids=0\n +A: power/runtime_active_time=27204033\n +A: power/runtime_enabled=forbidden\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n +A: power/runtime_usage=1\n +A: power/wakeup=disabled\n +A: power/wakeup_abort_count=\n +A: power/wakeup_active=\n +A: power/wakeup_active_count=\n +A: power/wakeup_count=\n +A: power/wakeup_expire_count=\n +A: power/wakeup_last_time_ms=\n +A: power/wakeup_max_time_ms=\n +A: power/wakeup_total_time_ms=\n +A: product=FPC L:0001 FW:127010\n +A: quirks=0x0\n +A: removable=removable\n +A: rx_lanes=1\n +A: speed=12\n +A: tx_lanes=1\n +A: urbnum=31\n +A: version= 2.00\n + +P: /devices/pci0000:00/0000:00:14.0/usb1 +N: bus/usb/001/001=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C +E: DEVNAME=/dev/bus/usb/001/001 +E: DEVTYPE=usb_device +E: DRIVER=usb +E: PRODUCT=1d6b/2/513 +E: TYPE=9/0/1 +E: BUSNUM=001 +E: DEVNUM=001 +E: MAJOR=189 +E: MINOR=0 +E: SUBSYSTEM=usb +E: ID_VENDOR=Linux_5.13.0-52-generic_xhci-hcd +E: ID_VENDOR_ENC=Linux\x205.13.0-52-generic\x20xhci-hcd +E: ID_VENDOR_ID=1d6b +E: ID_MODEL=xHCI_Host_Controller +E: ID_MODEL_ENC=xHCI\x20Host\x20Controller +E: ID_MODEL_ID=0002 +E: ID_REVISION=0513 +E: ID_SERIAL=Linux_5.13.0-52-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 +E: ID_SERIAL_SHORT=0000:00:14.0 +E: ID_BUS=usb +E: ID_USB_INTERFACES=:090000: +E: ID_VENDOR_FROM_DATABASE=Linux Foundation +E: ID_AUTOSUSPEND=1 +E: ID_MODEL_FROM_DATABASE=2.0 root hub +E: ID_PATH=pci-0000:00:14.0 +E: ID_PATH_TAG=pci-0000_00_14_0 +E: ID_FOR_SEAT=usb-pci-0000_00_14_0 +E: TAGS=:seat: +E: CURRENT_TAGS=:seat: +A: authorized=1\n +A: authorized_default=1\n +A: avoid_reset_quirk=0\n +A: bConfigurationValue=1\n +A: bDeviceClass=09\n +A: bDeviceProtocol=01\n +A: bDeviceSubClass=00\n +A: bMaxPacketSize0=64\n +A: bMaxPower=0mA\n +A: bNumConfigurations=1\n +A: bNumInterfaces= 1\n +A: bcdDevice=0513\n +A: bmAttributes=e0\n +A: busnum=1\n +A: configuration= +H: descriptors=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C +A: dev=189:0\n +A: devnum=1\n +A: devpath=0\n +L: driver=../../../../bus/usb/drivers/usb +L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d +A: idProduct=0002\n +A: idVendor=1d6b\n +A: interface_authorized_default=1\n +A: ltm_capable=no\n +A: manufacturer=Linux 5.13.0-52-generic xhci-hcd\n +A: maxchild=12\n +A: power/active_duration=32728176\n +A: power/async=enabled\n +A: power/autosuspend=0\n +A: power/autosuspend_delay_ms=0\n +A: power/connected_duration=32728176\n +A: power/control=auto\n +A: power/level=auto\n +A: power/runtime_active_kids=2\n +A: power/runtime_active_time=32728177\n +A: power/runtime_enabled=enabled\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n +A: power/runtime_usage=0\n +A: power/wakeup=disabled\n +A: power/wakeup_abort_count=\n +A: power/wakeup_active=\n +A: power/wakeup_active_count=\n +A: power/wakeup_count=\n +A: power/wakeup_expire_count=\n +A: power/wakeup_last_time_ms=\n +A: power/wakeup_max_time_ms=\n +A: power/wakeup_total_time_ms=\n +A: product=xHCI Host Controller\n +A: quirks=0x0\n +A: removable=unknown\n +A: rx_lanes=1\n +A: serial=0000:00:14.0\n +A: speed=480\n +A: tx_lanes=1\n +A: urbnum=1353\n +A: version= 2.00\n + +P: /devices/pci0000:00/0000:00:14.0 +E: DRIVER=xhci_hcd +E: PCI_CLASS=C0330 +E: PCI_ID=8086:9D2F +E: PCI_SUBSYS_ID=103C:8079 +E: PCI_SLOT_NAME=0000:00:14.0 +E: MODALIAS=pci:v00008086d00009D2Fsv0000103Csd00008079bc0Csc03i30 +E: SUBSYSTEM=pci +E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller +E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller +E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI +E: ID_VENDOR_FROM_DATABASE=Intel Corporation +E: ID_AUTOSUSPEND=1 +E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (EliteBook 840 G3) +A: ari_enabled=0\n +A: broken_parity_status=0\n +A: class=0x0c0330\n +H: config=86802F9D060490022130030C00008000040022E10000000000000000000000000000000000000000000000003C1079800000000070000000000000000B010000FD01348088C60F8000000000000000005F6ECE0F000000000000000000000000306000000000000000000000000000000180C2C1080000000000000000000000050087000480E0FE0000000022000000090014F01000400100000000C10A080000080400001800008F40020000010400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B30F400800000000 +A: consistent_dma_mask_bits=64\n +A: d3cold_allowed=1\n +A: dbc=disabled\n +A: device=0x9d2f\n +A: dma_mask_bits=64\n +L: driver=../../../bus/pci/drivers/xhci_hcd +A: driver_override=(null)\n +A: enable=1\n +L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c +A: irq=122\n +A: local_cpulist=0-3\n +A: local_cpus=f\n +A: modalias=pci:v00008086d00009D2Fsv0000103Csd00008079bc0Csc03i30\n +A: msi_bus=1\n +A: msi_irqs/122=msi\n +A: numa_node=-1\n +A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 14 2112 14\nxHCI ring segments 34 44 4096 44\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\n +A: power/async=enabled\n +A: power/control=auto\n +A: power/runtime_active_kids=1\n +A: power/runtime_active_time=32728973\n +A: power/runtime_enabled=enabled\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n +A: power/runtime_usage=0\n +A: power/wakeup=enabled\n +A: power/wakeup_abort_count=0\n +A: power/wakeup_active=0\n +A: power/wakeup_active_count=0\n +A: power/wakeup_count=0\n +A: power/wakeup_expire_count=0\n +A: power/wakeup_last_time_ms=0\n +A: power/wakeup_max_time_ms=0\n +A: power/wakeup_total_time_ms=0\n +A: power_state=D0\n +A: resource=0x00000000e1220000 0x00000000e122ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n +A: revision=0x21\n +A: subsystem_device=0x8079\n +A: subsystem_vendor=0x103c\n +A: vendor=0x8086\n + diff --git a/tests/meson.build b/tests/meson.build index 96db6260..94d47100 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -39,6 +39,7 @@ drivers_tests = [ 'goodixmoc', 'nb1010', 'egis0570', + 'fpcmoc', ] if get_option('introspection') From 0b6a92150caa450e6cef40c21a5e8ba1b4be4b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 13 Oct 2022 04:26:22 +0200 Subject: [PATCH 72/86] tests/fpcmoc: Ensure python tests exit with error on every exception We ignored assertions happening on callbacks as they only raise exceptions that does not stop the execution. So ensure that this is happening in all the tests as synaptics was doing already Same as commit: be8888431 --- tests/fpcmoc/custom.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/fpcmoc/custom.py b/tests/fpcmoc/custom.py index c99dbd03..709ba93b 100755 --- a/tests/fpcmoc/custom.py +++ b/tests/fpcmoc/custom.py @@ -1,9 +1,15 @@ #!/usr/bin/python3 +import traceback +import sys import gi + gi.require_version('FPrint', '2.0') from gi.repository import FPrint, GLib +# Exit with error on any exception, included those happening in async callbacks +sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1)) + ctx = GLib.main_context_default() c = FPrint.Context() From 669e091b03e7cd1cce39650ba26c20aa8cba47e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:01:49 +0200 Subject: [PATCH 73/86] virtual-device: Use an autoptr to handle the new scan print We may not use this print, so let's use an autoptr to handle its life cycle to clean it up when not used. --- libfprint/drivers/virtual-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/virtual-device.c b/libfprint/drivers/virtual-device.c index d21d94ba..c75455ff 100644 --- a/libfprint/drivers/virtual-device.c +++ b/libfprint/drivers/virtual-device.c @@ -526,8 +526,8 @@ dev_verify (FpDevice *dev) if (scan_id) { + g_autoptr(FpPrint) new_scan = NULL; GVariant *data = NULL; - FpPrint *new_scan; FpPrint *print; gboolean success; @@ -556,7 +556,7 @@ dev_verify (FpDevice *dev) self->match_reported = TRUE; fpi_device_verify_report (dev, success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, - new_scan, + g_steal_pointer (&new_scan), NULL); } } From b04eed0aeaf6e3956f09d6d51bd333ee960cfbbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:03:04 +0200 Subject: [PATCH 74/86] test-device-fake: Consume the identify print if we're returning with error --- tests/test-device-fake.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c index 4c61ed37..321bfe5b 100644 --- a/tests/test-device-fake.c +++ b/tests/test-device-fake.c @@ -187,6 +187,7 @@ fpi_device_fake_identify (FpDevice *device) else { fpi_device_identify_complete (device, fake_dev->ret_error); + g_clear_object (&fake_dev->ret_print); } } From a86ab6c8544876b3c276cfc371632220b8e65484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:03:51 +0200 Subject: [PATCH 75/86] test-fpi-device: Cleanup the device ID / driver before overriding it Otherwise we'd leak the one that was initially set. --- tests/test-fpi-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index f1c42753..2b5a9dc1 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -1112,6 +1112,7 @@ test_driver_enroll_update_nbis_wrong_device (void) fake_dev = FPI_DEVICE_FAKE (device); template_print = make_fake_nbis_print (device); + g_clear_pointer (&template_print->device_id, g_free); template_print->device_id = g_strdup ("wrong_device"); fake_dev->ret_print = template_print; @@ -1138,6 +1139,7 @@ test_driver_enroll_update_nbis_wrong_driver (void) fake_dev = FPI_DEVICE_FAKE (device); template_print = make_fake_nbis_print (device); + g_clear_pointer (&template_print->driver, g_free); template_print->driver = g_strdup ("wrong_driver"); fake_dev->ret_print = template_print; From 4278668c8f10b7be6b347ac030da5bec9d444b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:23:08 +0200 Subject: [PATCH 76/86] egis0570: Cleanup the received image that is going to be resized It's just temporary for us as we're providing the resized one instead. --- libfprint/drivers/egis0570.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/egis0570.c b/libfprint/drivers/egis0570.c index 04901952..0ff607da 100644 --- a/libfprint/drivers/egis0570.c +++ b/libfprint/drivers/egis0570.c @@ -190,7 +190,7 @@ data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GErro { if (!self->stop && (self->strips_len > 0)) { - FpImage *img; + g_autoptr(FpImage) img = NULL; self->strips = g_slist_reverse (self->strips); fpi_do_movement_estimation (&assembling_ctx, self->strips); img = fpi_assemble_frames (&assembling_ctx, self->strips); @@ -199,7 +199,7 @@ data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GErro self->strips = NULL; self->strips_len = 0; FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE); - fpi_image_device_image_captured (img_self, resizeImage); + fpi_image_device_image_captured (img_self, g_steal_pointer (&resizeImage)); } fpi_image_device_report_finger_status (img_self, FALSE); From 684e3c460acbcfecdbeeeb45e70d3d4ef3d8daa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:24:00 +0200 Subject: [PATCH 77/86] uru4000: Shutdown NSS on device close We were allocating NSS during device opening but never closing it, causing many leaks. --- libfprint/drivers/uru4000.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index dbb62132..72f53f17 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -1413,6 +1413,9 @@ dev_deinit (FpImageDevice *dev) SECITEM_FreeItem (self->param, PR_TRUE); if (self->slot) PK11_FreeSlot (self->slot); + + NSS_Shutdown (); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), self->interface, 0, &error); g_clear_pointer (&self->rand, g_rand_free); From 0592c0e5ad66e97f2120686290ead66322caa60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:24:38 +0200 Subject: [PATCH 78/86] uru4000: Cleanup cancelled error before early return --- libfprint/drivers/uru4000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 72f53f17..047e64c8 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -317,6 +317,7 @@ irq_handler (FpiUsbTransfer *transfer, if (urudev->irqs_stopped_cb) urudev->irqs_stopped_cb (imgdev); urudev->irqs_stopped_cb = NULL; + g_clear_error (&error); return; } else if (error) From fd7d93e619e1a273e4a017e5ee2ae25001cef0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:30:31 +0200 Subject: [PATCH 79/86] fpi-device: Do not leak suspend/resume tasks We kept suspend/resume GTask's around but at the moment of completing them we didn't unref them, leading to leaks. --- libfprint/fpi-device.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index e9eaa0a6..ba750654 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1610,11 +1610,13 @@ update_attr (const char *attr, const char *value) static void complete_suspend_resume_task (FpDevice *device) { + g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); g_assert (priv->suspend_resume_task); + task = g_steal_pointer (&priv->suspend_resume_task); - g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE); + g_task_return_boolean (task, TRUE); } void @@ -1779,6 +1781,7 @@ fpi_device_configure_wakeup (FpDevice *device, gboolean enabled) static void fpi_device_suspend_completed (FpDevice *device) { + g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); /* We have an ongoing operation, allow the device to wake up the machine. */ @@ -1788,11 +1791,12 @@ fpi_device_suspend_completed (FpDevice *device) if (priv->critical_section) g_warning ("Driver was in a critical section at suspend time. It likely deadlocked!"); + task = g_steal_pointer (&priv->suspend_resume_task); + if (priv->suspend_error) - g_task_return_error (g_steal_pointer (&priv->suspend_resume_task), - g_steal_pointer (&priv->suspend_error)); + g_task_return_error (task, g_steal_pointer (&priv->suspend_error)); else - g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE); + g_task_return_boolean (task, TRUE); } /** @@ -1820,11 +1824,12 @@ fpi_device_suspend_complete (FpDevice *device, g_return_if_fail (priv->suspend_resume_task); g_return_if_fail (priv->suspend_error == NULL); - priv->suspend_error = error; + priv->suspend_error = g_steal_pointer (&error); priv->is_suspended = TRUE; /* If there is no error, we have no running task, return immediately. */ - if (error == NULL || !priv->current_task || g_task_get_completed (priv->current_task)) + if (!priv->suspend_error || !priv->current_task || + g_task_get_completed (priv->current_task)) { fpi_device_suspend_completed (device); return; @@ -1856,6 +1861,7 @@ void fpi_device_resume_complete (FpDevice *device, GError *error) { + g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_if_fail (FP_IS_DEVICE (device)); @@ -1864,10 +1870,12 @@ fpi_device_resume_complete (FpDevice *device, priv->is_suspended = FALSE; fpi_device_configure_wakeup (device, FALSE); + task = g_steal_pointer (&priv->suspend_resume_task); + if (error) - g_task_return_error (g_steal_pointer (&priv->suspend_resume_task), error); + g_task_return_error (task, error); else - g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE); + g_task_return_boolean (task, TRUE); } /** From 8716ddb07a49117b44871cedff3ad6965906bfba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 20:32:01 +0200 Subject: [PATCH 80/86] fp-print: Fix a typo in documentation --- libfprint/fp-print.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c index 8532b6cc..7bcb9d8d 100644 --- a/libfprint/fp-print.c +++ b/libfprint/fp-print.c @@ -339,7 +339,7 @@ fp_print_init (FpPrint *self) * create a new print, fill in the relevant metadata, and then start * enrollment. * - * Returns: (transfer floating): A newyl created #FpPrint + * Returns: (transfer floating): A newly created #FpPrint */ FpPrint * fp_print_new (FpDevice *device) From abd7c668337bfc5b5c5d0cede25fd5e36fd5a07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 23:27:53 +0200 Subject: [PATCH 81/86] fp-device: Do not setup current action before updating temperature At every action we update the device temperature, and this can potentially lead to a failure, if the temperature is too hot. However in such case we were failing a task that we had just stolen, causing an error, tasks never returning and the device was left in an undefined state. So, just return early in case temperature is too hot, as we don't really need to have the current task or action set at this point because there's no active action to cancel yet. This was causing random errors when running tests under valgrind --- libfprint/fp-device.c | 32 ++++++++++++++++---------------- tests/test-fpi-device.c | 5 +++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 0d79fae1..17178d19 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -1172,10 +1172,6 @@ fp_device_enroll (FpDevice *device, } } - priv->current_action = FPI_DEVICE_ACTION_ENROLL; - priv->current_task = g_steal_pointer (&task); - setup_task_cancellable (device); - fpi_device_update_temp (device, TRUE); if (priv->temp_current == FP_TEMPERATURE_HOT) { @@ -1184,6 +1180,10 @@ fp_device_enroll (FpDevice *device, return; } + priv->current_action = FPI_DEVICE_ACTION_ENROLL; + priv->current_task = g_steal_pointer (&task); + setup_task_cancellable (device); + data = g_new0 (FpEnrollData, 1); data->print = g_object_ref_sink (template_print); data->enroll_progress_cb = progress_cb; @@ -1273,10 +1273,6 @@ fp_device_verify (FpDevice *device, return; } - priv->current_action = FPI_DEVICE_ACTION_VERIFY; - priv->current_task = g_steal_pointer (&task); - setup_task_cancellable (device); - fpi_device_update_temp (device, TRUE); if (priv->temp_current == FP_TEMPERATURE_HOT) { @@ -1285,6 +1281,10 @@ fp_device_verify (FpDevice *device, return; } + priv->current_action = FPI_DEVICE_ACTION_VERIFY; + priv->current_task = g_steal_pointer (&task); + setup_task_cancellable (device); + data = g_new0 (FpMatchData, 1); data->enrolled_print = g_object_ref (enrolled_print); data->match_cb = match_cb; @@ -1408,10 +1408,6 @@ fp_device_identify (FpDevice *device, return; } - priv->current_action = FPI_DEVICE_ACTION_IDENTIFY; - priv->current_task = g_steal_pointer (&task); - setup_task_cancellable (device); - fpi_device_update_temp (device, TRUE); if (priv->temp_current == FP_TEMPERATURE_HOT) { @@ -1420,6 +1416,10 @@ fp_device_identify (FpDevice *device, return; } + priv->current_action = FPI_DEVICE_ACTION_IDENTIFY; + priv->current_task = g_steal_pointer (&task); + setup_task_cancellable (device); + data = g_new0 (FpMatchData, 1); /* We cannot store the gallery directly, because the ptr array may not own * a reference to each print. Also, the caller could in principle modify the @@ -1533,10 +1533,6 @@ fp_device_capture (FpDevice *device, return; } - priv->current_action = FPI_DEVICE_ACTION_CAPTURE; - priv->current_task = g_steal_pointer (&task); - setup_task_cancellable (device); - fpi_device_update_temp (device, TRUE); if (priv->temp_current == FP_TEMPERATURE_HOT) { @@ -1545,6 +1541,10 @@ fp_device_capture (FpDevice *device, return; } + priv->current_action = FPI_DEVICE_ACTION_CAPTURE; + priv->current_task = g_steal_pointer (&task); + setup_task_cancellable (device); + priv->wait_for_finger = wait_for_finger; cls->capture (device); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 2b5a9dc1..f778eaa8 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -2388,6 +2388,11 @@ test_driver_identify_warmup_cooldown (void) g_assert_true (identify_data->called); g_assert_error (identify_data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_TOO_HOT); + /* Try to identify again, and ensure that we fail early */ + fp_device_identify_sync (device, prints, NULL, NULL, NULL, NULL, NULL, &error); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_TOO_HOT); + g_clear_error (&error); + /* Now, wait for it to cool down again; * WARM should be reached after about 2s * COLD after 5s but give it some more slack. */ From 2718dc02e0599ce9c12795f363dbf8ef118599b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 23:32:57 +0200 Subject: [PATCH 82/86] vfs0050: Initialize the usb transfer buffer when allocating it Ensure that the memory that we're going to populate via USB transfer is initialized, otherwise valgrind may complain about (even if that's not really an issue). --- libfprint/drivers/vfs0050.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c index dc77f542..2442937a 100644 --- a/libfprint/drivers/vfs0050.c +++ b/libfprint/drivers/vfs0050.c @@ -581,7 +581,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) /* Initialize fingerprint buffer */ g_free (self->lines_buffer); self->memory = VFS_USB_BUFFER_SIZE; - self->lines_buffer = g_malloc (self->memory); + self->lines_buffer = g_malloc0 (self->memory); self->bytes = 0; /* Finger is on the scanner */ @@ -589,12 +589,15 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) } /* Increase buffer size while it's insufficient */ - while (self->bytes + VFS_USB_BUFFER_SIZE > self->memory) + while (self->memory < self->bytes + VFS_USB_BUFFER_SIZE) { - self->memory <<= 1; + int pre_memory = self->memory; + self->memory += VFS_USB_BUFFER_SIZE; self->lines_buffer = (struct vfs_line *) g_realloc (self->lines_buffer, self->memory); + memset ((guint8 *) self->lines_buffer + pre_memory, 0, + VFS_USB_BUFFER_SIZE); } /* Receive chunk of data */ From 892c9767a25b4a583c325b132fa9b82545c0009b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 27 Sep 2022 19:58:53 +0200 Subject: [PATCH 83/86] tests: Be stricter on valgrind leak checks We used to ignore leaks, and we are ending up in having various of them, so let's make valgrind to exit with error when using the valgrind test setup (so in CI) to catch them better. --- tests/libfprint.supp | 19 +++++++++++++++++++ tests/meson.build | 11 ++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/libfprint.supp diff --git a/tests/libfprint.supp b/tests/libfprint.supp new file mode 100644 index 00000000..30a41454 --- /dev/null +++ b/tests/libfprint.supp @@ -0,0 +1,19 @@ +{ + + Memcheck:Leak + fun:malloc + ... + fun:dlopen* +} + +{ + + Memcheck:Param + socketcall.sendto(msg) + ... + fun:send + ... + fun:g_usb_device_get_string_descriptor + ... +} + diff --git a/tests/meson.build b/tests/meson.build index 94d47100..97a5bfa1 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -234,17 +234,26 @@ valgrind = find_program('valgrind', required: false) if valgrind.found() glib_share = glib_dep.get_pkgconfig_variable('prefix') / 'share' / glib_dep.name() glib_suppressions = glib_share + '/valgrind/glib.supp' + libfprint_suppressions = '@0@/@1@'.format(meson.source_root(), + files('libfprint.supp')[0]) python_suppressions = '@0@/@1@'.format(meson.source_root(), files('valgrind-python.supp')[0]) libfprint_wrapper = [ valgrind.path(), '--tool=memcheck', '--leak-check=full', + '--leak-resolution=high', + '--error-exitcode=1', + '--errors-for-leak-kinds=definite', + '--track-origins=yes', + '--show-leak-kinds=definite,possible', + '--show-error-list=yes', + '--suppressions=' + libfprint_suppressions, '--suppressions=' + glib_suppressions, '--suppressions=' + python_suppressions, ] add_test_setup('valgrind', - timeout_multiplier: 10, + timeout_multiplier: 15, exe_wrapper: libfprint_wrapper, env: [ 'G_SLICE=always-malloc', From 31004044192d22bbad9fe75452e554f4b3df9443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 13 Oct 2022 05:24:11 +0200 Subject: [PATCH 84/86] ci: Install more debug symbols --- .gitlab-ci/libfprint-image-variables.yaml | 2 +- .gitlab-ci/libfprint-templates.yaml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci/libfprint-image-variables.yaml b/.gitlab-ci/libfprint-image-variables.yaml index 2090e6fa..5244a2bd 100644 --- a/.gitlab-ci/libfprint-image-variables.yaml +++ b/.gitlab-ci/libfprint-image-variables.yaml @@ -1,2 +1,2 @@ variables: - LIBFPRINT_IMAGE_TAG: v1 + LIBFPRINT_IMAGE_TAG: v2 diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index a4ef62ac..dc35f806 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -36,7 +36,10 @@ dnf debuginfo-install -y \ glib2 \ glibc \ - libgusb + libgusb \ + libusb \ + nss \ + pixman git clone https://github.com/martinpitt/umockdev.git && \ cd umockdev && \ From 3ca20a8e70d87e248450d489e751822af3720b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 13 Oct 2022 05:37:12 +0200 Subject: [PATCH 85/86] ci: Do not run two image rebuild pipelines on schedules --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e63c1af..278d379a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -197,7 +197,7 @@ container_fedora_build_on_deps_changed: extends: .container_fedora_build_base only: variables: - - $CI_PROJECT_NAMESPACE == "libfprint" + - $CI_PROJECT_NAMESPACE == "libfprint" && $CI_PIPELINE_SOURCE != "schedule" refs: - branches - merge_requests From 86961a9429d589c387da37351fd6b4ff3caf67ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 13 Oct 2022 05:56:15 +0200 Subject: [PATCH 86/86] Release 1.94.5 --- NEWS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NEWS b/NEWS index e244ffb8..95c8b2a1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,18 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +2022-10-13: v1.94.5 release + +Highlights: + * New driver: fpcmoc, supporting various FPC MOC Fingerprint Sensors + * goodixmoc: New PIDs 0x6014, 0x6094, 0x631C, 0x634C, 0x6384, 0x659A. + * goodixmoc: Support resetting device on firmware failure due to corrupted DB. + * elanmoc: New PIDs 0x0c88, 0x0c8c, 0x0c8d. + * synaptics: New PID 0x0104. + * upektc: New PID 0x2017. + * Fixed various memory leaks + * More tests + 2022-05-24: v1.94.4 release Highlights: