diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca8587e0..589e86c0 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" @@ -15,6 +16,7 @@ variables: LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" stages: + - image-build - check-source - build - test @@ -69,6 +71,11 @@ test: - ninja -C _build coverage - cat _build/meson-logs/coverage.txt 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: @@ -79,6 +86,7 @@ test: test_valgrind: stage: test + allow_failure: true except: variables: - $CI_PIPELINE_SOURCE == "schedule" @@ -87,6 +95,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: @@ -118,7 +128,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 @@ -132,7 +142,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" @@ -153,11 +164,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 @@ -168,7 +180,27 @@ container_fedora_build: 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 + 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" && $CI_PIPELINE_SOURCE != "schedule" + refs: + - branches + - merge_requests + changes: + - .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..5244a2bd --- /dev/null +++ b/.gitlab-ci/libfprint-image-variables.yaml @@ -0,0 +1,2 @@ +variables: + LIBFPRINT_IMAGE_TAG: v2 diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index ace3f7b4..dc35f806 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -1,6 +1,10 @@ +# 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 + dnf-plugins-core flatpak-builder gcc gcc-c++ @@ -27,3 +31,17 @@ valgrind clang-analyzer diffutils + + LIBFPRINT_EXEC: | + dnf debuginfo-install -y \ + glib2 \ + glibc \ + libgusb \ + libusb \ + nss \ + pixman + + git clone https://github.com/martinpitt/umockdev.git && \ + cd umockdev && \ + meson _build --prefix=/usr && \ + ninja -C _build && ninja -C _build install diff --git a/NEWS b/NEWS index 2e0a2c6a..95c8b2a1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,29 @@ 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: + * 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/README.md b/README.md index b318be9c..26cd9012 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,90 @@ -# libfprint -libfprint is part of the fprint project: -https://fprint.freedesktop.org/ -## 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 -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). +*LibFPrint is part of the **[FPrint][Website]** project.* -## 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. +[![Button Website]][Website] +[![Button Documentation]][Documentation] -For more information on libfprint, supported devices, API documentation, etc., -see the homepage: -https://fprint.freedesktop.org/ +[![Button Supported]][Supported] +[![Button Unsupported]][Unsupported] -libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file -for the license text. +[![Button Contribute]][Contribute] +[![Button Contributors]][Contributors] -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 +
## TOD Informations See https://gitlab.freedesktop.org/3v1n0/libfprint/-/blob/tod/README.tod.md -## Historical links +## History -Older versions of libfprint are available at: -https://sourceforge.net/projects/fprint/files/ +**LibFPrint** was originally developed as part of an +academic project at the **[University Of Manchester]**. -Historical mailing-list archives: -http://www.reactivated.net/fprint_list_archives/ +It aimed to hide the differences between consumer +fingerprint scanners and provide a single uniform +API to application developers. -Historical website: -http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/ +## Goal + +The ultimate goal of the **FPrint** project is to make +fingerprint scanners widely and easily usable under +common Linux environments. + +## License + +`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. + +**LibFPrint** includes code from **NIST's** **[NBIS]** software distribution. + +We include **Bozorth3** from the **[US Export Controlled]** +distribution, which we have determined to be fine +being shipped in an open source project. + +
+ +
+ +[![Badge License]][License] + +
+ + + + +[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 diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb index 91a14ebd..d476f7e1 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* @@ -144,6 +145,10 @@ usb:v04F3p0C58* # Supported by libfprint driver elanmoc usb:v04F3p0C7D* usb:v04F3p0C7E* +usb:v04F3p0C82* +usb:v04F3p0C88* +usb:v04F3p0C8C* +usb:v04F3p0C8D* ID_AUTOSUSPEND=1 ID_PERSIST=0 @@ -152,10 +157,24 @@ 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* +usb:v27C6p6094* usb:v27C6p609C* usb:v27C6p60A2* +usb:v27C6p631C* +usb:v27C6p634C* +usb:v27C6p6384* usb:v27C6p639C* usb:v27C6p63AC* usb:v27C6p63BC* @@ -165,6 +184,7 @@ usb:v27C6p6584* usb:v27C6p658C* usb:v27C6p6592* usb:v27C6p6594* +usb:v27C6p659A* usb:v27C6p659C* usb:v27C6p6A94* ID_AUTOSUSPEND=1 @@ -187,6 +207,9 @@ usb:v06CBp0103* usb:v06CBp0123* usb:v06CBp0126* usb:v06CBp0129* +usb:v06CBp0168* +usb:v06CBp015F* +usb:v06CBp0104* ID_AUTOSUSPEND=1 ID_PERSIST=0 @@ -199,6 +222,7 @@ usb:v147Ep1001* # Supported by libfprint driver upektc usb:v0483p2015* +usb:v0483p2017* usb:v147Ep3001* ID_AUTOSUSPEND=1 ID_PERSIST=0 @@ -254,13 +278,19 @@ usb:v138Ap0091* ID_PERSIST=0 # Known unsupported devices +usb:v04E8p730B* usb:v04F3p036B* usb:v04F3p0C00* -usb:v04F3p0C4B* 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* @@ -277,6 +307,7 @@ usb:v06CBp00C9* usb:v06CBp00D8* usb:v06CBp00DA* usb:v06CBp00DC* +usb:v06CBp00E4* usb:v06CBp00E7* usb:v06CBp00E9* usb:v06CBp00FD* @@ -292,6 +323,7 @@ usb:v0A5Cp5845* usb:v0BDAp5812* usb:v10A5p0007* usb:v10A5p9200* +usb:v10A5p9800* usb:v1188p9545* usb:v138Ap0007* usb:v138Ap003A* @@ -313,24 +345,32 @@ 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* usb:v27C6p538C* 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* usb:v298Dp2033* usb:v3538p0930* diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index b6ab165d..8fd52f56 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -1,12 +1,12 @@ { "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": [ /* X11 + XShm access */ - "--share=ipc", "--socket=x11", + "--share=ipc", "--socket=fallback-x11", /* Wayland access */ "--socket=wayland", /* OpenGL access */ @@ -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" ] }, { @@ -62,12 +62,11 @@ { "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", - "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git", - "branch": "wip/benzea/v2" + "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git" } ] } diff --git a/examples/tod-inspector.c b/examples/tod-inspector.c index b121422b..4b64c044 100644 --- a/examples/tod-inspector.c +++ b/examples/tod-inspector.c @@ -113,9 +113,9 @@ main (void) g_autoptr(GArray) shared_drivers = NULL; guint i; - fpi_tod_shared_drivers_register (); + tod_shared_drivers_register (); - shared_drivers = fpi_tod_shared_drivers_get (); + shared_drivers = tod_shared_drivers_get (); g_print ("Found %u drivers\n", shared_drivers->len); for (i = 0; i < shared_drivers->len; i++) @@ -157,5 +157,5 @@ main (void) g_print ("------------\n"); } - fpi_tod_shared_drivers_unregister (); + tod_shared_drivers_unregister (); } 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); 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/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/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c index 69700a0c..471189fd 100644 --- a/libfprint/drivers/elanmoc/elanmoc.c +++ b/libfprint/drivers/elanmoc/elanmoc.c @@ -27,6 +27,10 @@ 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 = 0x04f3, .pid = 0x0c88, }, + { .vid = 0x04f3, .pid = 0x0c8c, }, + { .vid = 0x04f3, .pid = 0x0c8d, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; @@ -375,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); @@ -440,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; @@ -505,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); @@ -757,6 +761,7 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id, } enum identify_states { + IDENTIFY_SET_MODE, IDENTIFY_WAIT_FINGER, IDENTIFY_NUM_STATES, }; @@ -792,6 +797,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); @@ -998,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) { @@ -1006,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); } } @@ -1059,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; @@ -1066,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; 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} }; 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/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c index 4eeb7215..48dafe10 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], @@ -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; } @@ -1294,12 +1359,18 @@ gx_fp_probe (FpDevice *device) { case 0x6496: case 0x60A2: + case 0x6014: + case 0x6094: case 0x609C: + case 0x631C: + case 0x634C: + case 0x6384: case 0x639C: case 0x63AC: case 0x63BC: case 0x63CC: case 0x6A94: + case 0x659A: self->max_enroll_stage = 12; break; @@ -1530,8 +1601,13 @@ 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, }, + { .vid = 0x27c6, .pid = 0x631C, }, + { .vid = 0x27c6, .pid = 0x634C, }, + { .vid = 0x27c6, .pid = 0x6384, }, { .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x63AC, }, { .vid = 0x27c6, .pid = 0x63BC, }, @@ -1541,6 +1617,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 */ 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/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; } diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 7a2c6ebe..f13b820b 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -42,6 +42,9 @@ 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 = SYNAPTICS_VENDOR_ID, .pid = 0x015F, }, + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0104, }, { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; @@ -224,6 +227,7 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer, } else { + fpi_device_critical_leave (device); fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), 0, NULL, 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 }, }; diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 138673c8..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) @@ -551,7 +552,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); } @@ -1413,6 +1414,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); 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 */ 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/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); } } diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 65c57b22..99b660ed 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -295,11 +295,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); @@ -307,7 +306,7 @@ fp_context_finalize (GObject *object) g_object_run_dispose (G_OBJECT (priv->usb_ctx)); g_clear_object (&priv->usb_ctx); - fpi_tod_shared_drivers_unregister (); + tod_shared_drivers_unregister (); G_OBJECT_CLASS (fp_context_parent_class)->finalize (object); } @@ -368,10 +367,12 @@ 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 (); - fpi_tod_shared_drivers_register (); - shared_drivers = fpi_tod_shared_drivers_get (); + tod_shared_drivers_register (); + shared_drivers = tod_shared_drivers_get (); g_array_prepend_vals (priv->drivers, shared_drivers->data, shared_drivers->len); if (get_drivers_whitelist_env ()) diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h index 99eba410..759a678f 100644 --- a/libfprint/fp-device-private.h +++ b/libfprint/fp-device-private.h @@ -111,8 +111,6 @@ typedef struct GDestroyNotify enroll_progress_destroy; } FpEnrollData; -void enroll_data_free (FpEnrollData *enroll_data); - typedef struct { FpPrint *enrolled_print; /* verify */ @@ -128,7 +126,9 @@ typedef struct GDestroyNotify match_destroy; } FpMatchData; -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); diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 82f309e8..c1436448 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); @@ -948,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 @@ -1008,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); } /** @@ -1114,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); } /** @@ -1172,6 +1088,15 @@ fp_device_resume_finish (FpDevice *device, return g_task_propagate_boolean (G_TASK (result), error); } +static void +enroll_data_free (FpEnrollData *data) +{ + if (data->enroll_progress_destroy) + data->enroll_progress_destroy (data->enroll_progress_data); + data->enroll_progress_data = NULL; + g_clear_object (&data->print); + g_free (data); +} /** * fp_device_enroll: @@ -1256,10 +1181,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) { @@ -1268,6 +1189,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; @@ -1301,6 +1226,23 @@ fp_device_enroll_finish (FpDevice *device, return g_task_propagate_pointer (G_TASK (result), error); } +static void +match_data_free (FpMatchData *data) +{ + g_clear_object (&data->print); + g_clear_object (&data->match); + g_clear_error (&data->error); + + if (data->match_destroy) + data->match_destroy (data->match_data); + data->match_data = NULL; + + g_clear_object (&data->enrolled_print); + g_clear_pointer (&data->gallery, g_ptr_array_unref); + + g_free (data); +} + /** * fp_device_verify: * @device: a #FpDevice @@ -1357,10 +1299,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) { @@ -1369,6 +1307,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; @@ -1484,9 +1426,13 @@ fp_device_identify (FpDevice *device, return; } - priv->current_action = FPI_DEVICE_ACTION_IDENTIFY; - priv->current_task = g_steal_pointer (&task); - setup_task_cancellable (device); + if (prints == NULL) + { + g_task_return_error (task, + fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID, + "Invalid gallery array")); + return; + } fpi_device_update_temp (device, TRUE); if (priv->temp_current == FP_TEMPERATURE_HOT) @@ -1496,6 +1442,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 @@ -1609,10 +1559,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) { @@ -1621,6 +1567,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/libfprint/fp-image.c b/libfprint/fp-image.c index fa3a5b43..8870cfab 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" @@ -296,7 +297,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/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) 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-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 diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 89504dab..1b9fa8f3 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" @@ -521,33 +522,6 @@ fpi_device_get_driver_data (FpDevice *device) return priv->driver_data; } -void -enroll_data_free (FpEnrollData *data) -{ - if (data->enroll_progress_destroy) - data->enroll_progress_destroy (data->enroll_progress_data); - data->enroll_progress_data = NULL; - g_clear_object (&data->print); - g_free (data); -} - -void -match_data_free (FpMatchData *data) -{ - g_clear_object (&data->print); - g_clear_object (&data->match); - g_clear_error (&data->error); - - if (data->match_destroy) - data->match_destroy (data->match_data); - data->match_data = NULL; - - g_clear_object (&data->enrolled_print); - g_clear_pointer (&data->gallery, g_ptr_array_unref); - - g_free (data); -} - /** * fpi_device_get_enroll_data: * @device: The #FpDevice @@ -621,7 +595,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, @@ -866,16 +847,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; } @@ -912,6 +893,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, @@ -1310,12 +1292,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, @@ -1373,9 +1357,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, @@ -1550,6 +1539,150 @@ 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; +} + +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 (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) { @@ -1560,42 +1693,38 @@ 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, port; + guint8 bus; 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); /* 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); - g_string_prepend (ports, g_strdup_printf ("%d.", port)); - dev = parent; + port_str = g_strdup_printf ("%d.", port); + g_string_prepend (ports, port_str); + g_set_object (&dev, parent); } 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 +1732,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; } @@ -1636,6 +1754,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. */ @@ -1645,11 +1764,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); } /** @@ -1677,11 +1797,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; @@ -1713,6 +1834,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)); @@ -1721,10 +1843,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); } /** @@ -1881,12 +2005,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, 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))); } /** 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. */ diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c index ad9cdd07..cf1c4ecf 100644 --- a/libfprint/fprint-list-udev-hwdb.c +++ b/libfprint/fprint-list-udev-hwdb.c @@ -29,13 +29,19 @@ 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 = 0x0c4b }, { .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 }, @@ -52,6 +58,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 }, @@ -67,6 +74,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 }, @@ -88,24 +96,32 @@ 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 }, { .vid = 0x27c6, .pid = 0x538c }, { .vid = 0x27c6, .pid = 0x538d }, { .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 }, { .vid = 0x298d, .pid = 0x2033 }, { .vid = 0x3538, .pid = 0x0930 }, diff --git a/libfprint/meson.build b/libfprint/meson.build index 3db7dd40..856e0b35 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 = { @@ -334,7 +336,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, @@ -345,6 +347,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/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 diff --git a/libfprint/tod/libfprint-tod.ver.in b/libfprint/tod/libfprint-tod.ver.in index 496d5252..f917e4dd 100644 --- a/libfprint/tod/libfprint-tod.ver.in +++ b/libfprint/tod/libfprint-tod.ver.in @@ -240,7 +240,9 @@ LIBFPRINT_TOD_@tod_soversion@_1.94 { global: fpi_device_critical_enter; fpi_device_critical_leave; + fpi_device_resume; fpi_device_resume_complete; + fpi_device_suspend; fpi_device_suspend_complete; fpi_ssm_silence_debug; diff --git a/libfprint/tod/meson.build b/libfprint/tod/meson.build index 10c49e4c..ff59d1f8 100644 --- a/libfprint/tod/meson.build +++ b/libfprint/tod/meson.build @@ -19,6 +19,7 @@ mapfile = configure_file(input: 'libfprint-tod.ver.in', libfprint_tod_private = static_library('fprint-tod-private', sources: [ 'tod-shared-loader.c', + 'tod-goodix-wrapper.c', ], include_directories: include_directories('..'), link_with: libfprint_private, @@ -34,7 +35,7 @@ foreach source: libfprint_private_sources tod_sources += '..' / source endforeach -libfprint_tod = library(versioned_libname.split('lib')[1] + '-tod', +libfprint_tod = shared_library(versioned_libname.split('lib')[1] + '-tod', c_args: [ '-DTOD_LIBRARY=1', '-include', '@0@'.format(files('tod-symbols.h')[0]), @@ -49,7 +50,7 @@ libfprint_tod = library(versioned_libname.split('lib')[1] + '-tod', '-Wl,--unresolved-symbols=ignore-in-object-files' ], link_depends: mapfile, - link_with: [libfprint_private], + link_whole: [libfprint_tod_private], dependencies: deps, install: true) @@ -103,3 +104,7 @@ install_headers(tod_headers, install_headers(tod_local_headers, subdir: tod_subpath / 'tod', ) + +# Replace the libfprint private instance with the TOD one in this case as we +# contain already all the symbols. +libfprint_private = libfprint_tod diff --git a/libfprint/tod/tests/check-library-symbols.sh b/libfprint/tod/tests/check-library-symbols.sh new file mode 100755 index 00000000..61f44c3d --- /dev/null +++ b/libfprint/tod/tests/check-library-symbols.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +library1=$1 +library2=$2 + +function cleanup_results() { + grep -F -w '.text' | cut -s -f2 | awk '{print $(NF)}' +} + +function dump_exported_symbols() { + objdump -TC "$1" | cleanup_results +} + +function dump_defined_symbols() { + objdump -t "$1" | cleanup_results +} + +function in_array() { + local target=$1 + shift + + local i; + for i in "$@"; do + if [[ "$i" == "$target" ]]; then + return 0 + fi + done + + return 1 +} + +function is_fatal() { + if [[ "$1" == "fp_"* ]] || [[ "$1" == "fpi_"* ]]; then + return 0 + fi + return 1 +} + +lib1_exported=($(dump_exported_symbols "$library1")) +lib2_exported=($(dump_exported_symbols "$library2")) + +lib1_defined=("$(dump_defined_symbols "$library1")") +lib2_defined=("$(dump_defined_symbols "$library2")") + +valid=true + +for f in ${lib1_exported[*]}; do + if in_array "$f" ${lib2_exported[*]}; then + echo "$f function exported in both $library1 and $library2" + if is_fatal "$f"; then + valid=false + fi + fi +done + +for f in ${lib1_defined[*]}; do + if in_array "$f" ${lib2_defined[*]}; then + echo "$f function defined in both $library1 and $library2" + if is_fatal "$f"; then + valid=false + fi + fi +done + +[[ "$valid" == true ]] && exit 0 diff --git a/libfprint/tod/tod-goodix-wrapper.c b/libfprint/tod/tod-goodix-wrapper.c new file mode 100644 index 00000000..8b72a792 --- /dev/null +++ b/libfprint/tod/tod-goodix-wrapper.c @@ -0,0 +1,56 @@ +/* + * Shared library loader for libfprint + * Copyright (C) 2022 Marco Trevisan + * + * 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 "fp-device-private.h" +#include "fpi-device.h" +#define FP_COMPONENT "tod" + +#include "tod-goodix-wrapper.h" + +static void (*goodix_moc_identify)(FpDevice *) = NULL; + +static void +goodix_tod_identify_wrapper (FpDevice *device) +{ + GPtrArray *prints; + + fpi_device_get_identify_data (device, &prints); + + if (prints->len) + return goodix_moc_identify (device); + + g_warning ("%s does not support identify with empty gallery, let's skip it", + fp_device_get_name (device)); + + fpi_device_identify_report (device, NULL, NULL, NULL); + fpi_device_identify_complete (device, NULL); +} + +void +goodix_tod_wrapper_init (FpDeviceClass *device_class) +{ + g_assert (g_strcmp0 (device_class->id, "goodix-tod") == 0); + g_assert (goodix_moc_identify == NULL); + + g_message ("Creating TOD wrapper for %s (%s) driver", + device_class->id, device_class->full_name); + + goodix_moc_identify = device_class->identify; + device_class->identify = goodix_tod_identify_wrapper; +} diff --git a/libfprint/tod/tod-goodix-wrapper.h b/libfprint/tod/tod-goodix-wrapper.h new file mode 100644 index 00000000..802e6962 --- /dev/null +++ b/libfprint/tod/tod-goodix-wrapper.h @@ -0,0 +1,24 @@ +/* + * Shared library loader for libfprint + * Copyright (C) 2022 Marco Trevisan + * + * 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 "drivers_api.h" + +void goodix_tod_wrapper_init (FpDeviceClass *device_class); diff --git a/libfprint/tod/tod-shared-loader.c b/libfprint/tod/tod-shared-loader.c index d214aebb..72647552 100644 --- a/libfprint/tod/tod-shared-loader.c +++ b/libfprint/tod/tod-shared-loader.c @@ -22,6 +22,7 @@ #include #include "tod-shared-loader.h" +#include "tod-goodix-wrapper.h" #include "fpi-device.h" #include "fpi-log.h" #include "tod-config.h" @@ -48,7 +49,7 @@ get_tod_drivers_dir (void) } void -fpi_tod_shared_drivers_register (void) +tod_shared_drivers_register (void) { const char *dirname; const char *basename; @@ -131,6 +132,9 @@ fpi_tod_shared_drivers_register (void) { g_debug ("Initializing features for driver %s", cls->id); fpi_device_class_auto_initialize_features (cls); + + if (g_strcmp0 (cls->id, "goodix-tod") == 0) + goodix_tod_wrapper_init (cls); } shared_modules = g_list_prepend (shared_modules, @@ -139,7 +143,7 @@ fpi_tod_shared_drivers_register (void) } void -fpi_tod_shared_drivers_unregister (void) +tod_shared_drivers_unregister (void) { g_clear_pointer (&shared_drivers, g_array_unref); @@ -151,7 +155,7 @@ fpi_tod_shared_drivers_unregister (void) } GArray * -fpi_tod_shared_drivers_get (void) +tod_shared_drivers_get (void) { return g_array_ref (shared_drivers); } diff --git a/libfprint/tod/tod-shared-loader.h b/libfprint/tod/tod-shared-loader.h index 8ed2e811..cc3873d9 100644 --- a/libfprint/tod/tod-shared-loader.h +++ b/libfprint/tod/tod-shared-loader.h @@ -22,7 +22,7 @@ #include -void fpi_tod_shared_drivers_register (void); -void fpi_tod_shared_drivers_unregister (void); +void tod_shared_drivers_register (void); +void tod_shared_drivers_unregister (void); -GArray *fpi_tod_shared_drivers_get (void); +GArray *tod_shared_drivers_get (void); diff --git a/libfprint/tod/tod-symbols.h b/libfprint/tod/tod-symbols.h index d4f497bc..1f600a2d 100644 --- a/libfprint/tod/tod-symbols.h +++ b/libfprint/tod/tod-symbols.h @@ -19,12 +19,23 @@ #pragma once +#define LIBFPRINT_2_SYMBOL_VERSION_2_0 "LIBFPRINT_2.0.0" +#define LIBFPRINT_2_SYMBOL_VERSION(major, minor) \ + LIBFPRINT_2_SYMBOL_VERSION_ ## major ## _ ## minor + #define TOD_1_SYMBOL_VERSION_1_90 "LIBFPRINT_TOD_1.0.0" #define TOD_1_SYMBOL_VERSION_1_92 "LIBFPRINT_TOD_1_1.92" #define TOD_1_SYMBOL_VERSION_1_94 "LIBFPRINT_TOD_1_1.94" #define TOD_1_SYMBOL_VERSION(major, minor) \ TOD_1_SYMBOL_VERSION_ ## major ## _ ## minor +#define TOD_DEFAULT_UPSTREAM_SYMBOL_VERSIONED(symbol, major, minor) \ + __asm__ (".symver " # symbol "," # symbol "@@@" \ + LIBFPRINT_2_SYMBOL_VERSION (major, minor)); + +#define TOD_DEFAULT_UPSTREAM_SYMBOL(symbol) \ + __asm__ (".symver " # symbol "," # symbol "@@@"); + #define TOD_DEFAULT_VERSION_SYMBOL(symbol, major, minor) \ __asm__ (".symver " # symbol "," # symbol "@@@" \ TOD_1_SYMBOL_VERSION (major, minor)); diff --git a/meson.build b/meson.build index f7381ca7..188404a0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '1.94.3+tod1', + version: '1.94.5+tod1', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', @@ -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') @@ -124,6 +125,7 @@ default_drivers = [ 'upekts', 'goodixmoc', 'nb1010', + 'fpcmoc', # SPI 'elanspi', 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 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/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) diff --git a/tests/elanmoc/custom.pcapng b/tests/elanmoc/custom.pcapng index a41ac162..c839c37e 100644 Binary files a/tests/elanmoc/custom.pcapng and b/tests/elanmoc/custom.pcapng differ 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/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 diff --git a/tests/fpcmoc/custom.pcapng b/tests/fpcmoc/custom.pcapng new file mode 100644 index 00000000..57b6f766 Binary files /dev/null and b/tests/fpcmoc/custom.pcapng differ diff --git a/tests/fpcmoc/custom.py b/tests/fpcmoc/custom.py new file mode 100755 index 00000000..709ba93b --- /dev/null +++ b/tests/fpcmoc/custom.py @@ -0,0 +1,92 @@ +#!/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() +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/goodixmoc/custom.pcapng b/tests/goodixmoc/custom.pcapng index eb58d865..b5e2d89c 100644 Binary files a/tests/goodixmoc/custom.pcapng and b/tests/goodixmoc/custom.pcapng differ diff --git a/tests/goodixmoc/custom.py b/tests/goodixmoc/custom.py index 1fb513a1..aee43918 100755 --- 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() @@ -25,10 +31,13 @@ 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): - 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/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 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 48fece68..4dcae66e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -39,6 +39,7 @@ drivers_tests = [ 'goodixmoc', 'nb1010', 'egis0570', + 'fpcmoc', ] if get_option('introspection') @@ -57,16 +58,17 @@ 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'] - 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 @@ -106,8 +108,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, @@ -206,6 +211,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) @@ -228,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', @@ -392,4 +407,15 @@ if get_option('tod') ) endif endforeach + + if find_program('objdump', required: false).found() + check_libs_symbols = find_program(meson.source_root() / + 'libfprint/tod/tests/check-library-symbols.sh') + test('check-tod-lib-sybmbols', + check_libs_symbols, + args: [libfprint.full_path(), libfprint_tod.full_path()], + depends: [libfprint, libfprint_tod], + suite: ['abi-check', tod_suites ], + ) + endif endif diff --git a/tests/synaptics/custom.pcapng b/tests/synaptics/custom.pcapng index 44e161ca..f6dc26ef 100644 Binary files a/tests/synaptics/custom.pcapng and b/tests/synaptics/custom.pcapng differ diff --git a/tests/synaptics/custom.py b/tests/synaptics/custom.py index 3e48341d..5b4b1481 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 diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c index b07f830d..b854eb35 100644 --- a/tests/test-device-fake.c +++ b/tests/test-device-fake.c @@ -24,6 +24,7 @@ #define FP_COMPONENT "fake_test_dev" #endif +#include "fpi-log.h" #include "test-device-fake.h" G_DEFINE_TYPE (FpiDeviceFake, fpi_device_fake, FP_TYPE_DEVICE) @@ -33,12 +34,28 @@ static const FpIdEntry driver_ids[] = { { .virtual_envvar = NULL } }; +static void + (debug_action) (FpDevice * device, + const gchar *func) +{ + g_autofree char *action_str = NULL; + + action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, + fpi_device_get_current_action (device)); + + fp_dbg ("%s: Device %s in action %s\n", + func, fp_device_get_name (device), action_str); +} + +#define debug_action(d) (debug_action) ((d), G_STRFUNC) + static void fpi_device_fake_probe (FpDevice *device) { FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_probe; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); @@ -59,6 +76,7 @@ fpi_device_fake_open (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_open; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); @@ -76,6 +94,7 @@ fpi_device_fake_close (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_close; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLOSE); @@ -94,6 +113,7 @@ fpi_device_fake_enroll (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *print = fake_dev->ret_print; + debug_action (device); fake_dev->last_called_function = fpi_device_fake_enroll; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL); @@ -122,6 +142,7 @@ fpi_device_fake_verify (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *print = fake_dev->ret_print; + debug_action (device); fake_dev->last_called_function = fpi_device_fake_verify; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_VERIFY); @@ -153,6 +174,7 @@ fpi_device_fake_identify (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *match = fake_dev->ret_match; + debug_action (device); fake_dev->last_called_function = fpi_device_fake_identify; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_IDENTIFY); @@ -191,6 +213,7 @@ fpi_device_fake_identify (FpDevice *device) else { fpi_device_identify_complete (device, fake_dev->ret_error); + g_clear_object (&fake_dev->ret_print); } } @@ -200,6 +223,7 @@ fpi_device_fake_capture (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); gboolean wait_for_finger; + debug_action (device); fake_dev->last_called_function = fpi_device_fake_capture; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE); @@ -219,6 +243,7 @@ fpi_device_fake_list (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_list; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_LIST); @@ -236,6 +261,7 @@ fpi_device_fake_delete (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_delete; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE); @@ -254,6 +280,7 @@ fpi_device_fake_clear_storage (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_clear_storage; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLEAR_STORAGE); @@ -271,6 +298,7 @@ fpi_device_fake_cancel (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_cancel; g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE); } @@ -280,6 +308,7 @@ fpi_device_fake_suspend (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_suspend; fpi_device_suspend_complete (device, g_steal_pointer (&fake_dev->ret_suspend)); @@ -290,6 +319,7 @@ fpi_device_fake_resume (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + debug_action (device); fake_dev->last_called_function = fpi_device_fake_resume; fpi_device_resume_complete (device, g_steal_pointer (&fake_dev->ret_resume)); diff --git a/tests/test-fp-context-tod.c b/tests/test-fp-context-tod.c index 7137e3dd..912a82e9 100644 --- a/tests/test-fp-context-tod.c +++ b/tests/test-fp-context-tod.c @@ -20,6 +20,7 @@ #define FP_COMPONENT "tod" #include "fpi-log.h" +#include "fpi-device.h" #include static void @@ -77,6 +78,19 @@ test_context_has_fake_device (void) } g_assert_true (FP_IS_DEVICE (fake_device)); + + if (FP_DEVICE_GET_CLASS (fake_device)->open) + { + GCancellable *cancellable; + g_assert_true (fp_device_open_sync (fake_device, NULL, NULL)); + g_assert_false (fp_device_open_sync (fake_device, NULL, NULL)); + g_assert_true (fp_device_close_sync (fake_device, NULL, NULL)); + + cancellable = g_cancellable_new (); + g_cancellable_cancel (cancellable); + g_assert_false (fp_device_open_sync (fake_device, cancellable, NULL)); + g_clear_object (&cancellable); + } } static void 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 (); } diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index a7b2611b..19fadba4 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -143,6 +143,10 @@ tod_check_device_version (FpDevice *device_class, tod_subversion); } +/* 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; @@ -1260,6 +1264,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; @@ -1286,6 +1291,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; @@ -2564,6 +2570,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. */ diff --git a/tests/test-generated-hwdb.sh b/tests/test-generated-hwdb.sh index 87c08bbf..7e1af144 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 @@ -17,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 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.') diff --git a/tests/virtual-device.py b/tests/virtual-device.py index e15b4327..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() @@ -235,10 +238,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 +326,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 +597,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..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) @@ -234,7 +237,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