diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ca8587e0..278d379a 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:
@@ -87,6 +94,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 +127,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 +141,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 +163,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 +179,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/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..9a4300e0 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);
@@ -368,6 +367,8 @@ fp_context_init (FpContext *self)
FpContextPrivate *priv = fp_context_get_instance_private (self);
guint i;
+ g_debug ("Initializing FpContext (libfprint version " LIBFPRINT_VERSION ")");
+
priv->drivers = fpi_get_driver_types ();
fpi_tod_shared_drivers_register ();
diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h
index f84a0d15..759a678f 100644
--- a/libfprint/fp-device-private.h
+++ b/libfprint/fp-device-private.h
@@ -126,6 +126,10 @@ typedef struct
GDestroyNotify match_destroy;
} FpMatchData;
+
+void fpi_device_suspend (FpDevice *device);
+void fpi_device_resume (FpDevice *device);
+
void fpi_device_configure_wakeup (FpDevice *device,
gboolean enabled);
void fpi_device_update_temp (FpDevice *device,
diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c
index 6a9178f7..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);
}
/**
@@ -1265,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)
{
@@ -1277,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;
@@ -1383,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)
{
@@ -1395,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;
@@ -1510,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)
@@ -1522,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
@@ -1635,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)
{
@@ -1647,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 812f0a2b..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"
@@ -594,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,
@@ -839,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;
}
@@ -885,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,
@@ -1283,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,
@@ -1346,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,
@@ -1523,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)
{
@@ -1533,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.
@@ -1576,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;
}
@@ -1609,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. */
@@ -1618,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);
}
/**
@@ -1650,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;
@@ -1686,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));
@@ -1694,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);
}
/**
@@ -1854,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/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 0670cf8b..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',
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 e7038b22..b854eb35 100644
--- a/tests/test-device-fake.c
+++ b/tests/test-device-fake.c
@@ -213,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);
}
}
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