mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
Compare commits
238 Commits
benzea/fix
...
benzea/add
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f13ddc40d | ||
|
|
e0f081c6e3 | ||
|
|
ae1fb4094b | ||
|
|
13350e05a2 | ||
|
|
3ea9cc90fe | ||
|
|
e862e8e881 | ||
|
|
60f5cd650a | ||
|
|
7ff36888b7 | ||
|
|
e3043123f5 | ||
|
|
77400b7a60 | ||
|
|
8d83e5eb38 | ||
|
|
e59d5451cc | ||
|
|
798bc4ee1e | ||
|
|
0e732dbafa | ||
|
|
84112abc71 | ||
|
|
c221c6b63e | ||
|
|
6e28b9a8c4 | ||
|
|
e5589a0ec2 | ||
|
|
966703057d | ||
|
|
9e164485f0 | ||
|
|
3bb38e2ff6 | ||
|
|
6a62d32c81 | ||
|
|
b2a64cc980 | ||
|
|
88117c172e | ||
|
|
27a62443a1 | ||
|
|
2f7c78eb97 | ||
|
|
74f8a8ee27 | ||
|
|
acd0a10e76 | ||
|
|
27c2466bda | ||
|
|
33ba248c44 | ||
|
|
43cf28b9da | ||
|
|
4da52f78f6 | ||
|
|
e4e0937848 | ||
|
|
25a6c916aa | ||
|
|
51009b48a0 | ||
|
|
e1e3f6955e | ||
|
|
c495b82000 | ||
|
|
d90ee96df8 | ||
|
|
36304b736b | ||
|
|
31e34bd4bd | ||
|
|
ec4c7ca5a9 | ||
|
|
8d21a9c27c | ||
|
|
c4069065f9 | ||
|
|
31541edc58 | ||
|
|
549718753f | ||
|
|
cfde050220 | ||
|
|
88a38c38af | ||
|
|
7ffcc2f9e7 | ||
|
|
1dae6796f7 | ||
|
|
0bb0492025 | ||
|
|
3db0858fb0 | ||
|
|
2382506491 | ||
|
|
08f4be707c | ||
|
|
3693c39bc5 | ||
|
|
993109a7f8 | ||
|
|
18db20d160 | ||
|
|
89b4c4ee75 | ||
|
|
153b24a95a | ||
|
|
8c45c0952e | ||
|
|
c3ece8621d | ||
|
|
67cb61cc18 | ||
|
|
33ffadf402 | ||
|
|
162a83e484 | ||
|
|
dfb27222eb | ||
|
|
81e53c422d | ||
|
|
be0b4ae2bb | ||
|
|
56bcf1ffdd | ||
|
|
665de7813b | ||
|
|
a291d17f26 | ||
|
|
e8886dbc6b | ||
|
|
3d6fb15b5c | ||
|
|
43d0dfdd8f | ||
|
|
50f522583e | ||
|
|
f0443ba2f3 | ||
|
|
546f35132c | ||
|
|
ce9527d2cb | ||
|
|
89890dbd1f | ||
|
|
e0c41c5444 | ||
|
|
3b83157e9b | ||
|
|
57f836a0f6 | ||
|
|
170924ee4f | ||
|
|
63bfaf4f60 | ||
|
|
2f6adce2fa | ||
|
|
018641ad20 | ||
|
|
8ded064e65 | ||
|
|
3f7a638eed | ||
|
|
253750ec08 | ||
|
|
5df14206d8 | ||
|
|
2f2da87240 | ||
|
|
533180a2e6 | ||
|
|
99c269b3fe | ||
|
|
66fc93eeff | ||
|
|
284f6f1ef8 | ||
|
|
1f2d723485 | ||
|
|
f6179d6cc4 | ||
|
|
cbce56c142 | ||
|
|
55a2bb5536 | ||
|
|
16095a21fd | ||
|
|
80dbc9c0cb | ||
|
|
944e0d0383 | ||
|
|
349fbeb834 | ||
|
|
17a8bacfaf | ||
|
|
6d4b498dae | ||
|
|
7c2a67a954 | ||
|
|
a6c2509ca8 | ||
|
|
8254b9e99e | ||
|
|
943c64d96f | ||
|
|
f852d972a5 | ||
|
|
35d2d78e67 | ||
|
|
3d5db6a391 | ||
|
|
2ee0d16784 | ||
|
|
e6712fbcca | ||
|
|
ee928db5b2 | ||
|
|
d6ca8ff2b0 | ||
|
|
b1b20f8ab9 | ||
|
|
7e2b89791e | ||
|
|
3560a0f1e7 | ||
|
|
ed5339c4f5 | ||
|
|
2d10d864d8 | ||
|
|
c96958582f | ||
|
|
c02771d16b | ||
|
|
989d498eb9 | ||
|
|
91ee03eb7a | ||
|
|
28ba6a0de9 | ||
|
|
faade91c39 | ||
|
|
499de3e442 | ||
|
|
0ff7a07671 | ||
|
|
0d9d7dcb46 | ||
|
|
fb23f8690f | ||
|
|
6ca8441df9 | ||
|
|
8112da0358 | ||
|
|
f2ea3e784e | ||
|
|
74810a8472 | ||
|
|
91fb8d8cb4 | ||
|
|
0688288c6d | ||
|
|
c1e832e7a7 | ||
|
|
b5496fd257 | ||
|
|
de271a0e8d | ||
|
|
12b0120a3d | ||
|
|
2783ac3e60 | ||
|
|
abb0b1267c | ||
|
|
5cb91a4189 | ||
|
|
0bb132b167 | ||
|
|
ce39f27b5e | ||
|
|
7d0956513b | ||
|
|
2b7cfa751a | ||
|
|
0eee6a56dd | ||
|
|
8962e14fde | ||
|
|
e246e00ba3 | ||
|
|
fa3bdb874d | ||
|
|
2caeb8cbb3 | ||
|
|
dda3587b76 | ||
|
|
fb5854213a | ||
|
|
21ee241f0c | ||
|
|
280f916ace | ||
|
|
1b5dd0057f | ||
|
|
8a6f1932f8 | ||
|
|
0051ff6352 | ||
|
|
b6dd522459 | ||
|
|
656bf3d175 | ||
|
|
fe498c56c7 | ||
|
|
251ccef9ba | ||
|
|
3b993fabb6 | ||
|
|
0c56e0de6d | ||
|
|
893ff9c033 | ||
|
|
3c382cac7f | ||
|
|
42e4506b1b | ||
|
|
ae3baadcf9 | ||
|
|
4f29a32da8 | ||
|
|
e5fa54e8e7 | ||
|
|
d3076039d0 | ||
|
|
a748f4d30f | ||
|
|
3ee5536a13 | ||
|
|
f56aacc7ef | ||
|
|
96fa0a96eb | ||
|
|
1754bd0204 | ||
|
|
90a1abf2f8 | ||
|
|
59824d2122 | ||
|
|
31319d9c6f | ||
|
|
e27b65c930 | ||
|
|
b03f9a502a | ||
|
|
44ef20d5ac | ||
|
|
4719b30f16 | ||
|
|
7eb361087a | ||
|
|
33d50e4e30 | ||
|
|
994690cfa3 | ||
|
|
52b2d10887 | ||
|
|
81e0f4dfe5 | ||
|
|
c7cab77fc1 | ||
|
|
a63dcc96d5 | ||
|
|
fab349f356 | ||
|
|
62edf93958 | ||
|
|
8c4ff253cb | ||
|
|
3ce6a15547 | ||
|
|
174aa2c091 | ||
|
|
9efe25b91c | ||
|
|
bcce8876e2 | ||
|
|
3962372f47 | ||
|
|
f67f61c638 | ||
|
|
d5f7f4dfaa | ||
|
|
ce6961d165 | ||
|
|
30e1a68344 | ||
|
|
5b087ed848 | ||
|
|
5d0481b031 | ||
|
|
596d22a449 | ||
|
|
c85f385191 | ||
|
|
eb2aaaaa20 | ||
|
|
e3c009c5b3 | ||
|
|
a4f7293f32 | ||
|
|
8b64312f4b | ||
|
|
b7e27bfdc6 | ||
|
|
37b19674f1 | ||
|
|
a5f4ad507a | ||
|
|
1f96077e36 | ||
|
|
ed26976ac5 | ||
|
|
e4d292b595 | ||
|
|
c6b8430c72 | ||
|
|
cbf1dcca29 | ||
|
|
7f7d099ba0 | ||
|
|
b6f965c1d9 | ||
|
|
fd2875aa3e | ||
|
|
4b2816db64 | ||
|
|
4af3e59174 | ||
|
|
24b1faffde | ||
|
|
49983c8ee7 | ||
|
|
d276c3489e | ||
|
|
3f51e6dcb6 | ||
|
|
b4dbbd667a | ||
|
|
7d9245505f | ||
|
|
570daf2321 | ||
|
|
60d0f84294 | ||
|
|
6633025437 | ||
|
|
40ed353666 | ||
|
|
32bdd8d5c4 | ||
|
|
ec4fc9aec5 | ||
|
|
390611d5c9 | ||
|
|
685052c605 | ||
|
|
4b83f8bfd9 |
10
.git-blame-ignore-revs
Normal file
10
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,10 @@
|
||||
# The commits that did automated reformatting. You can ignore them
|
||||
# during git-blame with `--ignore-rev` or `--ignore-revs-file`.
|
||||
#
|
||||
# $ git config --add 'blame.ignoreRevsFile' '.git-blame-ignore-revs'
|
||||
#
|
||||
|
||||
d1fb1e26f3b79e54febc94496c1184763cf2af3d
|
||||
e4f9935706be4c0e3253afe251c182019ff7ccef
|
||||
65e602d8c72baa7020efb62d10bf28e621feb05d
|
||||
4115ae7ced77d392ee11ea55212206d9404356f0
|
||||
@@ -3,6 +3,7 @@ include:
|
||||
- project: 'wayland/ci-templates'
|
||||
ref: master
|
||||
file: '/templates/fedora.yml'
|
||||
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
|
||||
|
||||
variables:
|
||||
extends: .libfprint_common_variables
|
||||
@@ -60,7 +61,7 @@ test:
|
||||
variables:
|
||||
- $CI_PIPELINE_SOURCE == "schedule"
|
||||
script:
|
||||
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
||||
- meson --werror -Ddrivers=all -Db_coverage=true -Dsdcp_virt_binary=/usr/local/bin/sdcp_virt_device . _build
|
||||
- ninja -C _build
|
||||
- meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3
|
||||
- ninja -C _build coverage
|
||||
@@ -69,6 +70,7 @@ test:
|
||||
paths:
|
||||
- _build/meson-logs
|
||||
expire_in: 1 week
|
||||
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
||||
|
||||
test_valgrind:
|
||||
stage: test
|
||||
@@ -76,7 +78,7 @@ test_valgrind:
|
||||
variables:
|
||||
- $CI_PIPELINE_SOURCE == "schedule"
|
||||
script:
|
||||
- meson -Ddrivers=all . _build
|
||||
- meson -Ddrivers=all -Dsdcp_virt_binary=/usr/local/bin/sdcp_virt_device . _build
|
||||
- ninja -C _build
|
||||
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
|
||||
|
||||
@@ -107,56 +109,37 @@ test_indent:
|
||||
- git diff
|
||||
- "! git status -s | grep -q ."
|
||||
|
||||
.flatpak_script_template: &flatpak_script
|
||||
script:
|
||||
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||
# Make sure to keep this in sync with the Flatpak manifest, all arguments
|
||||
# are passed except the config-args because we build it ourselves
|
||||
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
|
||||
- flatpak build app ninja -C _build install
|
||||
- flatpak build app rm -rf /app/include/ /app/lib/pkgconfig/
|
||||
- flatpak-builder --finish-only --repo=repo app ${MANIFEST_PATH}
|
||||
# Generate a Flatpak bundle
|
||||
- flatpak build-bundle repo ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${DBUS_ID}
|
||||
|
||||
.flatpak_artifacts_template: &flatpak_artifacts
|
||||
artifacts:
|
||||
paths:
|
||||
- ${BUNDLE}
|
||||
when: always
|
||||
expire_in: 30 days
|
||||
|
||||
.flatpak_template: &flatpak
|
||||
<<: *flatpak_script
|
||||
<<: *flatpak_artifacts
|
||||
|
||||
.flatpak_master_template: &flatpak_master
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
|
||||
stage: flatpak
|
||||
test_unsupported_list:
|
||||
stage: check-source
|
||||
except:
|
||||
variables:
|
||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||
# From demo/org.freedesktop.libfprint.Demo.json
|
||||
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
|
||||
FLATPAK_MODULE: "libfprint"
|
||||
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
||||
<<: *flatpak
|
||||
- $CI_PIPELINE_SOURCE == "schedule"
|
||||
allow_failure: true
|
||||
script:
|
||||
- tests/hwdb-check-unsupported.py
|
||||
|
||||
flatpak-auto master:
|
||||
<<: *flatpak_master
|
||||
when: always
|
||||
only:
|
||||
- tags
|
||||
- master
|
||||
|
||||
flatpak-manual master:
|
||||
<<: *flatpak_master
|
||||
when: manual
|
||||
except:
|
||||
refs:
|
||||
- tags
|
||||
- master
|
||||
variables:
|
||||
- $CI_PIPELINE_SOURCE == "schedule"
|
||||
flatpak:
|
||||
stage: flatpak
|
||||
extends: .flatpak
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36
|
||||
variables:
|
||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||
FLATPAK_MODULE: "libfprint"
|
||||
APP_ID: "org.freedesktop.libfprint.Demo"
|
||||
rules:
|
||||
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
|
||||
when: never
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
when: never
|
||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_TAG'
|
||||
when: always
|
||||
# For any other (commit), allow manual run.
|
||||
# This excludes MRs which would create a duplicate pipeline
|
||||
- if: '$CI_COMMIT_BRANCH'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
# CONTAINERS creation stage
|
||||
container_fedora_build:
|
||||
@@ -166,5 +149,17 @@ container_fedora_build:
|
||||
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||
variables:
|
||||
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
||||
# a list of packages to install
|
||||
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES
|
||||
# a list of packages to install; we only include mbedtls here
|
||||
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES mbedtls-devel
|
||||
FDO_DISTRIBUTION_EXEC: |
|
||||
cd /tmp
|
||||
mkdir -p /usr/local/bin
|
||||
git clone https://github.com/benzea/SecureDeviceConnectionProtocol.git
|
||||
# Don't bother with cmake
|
||||
gcc -l mbedcrypto -I SecureDeviceConnectionProtocol/src/include \
|
||||
SecureDeviceConnectionProtocol/src/test/virt_device.c \
|
||||
SecureDeviceConnectionProtocol/src/client/client.c \
|
||||
SecureDeviceConnectionProtocol/src/test/helpers.c \
|
||||
SecureDeviceConnectionProtocol/src/test/testkeys.c \
|
||||
-o /usr/local/bin/sdcp_virt_device
|
||||
rm -rf SecureDeviceConnectionProtocol
|
||||
|
||||
88
NEWS
88
NEWS
@@ -1,6 +1,94 @@
|
||||
This file lists notable changes in each release. For the full history of all
|
||||
changes, see ChangeLog.
|
||||
|
||||
2020-12-01: v1.90.7 release
|
||||
|
||||
Highlights:
|
||||
* vfs5011: Fix possible use-after-free
|
||||
* goodixmoc: Add two new PIDs (0x63AC, 0x639C)
|
||||
* goodixmoc: Support finger status API
|
||||
* synaptics: Only identify within provided prints
|
||||
* synaptics: Reject devices with old firmware during probe (#239)
|
||||
|
||||
|
||||
2020-12-01: v1.90.6 release
|
||||
|
||||
This release is primarily a bugfix release for some older issues.
|
||||
|
||||
The major change is that fp_print_deserialize will now correctly return a
|
||||
sunken reference rather than a floating one. Most API users will have
|
||||
assumed this was true, and issues could happen at a later point.
|
||||
If any API user worked around this libfprint bug, they will now leak the
|
||||
returned print.
|
||||
|
||||
Highlights:
|
||||
* Object reference management fixes for FpPrint and identify
|
||||
* Fixed issues that caused problem on non-x86 machines (#236)
|
||||
* Fix building with older GLib versions
|
||||
* synaptics: Support PID 00e7
|
||||
* goodix: Fix issue with long USB packages
|
||||
|
||||
|
||||
2020-12-01: v1.90.5 release
|
||||
|
||||
The 1.90.4 release caused a major regression, as it included a USB hub in
|
||||
UDEV the autosupend rule list.
|
||||
|
||||
Highlights:
|
||||
* Remove USB hub from udev autosupend rules
|
||||
* synaptics: Add PID 0x00c9 which is used in some HP laptops
|
||||
|
||||
|
||||
2020-11-27: v1.90.4 release
|
||||
|
||||
This release contains a number of important bugfixes. On the feature side,
|
||||
the USB hotplug support was improved. A lot of drivers received fixes and
|
||||
improvements.
|
||||
|
||||
Highlights:
|
||||
* Work around GUsb cancellation issue
|
||||
* Redefine internal image device state machine for more robustness
|
||||
* Add public finger-status reporting to FpDevice
|
||||
* Rework device removal API to be convenient (#330)
|
||||
* Enable powersave for unsupported USB devices
|
||||
* Improvements to examples
|
||||
* synaptics: Support identify operation
|
||||
* synaptics: Fix possible crash when the interrupt transfer is resubmitted
|
||||
* synaptics: Add support for PIDs 0x00f9, 0x00fc and 0x00c2
|
||||
* elan: Add PID 0x0c4d to supported device list
|
||||
* aes3k: Fix driver and add CI test (#306)
|
||||
* uru4000: Fix reference counting of image transfer
|
||||
* vfs301: Fix driver and add CI test (#320)
|
||||
|
||||
2020-06-08: v1.90.3 release
|
||||
|
||||
This release mostly contains support for a number of new match-on-chip
|
||||
devices. Most notable is the addition of the new goodixmoc driver.
|
||||
Currently the driver has the small caveat that we have no strategy to
|
||||
garbage collect old prints yet (a simple strategy could be implemented
|
||||
in fprintd).
|
||||
|
||||
Highlights:
|
||||
* New goodixmoc driver supporting Goodix USB devices:
|
||||
27C6:5840
|
||||
27C6:6496
|
||||
27C6:60A2
|
||||
* Newly added support for Synaptics device:
|
||||
06CB:00E9
|
||||
06CB:00DF
|
||||
* Fixed an issue with Synaptics devices sometimes not working at boot
|
||||
* Fix issue with aes3k driver (#306)
|
||||
|
||||
2020-06-08: v1.90.2 release
|
||||
|
||||
This release contains a large amount of bug and regression fixes. These
|
||||
are not listed explicitly, but affect the majority of drivers.
|
||||
|
||||
Highlights:
|
||||
* A patch for nbis required for some sensors was accidentally dropped in
|
||||
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
|
||||
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
|
||||
|
||||
2019-11-20: v1.90.1 release
|
||||
|
||||
This release fixes a lot of the regressions introduced in 1.90.0. Please note
|
||||
|
||||
264
data/autosuspend.hwdb
Normal file
264
data/autosuspend.hwdb
Normal file
@@ -0,0 +1,264 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# This file has been generated using fprint-list-udev-hwdb with all drivers enabled
|
||||
|
||||
# Supported by libfprint driver aes1610
|
||||
usb:v08FFp1600*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes1660
|
||||
usb:v08FFp1660*
|
||||
usb:v08FFp1680*
|
||||
usb:v08FFp1681*
|
||||
usb:v08FFp1682*
|
||||
usb:v08FFp1683*
|
||||
usb:v08FFp1684*
|
||||
usb:v08FFp1685*
|
||||
usb:v08FFp1686*
|
||||
usb:v08FFp1687*
|
||||
usb:v08FFp1688*
|
||||
usb:v08FFp1689*
|
||||
usb:v08FFp168A*
|
||||
usb:v08FFp168B*
|
||||
usb:v08FFp168C*
|
||||
usb:v08FFp168D*
|
||||
usb:v08FFp168E*
|
||||
usb:v08FFp168F*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes2501
|
||||
usb:v08FFp2500*
|
||||
usb:v08FFp2580*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes2550
|
||||
usb:v08FFp2550*
|
||||
usb:v08FFp2810*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes2660
|
||||
usb:v08FFp2660*
|
||||
usb:v08FFp2680*
|
||||
usb:v08FFp2681*
|
||||
usb:v08FFp2682*
|
||||
usb:v08FFp2683*
|
||||
usb:v08FFp2684*
|
||||
usb:v08FFp2685*
|
||||
usb:v08FFp2686*
|
||||
usb:v08FFp2687*
|
||||
usb:v08FFp2688*
|
||||
usb:v08FFp2689*
|
||||
usb:v08FFp268A*
|
||||
usb:v08FFp268B*
|
||||
usb:v08FFp268C*
|
||||
usb:v08FFp268D*
|
||||
usb:v08FFp268E*
|
||||
usb:v08FFp268F*
|
||||
usb:v08FFp2691*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes3500
|
||||
usb:v08FFp5731*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver aes4000
|
||||
usb:v5501p08FF*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver elan
|
||||
usb:v04F3p0903*
|
||||
usb:v04F3p0907*
|
||||
usb:v04F3p0C01*
|
||||
usb:v04F3p0C02*
|
||||
usb:v04F3p0C03*
|
||||
usb:v04F3p0C04*
|
||||
usb:v04F3p0C05*
|
||||
usb:v04F3p0C06*
|
||||
usb:v04F3p0C07*
|
||||
usb:v04F3p0C08*
|
||||
usb:v04F3p0C09*
|
||||
usb:v04F3p0C0A*
|
||||
usb:v04F3p0C0B*
|
||||
usb:v04F3p0C0C*
|
||||
usb:v04F3p0C0D*
|
||||
usb:v04F3p0C0E*
|
||||
usb:v04F3p0C0F*
|
||||
usb:v04F3p0C10*
|
||||
usb:v04F3p0C11*
|
||||
usb:v04F3p0C12*
|
||||
usb:v04F3p0C13*
|
||||
usb:v04F3p0C14*
|
||||
usb:v04F3p0C15*
|
||||
usb:v04F3p0C16*
|
||||
usb:v04F3p0C17*
|
||||
usb:v04F3p0C18*
|
||||
usb:v04F3p0C19*
|
||||
usb:v04F3p0C1A*
|
||||
usb:v04F3p0C1B*
|
||||
usb:v04F3p0C1C*
|
||||
usb:v04F3p0C1D*
|
||||
usb:v04F3p0C1E*
|
||||
usb:v04F3p0C1F*
|
||||
usb:v04F3p0C20*
|
||||
usb:v04F3p0C21*
|
||||
usb:v04F3p0C22*
|
||||
usb:v04F3p0C23*
|
||||
usb:v04F3p0C24*
|
||||
usb:v04F3p0C25*
|
||||
usb:v04F3p0C26*
|
||||
usb:v04F3p0C27*
|
||||
usb:v04F3p0C28*
|
||||
usb:v04F3p0C29*
|
||||
usb:v04F3p0C2A*
|
||||
usb:v04F3p0C2B*
|
||||
usb:v04F3p0C2C*
|
||||
usb:v04F3p0C2D*
|
||||
usb:v04F3p0C2E*
|
||||
usb:v04F3p0C2F*
|
||||
usb:v04F3p0C30*
|
||||
usb:v04F3p0C31*
|
||||
usb:v04F3p0C32*
|
||||
usb:v04F3p0C33*
|
||||
usb:v04F3p0C42*
|
||||
usb:v04F3p0C4D*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver etes603
|
||||
usb:v1C7Ap0603*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver goodixmoc
|
||||
usb:v27C6p5840*
|
||||
usb:v27C6p6496*
|
||||
usb:v27C6p60A2*
|
||||
usb:v27C6p63AC*
|
||||
usb:v27C6p639C*
|
||||
usb:v27C6p6594*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver synaptics
|
||||
usb:v06CBp00BD*
|
||||
usb:v06CBp00E9*
|
||||
usb:v06CBp00DF*
|
||||
usb:v06CBp00F9*
|
||||
usb:v06CBp00FC*
|
||||
usb:v06CBp00C2*
|
||||
usb:v06CBp00C9*
|
||||
usb:v06CBp00E7*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver upeksonly
|
||||
usb:v147Ep2016*
|
||||
usb:v147Ep1000*
|
||||
usb:v147Ep1001*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver upektc
|
||||
usb:v0483p2015*
|
||||
usb:v147Ep3001*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver upektc_img
|
||||
usb:v147Ep2020*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver uru4000
|
||||
usb:v045Ep00BC*
|
||||
usb:v045Ep00BD*
|
||||
usb:v045Ep00CA*
|
||||
usb:v05BAp0007*
|
||||
usb:v05BAp0008*
|
||||
usb:v05BAp000A*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver vcom5s
|
||||
usb:v061Ap0110*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver vfs0050
|
||||
usb:v138Ap0050*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver vfs101
|
||||
usb:v138Ap0001*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver vfs301
|
||||
usb:v138Ap0005*
|
||||
usb:v138Ap0008*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Supported by libfprint driver vfs5011
|
||||
usb:v138Ap0010*
|
||||
usb:v138Ap0011*
|
||||
usb:v138Ap0015*
|
||||
usb:v138Ap0017*
|
||||
usb:v138Ap0018*
|
||||
ID_AUTOSUSPEND=1
|
||||
|
||||
# Known unsupported devices
|
||||
usb:v04F3p036B*
|
||||
usb:v04F3p0C00*
|
||||
usb:v04F3p0C4B*
|
||||
usb:v04F3p0C4C*
|
||||
usb:v04F3p0C4F*
|
||||
usb:v04F3p0C57*
|
||||
usb:v04F3p2706*
|
||||
usb:v06CBp0081*
|
||||
usb:v06CBp0088*
|
||||
usb:v06CBp008A*
|
||||
usb:v06CBp009A*
|
||||
usb:v06CBp009B*
|
||||
usb:v06CBp00A2*
|
||||
usb:v06CBp00B7*
|
||||
usb:v06CBp00BB*
|
||||
usb:v06CBp00BE*
|
||||
usb:v06CBp00CB*
|
||||
usb:v06CBp00D8*
|
||||
usb:v06CBp00DA*
|
||||
usb:v0A5Cp5801*
|
||||
usb:v0A5Cp5805*
|
||||
usb:v0A5Cp5834*
|
||||
usb:v0A5Cp5843*
|
||||
usb:v10A5p0007*
|
||||
usb:v1188p9545*
|
||||
usb:v138Ap0007*
|
||||
usb:v138Ap003A*
|
||||
usb:v138Ap003C*
|
||||
usb:v138Ap003D*
|
||||
usb:v138Ap003F*
|
||||
usb:v138Ap0090*
|
||||
usb:v138Ap0091*
|
||||
usb:v138Ap0092*
|
||||
usb:v138Ap0094*
|
||||
usb:v138Ap0097*
|
||||
usb:v138Ap009D*
|
||||
usb:v138Ap00AB*
|
||||
usb:v147Ep1002*
|
||||
usb:v1491p0088*
|
||||
usb:v16D1p1027*
|
||||
usb:v1C7Ap0300*
|
||||
usb:v1C7Ap0570*
|
||||
usb:v1C7Ap0575*
|
||||
usb:v27C6p5042*
|
||||
usb:v27C6p5110*
|
||||
usb:v27C6p5117*
|
||||
usb:v27C6p5201*
|
||||
usb:v27C6p521D*
|
||||
usb:v27C6p5301*
|
||||
usb:v27C6p530C*
|
||||
usb:v27C6p532D*
|
||||
usb:v27C6p533C*
|
||||
usb:v27C6p5381*
|
||||
usb:v27C6p5385*
|
||||
usb:v27C6p538C*
|
||||
usb:v27C6p538D*
|
||||
usb:v27C6p5395*
|
||||
usb:v27C6p5584*
|
||||
usb:v27C6p55A2*
|
||||
usb:v27C6p55A4*
|
||||
usb:v27C6p55B4*
|
||||
usb:v27C6p5740*
|
||||
usb:v2808p9338*
|
||||
usb:v298Dp2033*
|
||||
usb:v3538p0930*
|
||||
ID_AUTOSUSPEND=1
|
||||
9
data/meson.build
Normal file
9
data/meson.build
Normal file
@@ -0,0 +1,9 @@
|
||||
if get_option('udev_rules')
|
||||
# This file has to be updated using
|
||||
# ninja -C <builddir> libfprint/sync-udev-hwdb
|
||||
|
||||
install_data('autosuspend.hwdb',
|
||||
rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname),
|
||||
install_dir: udev_hwdb_dir,
|
||||
)
|
||||
endif
|
||||
@@ -241,6 +241,8 @@ dev_capture_start_cb (FpDevice *dev,
|
||||
if (error->domain == FP_DEVICE_RETRY ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
libfprint_demo_set_mode (win, RETRY_MODE);
|
||||
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
||||
libfprint_demo_set_mode (win, NOIMAGING_MODE);
|
||||
else
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"app-id": "org.freedesktop.libfprint.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "3.32",
|
||||
"runtime-version": "3.36",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk-libfprint-test",
|
||||
"finish-args": [
|
||||
|
||||
@@ -85,14 +85,18 @@ FP_TYPE_IMAGE_DEVICE
|
||||
FpImageDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-sdcp-device</FILE>
|
||||
FP_TYPE_SDCP_DEVICE
|
||||
FpSdcpDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-print</FILE>
|
||||
FP_TYPE_PRINT
|
||||
FpFinger
|
||||
FpPrint
|
||||
fp_print_new
|
||||
fp_print_new_from_data
|
||||
fp_print_to_data
|
||||
fp_print_get_driver
|
||||
fp_print_get_device_id
|
||||
fp_print_get_device_stored
|
||||
@@ -188,6 +192,26 @@ fpi_image_device_image_captured
|
||||
fpi_image_device_retry_scan
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-sdcp-device</FILE>
|
||||
<TITLE>Internal FpSdcpDevice</TITLE>
|
||||
FpiSdcpClaim
|
||||
FpSdcpDeviceClass
|
||||
fpi_sdcp_claim_copy
|
||||
fpi_sdcp_claim_free
|
||||
fpi_sdcp_claim_get_type
|
||||
fpi_sdcp_claim_new
|
||||
fpi_sdcp_device_connect_complete
|
||||
fpi_sdcp_device_get_connect_data
|
||||
fpi_sdcp_device_get_reconnect_data
|
||||
fpi_sdcp_device_reconnect_complete
|
||||
fpi_sdcp_device_enroll_commit_complete
|
||||
fpi_sdcp_device_enroll_ready
|
||||
fpi_sdcp_device_enroll_set_nonce
|
||||
fpi_sdcp_device_identify_retry
|
||||
fpi_sdcp_device_identify_complete
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-log</FILE>
|
||||
fp_dbg
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<xi:include href="xml/fp-context.xml"/>
|
||||
<xi:include href="xml/fp-device.xml"/>
|
||||
<xi:include href="xml/fp-image-device.xml"/>
|
||||
<xi:include href="xml/fp-sdcp-device.xml"/>
|
||||
<xi:include href="xml/fp-print.xml"/>
|
||||
<xi:include href="xml/fp-image.xml"/>
|
||||
</part>
|
||||
@@ -38,6 +39,7 @@
|
||||
<title>Device methods for drivers</title>
|
||||
<xi:include href="xml/fpi-device.xml"/>
|
||||
<xi:include href="xml/fpi-image-device.xml"/>
|
||||
<xi:include href="xml/fpi-sdcp-device.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-helpers">
|
||||
|
||||
@@ -57,7 +57,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
g_warning ("Failed closing device %s", error->message);
|
||||
|
||||
g_main_loop_quit (enroll_data->loop);
|
||||
}
|
||||
@@ -76,20 +76,24 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
enroll_data->ret_value = EXIT_SUCCESS;
|
||||
|
||||
if (!fp_device_has_storage (dev))
|
||||
if (fp_device_has_storage (dev))
|
||||
g_debug ("Device has storage, saving a print reference locally");
|
||||
else
|
||||
g_debug ("Device has not storage, saving print only locally");
|
||||
|
||||
/* Even if the device has storage, it may not be able to save all the
|
||||
* metadata that the print contains, so we can always save a local copy
|
||||
* containing the handle to the device print */
|
||||
int r = print_data_save (print, enroll_data->finger);
|
||||
if (r < 0)
|
||||
{
|
||||
g_debug ("Device has not storage, saving locally");
|
||||
int r = print_data_save (print, enroll_data->finger);
|
||||
if (r < 0)
|
||||
{
|
||||
g_warning ("Data save failed, code %d", r);
|
||||
enroll_data->ret_value = EXIT_FAILURE;
|
||||
}
|
||||
g_warning ("Data save failed, code %d", r);
|
||||
enroll_data->ret_value = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Enroll failed with error %s\n", error->message);
|
||||
g_warning ("Enroll failed with error %s", error->message);
|
||||
}
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||
@@ -112,7 +116,7 @@ on_enroll_progress (FpDevice *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp_device_supports_capture (device) &&
|
||||
if (print && fp_print_get_image (print) &&
|
||||
print_image_save (print, "enrolled.pgm"))
|
||||
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||
|
||||
|
||||
319
examples/identify.c
Normal file
319
examples/identify.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Example fingerprint verification program, which verifies the
|
||||
* finger which has been previously enrolled to disk.
|
||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "example-identify"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libfprint/fprint.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "storage.h"
|
||||
#include "utilities.h"
|
||||
|
||||
typedef struct _IdentifyData
|
||||
{
|
||||
GMainLoop *loop;
|
||||
GCancellable *cancellable;
|
||||
unsigned int sigint_handler;
|
||||
int ret_value;
|
||||
} IdentifyData;
|
||||
|
||||
static void
|
||||
identify_data_free (IdentifyData *identify_data)
|
||||
{
|
||||
g_clear_handle_id (&identify_data->sigint_handler, g_source_remove);
|
||||
g_clear_object (&identify_data->cancellable);
|
||||
g_main_loop_unref (identify_data->loop);
|
||||
g_free (identify_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdentifyData, identify_data_free)
|
||||
|
||||
static void
|
||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s", error->message);
|
||||
|
||||
g_main_loop_quit (identify_data->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
identify_quit (FpDevice *dev,
|
||||
IdentifyData *identify_data)
|
||||
{
|
||||
if (!fp_device_is_open (dev))
|
||||
{
|
||||
g_main_loop_quit (identify_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, identify_data);
|
||||
}
|
||||
|
||||
static void start_identification (FpDevice *dev,
|
||||
IdentifyData *identify_data);
|
||||
|
||||
static void
|
||||
on_identify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
g_autoptr(FpPrint) match = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
char buffer[20];
|
||||
|
||||
if (!fp_device_identify_finish (dev, res, &match, &print, &error))
|
||||
{
|
||||
g_warning ("Failed to identify print: %s", error->message);
|
||||
identify_data->ret_value = EXIT_FAILURE;
|
||||
|
||||
if (error->domain != FP_DEVICE_RETRY)
|
||||
{
|
||||
identify_quit (dev, identify_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_print ("Identify again? [Y/n]? ");
|
||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
||||
{
|
||||
start_identification (dev, identify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
identify_quit (dev, identify_data);
|
||||
}
|
||||
|
||||
static FpPrint *
|
||||
get_stored_print (FpDevice *dev, FpPrint *print)
|
||||
{
|
||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
||||
guint index;
|
||||
|
||||
if (g_ptr_array_find_with_equal_func (gallery, print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index))
|
||||
return g_object_ref (g_ptr_array_index (gallery, index));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Identify report: No finger matched, retry error reported: %s",
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (print && fp_print_get_image (print) &&
|
||||
print_image_save (print, "identify.pgm"))
|
||||
g_print ("Print image saved as identify.pgm\n");
|
||||
|
||||
if (match)
|
||||
{
|
||||
g_autoptr(FpPrint) matched_print = g_object_ref (match);
|
||||
char date_str[128] = {};
|
||||
|
||||
identify_data->ret_value = EXIT_SUCCESS;
|
||||
|
||||
if (fp_print_get_device_stored (match))
|
||||
{
|
||||
FpPrint *stored_print = get_stored_print (dev, match);
|
||||
|
||||
if (stored_print)
|
||||
matched_print = g_steal_pointer (&stored_print);
|
||||
}
|
||||
|
||||
if (fp_print_get_enroll_date (matched_print))
|
||||
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
||||
fp_print_get_enroll_date (matched_print));
|
||||
else
|
||||
strcpy (date_str, "<unknown>");
|
||||
|
||||
g_debug ("Identify report: device %s matched finger %s successfully "
|
||||
"with print '%s', enrolled on date %s by user %s",
|
||||
fp_device_get_name (dev),
|
||||
finger_to_string (fp_print_get_finger (matched_print)),
|
||||
fp_print_get_description (matched_print), date_str,
|
||||
fp_print_get_username (matched_print));
|
||||
|
||||
g_print ("IDENTIFIED!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Identification report: No finger matched");
|
||||
g_print ("NOT IDENTIFIED!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
g_autoptr(GPtrArray) gallery = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
gallery = fp_device_list_prints_finish (dev, res, &error);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if (!gallery->len)
|
||||
{
|
||||
g_warning ("No prints saved on device");
|
||||
identify_quit (dev, identify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_debug ("Identifying with %u prints in gallery", gallery->len);
|
||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
||||
on_identify_cb, identify_data, NULL,
|
||||
(GAsyncReadyCallback) on_identify_completed,
|
||||
identify_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Loading prints failed with error %s", error->message);
|
||||
identify_quit (dev, identify_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_identification (FpDevice *dev, IdentifyData *identify_data)
|
||||
{
|
||||
if (fp_device_has_storage (dev))
|
||||
{
|
||||
g_print ("Creating finger template, using device storage...\n");
|
||||
fp_device_list_prints (dev, NULL,
|
||||
(GAsyncReadyCallback) on_list_completed,
|
||||
identify_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
||||
|
||||
if (!gallery)
|
||||
{
|
||||
identify_quit (dev, identify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Gallery loaded. Time to identify!\n");
|
||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
||||
on_identify_cb, identify_data, NULL,
|
||||
(GAsyncReadyCallback) on_identify_completed,
|
||||
identify_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
identify_quit (dev, identify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Opened device. ");
|
||||
|
||||
start_identification (dev, identify_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sigint_cb (void *user_data)
|
||||
{
|
||||
IdentifyData *identify_data = user_data;
|
||||
|
||||
g_cancellable_cancel (identify_data->cancellable);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
g_autoptr(FpContext) ctx = NULL;
|
||||
g_autoptr(IdentifyData) identify_data = NULL;
|
||||
GPtrArray *devices;
|
||||
FpDevice *dev;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
ctx = fp_context_new ();
|
||||
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
g_warning ("Impossible to get devices");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev = discover_device (devices);
|
||||
if (!dev)
|
||||
{
|
||||
g_warning ("No devices detected.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!fp_device_supports_identify (dev))
|
||||
{
|
||||
g_warning ("Device %s does not support identification.",
|
||||
fp_device_get_name (dev));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
identify_data = g_new0 (IdentifyData, 1);
|
||||
identify_data->ret_value = EXIT_FAILURE;
|
||||
identify_data->loop = g_main_loop_new (NULL, FALSE);
|
||||
identify_data->cancellable = g_cancellable_new ();
|
||||
identify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
||||
SIGINT,
|
||||
sigint_cb,
|
||||
identify_data,
|
||||
NULL);
|
||||
fp_device_open (dev, identify_data->cancellable,
|
||||
(GAsyncReadyCallback) on_device_opened,
|
||||
identify_data);
|
||||
|
||||
g_main_loop_run (identify_data->loop);
|
||||
|
||||
return identify_data->ret_value;
|
||||
}
|
||||
192
examples/img-capture.c
Normal file
192
examples/img-capture.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Example fingerprint verification program, which verifies the
|
||||
* finger which has been previously enrolled to disk.
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
* Copyright (C) 2020 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "example-capture"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libfprint/fprint.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "storage.h"
|
||||
#include "utilities.h"
|
||||
|
||||
typedef struct CaptureData
|
||||
{
|
||||
GMainLoop *loop;
|
||||
GCancellable *cancellable;
|
||||
unsigned int sigint_handler;
|
||||
int ret_value;
|
||||
const char *filename;
|
||||
} CaptureData;
|
||||
|
||||
static void
|
||||
capture_data_free (CaptureData *capture_data)
|
||||
{
|
||||
g_clear_handle_id (&capture_data->sigint_handler, g_source_remove);
|
||||
g_clear_object (&capture_data->cancellable);
|
||||
g_main_loop_unref (capture_data->loop);
|
||||
g_free (capture_data);
|
||||
}
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CaptureData, capture_data_free)
|
||||
|
||||
static void
|
||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
CaptureData *capture_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s", error->message);
|
||||
|
||||
g_main_loop_quit (capture_data->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
capture_quit (FpDevice *dev,
|
||||
CaptureData *capture_data)
|
||||
{
|
||||
if (!fp_device_is_open (dev))
|
||||
{
|
||||
g_main_loop_quit (capture_data->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, capture_data);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_capture_cb (FpDevice *dev,
|
||||
GAsyncResult *res,
|
||||
void *user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
CaptureData *capture_data = user_data;
|
||||
FpImage *image = NULL;
|
||||
|
||||
g_clear_object (&capture_data->cancellable);
|
||||
|
||||
image = fp_device_capture_finish (dev, res, &error);
|
||||
if (!image)
|
||||
{
|
||||
g_warning ("Error capturing data: %s", error->message);
|
||||
capture_quit (dev, capture_data);
|
||||
return;
|
||||
}
|
||||
|
||||
save_image_to_pgm (image, capture_data->filename);
|
||||
|
||||
capture_quit (dev, capture_data);
|
||||
}
|
||||
|
||||
static void
|
||||
start_capture (FpDevice *dev, CaptureData *capture_data)
|
||||
{
|
||||
fp_device_capture (dev, TRUE, capture_data->cancellable, (GAsyncReadyCallback) dev_capture_cb, capture_data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
{
|
||||
CaptureData *capture_data = user_data;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
if (!fp_device_open_finish (dev, res, &error))
|
||||
{
|
||||
g_warning ("Failed to open device: %s", error->message);
|
||||
capture_quit (dev, capture_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Opened device. ");
|
||||
|
||||
start_capture (dev, capture_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sigint_cb (void *user_data)
|
||||
{
|
||||
CaptureData *capture_data = user_data;
|
||||
|
||||
g_cancellable_cancel (capture_data->cancellable);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
g_autoptr(FpContext) ctx = NULL;
|
||||
g_autoptr(CaptureData) capture_data = NULL;
|
||||
GPtrArray *devices;
|
||||
FpDevice *dev;
|
||||
|
||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||
|
||||
ctx = fp_context_new ();
|
||||
|
||||
devices = fp_context_get_devices (ctx);
|
||||
if (!devices)
|
||||
{
|
||||
g_warning ("Impossible to get devices");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dev = discover_device (devices);
|
||||
if (!dev)
|
||||
{
|
||||
g_warning ("No devices detected.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!fp_device_supports_capture (dev))
|
||||
{
|
||||
g_warning ("Device %s doesn't support capture",
|
||||
fp_device_get_name (dev));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
capture_data = g_new0 (CaptureData, 1);
|
||||
capture_data->ret_value = EXIT_FAILURE;
|
||||
capture_data->loop = g_main_loop_new (NULL, FALSE);
|
||||
capture_data->cancellable = g_cancellable_new ();
|
||||
capture_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
||||
SIGINT,
|
||||
sigint_cb,
|
||||
capture_data,
|
||||
NULL);
|
||||
if (argc == 2)
|
||||
capture_data->filename = argv[1];
|
||||
else
|
||||
capture_data->filename = "finger.pgm";
|
||||
fp_device_open (dev, capture_data->cancellable,
|
||||
(GAsyncReadyCallback) on_device_opened,
|
||||
capture_data);
|
||||
|
||||
g_main_loop_run (capture_data->loop);
|
||||
|
||||
return capture_data->ret_value;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ on_device_closed (FpDevice *dev,
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
g_warning ("Failed closing device %s", error->message);
|
||||
|
||||
g_main_loop_quit (list_data->loop);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ delete_next_print (FpDevice *dev,
|
||||
g_assert_nonnull (list_data->to_delete);
|
||||
print = list_data->to_delete->data;
|
||||
|
||||
g_debug ("Deleting print %s\n", fp_print_get_description (print));
|
||||
g_debug ("Deleting print %s", fp_print_get_description (print));
|
||||
fp_device_delete_print (dev, print, NULL,
|
||||
(GAsyncReadyCallback) on_print_deleted, list_data);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
|
||||
examples = [ 'enroll', 'verify', 'manage-prints' ]
|
||||
examples = [
|
||||
'enroll',
|
||||
'identify',
|
||||
'img-capture',
|
||||
'manage-prints',
|
||||
'verify',
|
||||
]
|
||||
|
||||
foreach example: examples
|
||||
executable(example,
|
||||
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Trivial storage driver for example programs
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
* Copyright (C) 2019-2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -160,6 +160,52 @@ print_data_load (FpDevice *dev, FpFinger finger)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
gallery_data_load (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GVariantDict) dict = NULL;
|
||||
g_autoptr(GVariant) dict_variant = NULL;
|
||||
g_autofree char *dev_prefix = NULL;
|
||||
GPtrArray *gallery;
|
||||
const char *driver;
|
||||
const char *dev_id;
|
||||
GVariantIter iter;
|
||||
GVariant *value;
|
||||
gchar *key;
|
||||
|
||||
gallery = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
dict = load_data ();
|
||||
dict_variant = g_variant_dict_end (dict);
|
||||
driver = fp_device_get_driver (dev);
|
||||
dev_id = fp_device_get_device_id (dev);
|
||||
dev_prefix = g_strdup_printf ("%s/%s/", driver, dev_id);
|
||||
|
||||
g_variant_iter_init (&iter, dict_variant);
|
||||
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
||||
{
|
||||
FpPrint *print;
|
||||
const guchar *stored_data;
|
||||
g_autoptr(GError) error = NULL;
|
||||
gsize stored_len;
|
||||
|
||||
if (!g_str_has_prefix (key, dev_prefix))
|
||||
continue;
|
||||
|
||||
stored_data = (const guchar *) g_variant_get_fixed_array (value, &stored_len, 1);
|
||||
print = fp_print_deserialize (stored_data, stored_len, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Error deserializing data: %s", error->message);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_ptr_array_add (gallery, print);
|
||||
}
|
||||
|
||||
return gallery;
|
||||
}
|
||||
|
||||
FpPrint *
|
||||
print_create_template (FpDevice *dev, FpFinger finger)
|
||||
{
|
||||
@@ -180,7 +226,7 @@ print_create_template (FpDevice *dev, FpFinger finger)
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gboolean
|
||||
save_image_to_pgm (FpImage *img, const char *path)
|
||||
{
|
||||
FILE *fd = fopen (path, "w");
|
||||
|
||||
@@ -24,7 +24,10 @@ int print_data_save (FpPrint *print,
|
||||
FpFinger finger);
|
||||
FpPrint * print_data_load (FpDevice *dev,
|
||||
FpFinger finger);
|
||||
GPtrArray * gallery_data_load (FpDevice *dev);
|
||||
FpPrint * print_create_template (FpDevice *dev,
|
||||
FpFinger finger);
|
||||
gboolean print_image_save (FpPrint *print,
|
||||
const char *path);
|
||||
gboolean save_image_to_pgm (FpImage *img,
|
||||
const char *path);
|
||||
|
||||
@@ -57,7 +57,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
fp_device_close_finish (dev, res, &error);
|
||||
|
||||
if (error)
|
||||
g_warning ("Failed closing device %s\n", error->message);
|
||||
g_warning ("Failed closing device %s", error->message);
|
||||
|
||||
g_main_loop_quit (verify_data->loop);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||
return;
|
||||
}
|
||||
|
||||
if (print && fp_device_supports_capture (dev) &&
|
||||
if (print && fp_print_get_image (print) &&
|
||||
print_image_save (print, "verify.pgm"))
|
||||
g_print ("Print image saved as verify.pgm\n");
|
||||
|
||||
@@ -152,6 +152,26 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||
}
|
||||
}
|
||||
|
||||
static FpPrint *
|
||||
get_stored_print (FpDevice *dev, VerifyData *verify_data)
|
||||
{
|
||||
FpPrint *verify_print;
|
||||
|
||||
g_print ("Loading previously enrolled %s finger data...\n",
|
||||
finger_to_string (verify_data->finger));
|
||||
|
||||
verify_print = print_data_load (dev, verify_data->finger);
|
||||
|
||||
if (!verify_print)
|
||||
{
|
||||
g_warning ("Failed to load fingerprint data");
|
||||
g_warning ("Did you remember to enroll your %s finger first?",
|
||||
finger_to_string (verify_data->finger));
|
||||
}
|
||||
|
||||
return verify_print;
|
||||
}
|
||||
|
||||
static void
|
||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
@@ -165,15 +185,27 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||
if (!error)
|
||||
{
|
||||
FpPrint *verify_print = NULL;
|
||||
g_autoptr(FpPrint) stored_print = NULL;
|
||||
guint i;
|
||||
|
||||
if (!prints->len)
|
||||
g_warning ("No prints saved on device");
|
||||
{
|
||||
g_warning ("No prints saved on device");
|
||||
verify_quit (dev, verify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
stored_print = get_stored_print (dev, verify_data);
|
||||
|
||||
for (i = 0; i < prints->len; ++i)
|
||||
{
|
||||
FpPrint *print = prints->pdata[i];
|
||||
|
||||
if (stored_print && fp_print_equal (stored_print, print))
|
||||
/* If the private print data matches, let's use the stored print
|
||||
* as it contains more metadata to show */
|
||||
print = stored_print;
|
||||
|
||||
if (fp_print_get_finger (print) == verify_data->finger &&
|
||||
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
||||
{
|
||||
@@ -191,8 +223,6 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||
|
||||
if (!verify_print)
|
||||
{
|
||||
g_warning ("Did you remember to enroll your %s finger first?",
|
||||
finger_to_string (verify_data->finger));
|
||||
verify_quit (dev, verify_data);
|
||||
return;
|
||||
}
|
||||
@@ -239,24 +269,17 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Loading previously enrolled %s finger data...\n",
|
||||
finger_to_string (verify_data->finger));
|
||||
g_autoptr(FpPrint) verify_print = NULL;
|
||||
|
||||
verify_print = print_data_load (dev, verify_data->finger);
|
||||
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
|
||||
|
||||
if (!verify_print)
|
||||
{
|
||||
g_warning ("Failed to load fingerprint data");
|
||||
g_warning ("Did you remember to enroll your %s finger first?",
|
||||
finger_to_string (verify_data->finger));
|
||||
verify_quit (dev, verify_data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_print ("Print loaded. Time to verify!\n");
|
||||
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||
NULL, NULL, NULL,
|
||||
on_match_cb, verify_data, NULL,
|
||||
(GAsyncReadyCallback) on_verify_completed,
|
||||
verify_data);
|
||||
}
|
||||
|
||||
@@ -135,10 +135,8 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
||||
size_t bytes)
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||
unsigned char *data;
|
||||
|
||||
data = g_malloc (bytes);
|
||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
|
||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#define AES1660_FRAME_SIZE 0x244
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
||||
*/
|
||||
|
||||
@@ -197,12 +197,12 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
|
||||
|
||||
if (data[0] != AES2550_EDATA_MAGIC)
|
||||
{
|
||||
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
|
||||
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
|
||||
return FALSE;
|
||||
}
|
||||
len = data[1] * 256 + data[2];
|
||||
if (len != (AES2550_STRIP_SIZE - 3))
|
||||
fp_dbg ("Bogus frame len: %.4x\n", len);
|
||||
fp_dbg ("Bogus frame len: %.4x", len);
|
||||
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
||||
stripe->delta_x = (int8_t) data[6];
|
||||
stripe->delta_y = -(int8_t) data[7];
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#define AES2660_FRAME_SIZE 0x354
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
||||
*/
|
||||
|
||||
@@ -106,7 +106,9 @@ static struct aes_regwrite init_reqs[] = {
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct aes_regwrite capture_reqs[] = {
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
@@ -155,4 +157,6 @@ fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||
aes_class->init_reqs = init_reqs;
|
||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||
aes_class->capture_reqs = capture_reqs;
|
||||
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
||||
}
|
||||
|
||||
@@ -42,8 +42,10 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FpiUsbTransfer *img_trf;
|
||||
gboolean deactivating;
|
||||
/* This is used both as a flag that we are in a capture operation
|
||||
* and for cancellation.
|
||||
*/
|
||||
GCancellable *img_capture_cancel;
|
||||
} FpiDeviceAes3kPrivate;
|
||||
|
||||
#define CTRL_TIMEOUT 1000
|
||||
@@ -84,7 +86,8 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
FpImage *img;
|
||||
int i;
|
||||
|
||||
priv->img_trf = NULL;
|
||||
/* Image capture operation is finished (error/completed) */
|
||||
g_clear_object (&priv->img_capture_cancel);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -92,14 +95,14 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
/* Deactivation was completed. */
|
||||
/* Cancellation implies we are deactivating. */
|
||||
g_error_free (error);
|
||||
if (priv->deactivating)
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_image_device_report_finger_status (dev, TRUE);
|
||||
@@ -123,43 +126,69 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
fpi_image_device_image_captured (dev, img);
|
||||
|
||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||
* it really has, then restart the capture */
|
||||
* it really has. */
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
|
||||
do_capture (dev);
|
||||
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
|
||||
}
|
||||
|
||||
static void
|
||||
do_capture (FpImageDevice *dev)
|
||||
{
|
||||
g_autoptr(FpiUsbTransfer) img_trf = NULL;
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
|
||||
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
|
||||
priv->img_trf->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (priv->img_trf, 0,
|
||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
|
||||
img_trf->short_is_error = TRUE;
|
||||
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
|
||||
priv->img_capture_cancel,
|
||||
img_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||
{
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
|
||||
if (result)
|
||||
{
|
||||
g_clear_object (&priv->img_capture_cancel);
|
||||
fpi_image_device_session_error (dev, result);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: we never cancel a pending capture. So we are likely leaving the
|
||||
* hardware in a bad state should we abort the capture operation and the
|
||||
* user does not touch the device.
|
||||
* But, we don't know how we might cancel, so just leave it as is. */
|
||||
do_capture (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
do_capture_start (FpImageDevice *dev)
|
||||
{
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
|
||||
aes_write_regv (dev, cls->capture_reqs, cls->capture_reqs_len, capture_reqs_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||
{
|
||||
fpi_image_device_activate_complete (dev, result);
|
||||
if (!result)
|
||||
do_capture (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
aes3k_dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||
|
||||
priv->deactivating = FALSE;
|
||||
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||
}
|
||||
|
||||
@@ -169,10 +198,26 @@ aes3k_dev_deactivate (FpImageDevice *dev)
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
|
||||
priv->deactivating = TRUE;
|
||||
if (priv->img_trf)
|
||||
return;
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
/* If a capture is running, then deactivation finishes from the cancellation handler */
|
||||
if (priv->img_capture_cancel)
|
||||
g_cancellable_cancel (priv->img_capture_cancel);
|
||||
else
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
aes3k_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||
{
|
||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||
|
||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
{
|
||||
g_assert (!priv->img_capture_cancel);
|
||||
priv->img_capture_cancel = g_cancellable_new ();
|
||||
|
||||
do_capture_start (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -217,6 +262,7 @@ fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||
img_class->img_open = aes3k_dev_init;
|
||||
img_class->img_close = aes3k_dev_deinit;
|
||||
img_class->activate = aes3k_dev_activate;
|
||||
img_class->change_state = aes3k_dev_change_state;
|
||||
img_class->deactivate = aes3k_dev_deactivate;
|
||||
|
||||
/* Extremely low due to low image quality. */
|
||||
|
||||
@@ -57,4 +57,6 @@ struct _FpiDeviceAes3kClass
|
||||
gsize data_buflen; /* buffer length of usb bulk transfer */
|
||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||
gsize init_reqs_len;
|
||||
struct aes_regwrite *capture_reqs; /* capture values sent to device */
|
||||
gsize capture_reqs_len;
|
||||
};
|
||||
|
||||
@@ -103,7 +103,9 @@ static struct aes_regwrite init_reqs[] = {
|
||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static struct aes_regwrite capture_reqs[] = {
|
||||
{ 0x80, 0x00 },
|
||||
{ 0x81, 0x00 },
|
||||
{ 0, 0 },
|
||||
@@ -152,4 +154,6 @@ fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||
aes_class->init_reqs = init_reqs;
|
||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||
aes_class->capture_reqs = capture_reqs;
|
||||
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ static void complete_deactivation (FpImageDevice *dev);
|
||||
#define CALIBRATE_DATA_LEN 4
|
||||
#define FINGER_DET_DATA_LEN 4
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
static void
|
||||
aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||
FpDevice *_dev,
|
||||
@@ -70,6 +71,7 @@ aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
|
||||
}
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
static void
|
||||
aesX660_send_cmd (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
@@ -89,13 +91,12 @@ aesX660_read_response (FpiSsm *ssm,
|
||||
FpiUsbTransferCallback callback)
|
||||
{
|
||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||
unsigned char *data;
|
||||
GCancellable *cancel = NULL;
|
||||
|
||||
if (cancellable)
|
||||
cancel = fpi_device_get_cancellable (_dev);
|
||||
data = g_malloc (buf_len);
|
||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, buf_len, NULL);
|
||||
|
||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, buf_len);
|
||||
transfer->ssm = ssm;
|
||||
transfer->short_is_error = short_is_error;
|
||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
|
||||
@@ -116,7 +117,7 @@ aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer,
|
||||
/* Calibrate response was read correctly? */
|
||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
|
||||
{
|
||||
fp_dbg ("Bogus calibrate response: %.2x\n", data[0]);
|
||||
fp_dbg ("Bogus calibrate response: %.2x", data[0]);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Bogus calibrate "
|
||||
@@ -155,14 +156,14 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("Failed to read FD data\n");
|
||||
fp_dbg ("Failed to read FD data");
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
|
||||
{
|
||||
fp_dbg ("Bogus FD response: %.2x\n", data[0]);
|
||||
fp_dbg ("Bogus FD response: %.2x", data[0]);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Bogus FD response %.2x",
|
||||
@@ -177,7 +178,7 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("Wait for finger returned %.2x as result\n",
|
||||
fp_dbg ("Wait for finger returned %.2x as result",
|
||||
data[AESX660_FINGER_PRESENT_OFFSET]);
|
||||
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
|
||||
}
|
||||
@@ -405,7 +406,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||
g_byte_array_set_size (priv->stripe_packet, 0);
|
||||
}
|
||||
|
||||
fp_dbg ("finger %s\n", finger_missing ? "missing" : "present");
|
||||
fp_dbg ("finger %s", finger_missing ? "missing" : "present");
|
||||
|
||||
if (finger_missing)
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
@@ -440,7 +441,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
break;
|
||||
|
||||
case CAPTURE_SET_IDLE:
|
||||
fp_dbg ("Got %lu frames\n", priv->strips_len);
|
||||
fp_dbg ("Got %lu frames", priv->strips_len);
|
||||
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||
capture_set_idle_cmd_cb);
|
||||
break;
|
||||
@@ -513,19 +514,19 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("read_id cmd failed\n");
|
||||
fp_dbg ("read_id cmd failed");
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
/* ID was read correctly */
|
||||
if (data[0] == 0x07)
|
||||
{
|
||||
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n",
|
||||
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x",
|
||||
data[4], data[3], data[5], data[6], data[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
||||
fp_dbg ("Bogus read ID response: %.2x", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Bogus read ID response %.2x",
|
||||
@@ -553,7 +554,7 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_dbg ("Failed to init device! init status: %.2x\n", data[7]);
|
||||
fp_dbg ("Failed to init device! init status: %.2x", data[7]);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Failed to init device %.2x",
|
||||
@@ -570,11 +571,11 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
fp_dbg ("read_init_cb\n");
|
||||
fp_dbg ("read_init_cb");
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("read_init transfer status: %s, actual_len: %d\n", error->message,
|
||||
fp_dbg ("read_init transfer status: %s, actual_len: %d", error->message,
|
||||
(gint) transfer->actual_length);
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
@@ -582,7 +583,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
/* ID was read correctly */
|
||||
if (data[0] != 0x42 || data[3] != 0x01)
|
||||
{
|
||||
fp_dbg ("Bogus read init response: %.2x %.2x\n", data[0],
|
||||
fp_dbg ("Bogus read init response: %.2x %.2x", data[0],
|
||||
data[3]);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -614,13 +615,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
case ACTIVATE_SET_IDLE:
|
||||
priv->init_seq_idx = 0;
|
||||
fp_dbg ("Activate: set idle\n");
|
||||
fp_dbg ("Activate: set idle");
|
||||
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||
fpi_ssm_usb_transfer_cb);
|
||||
break;
|
||||
|
||||
case ACTIVATE_SEND_READ_ID_CMD:
|
||||
fp_dbg ("Activate: read ID\n");
|
||||
fp_dbg ("Activate: read ID");
|
||||
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
|
||||
fpi_ssm_usb_transfer_cb);
|
||||
break;
|
||||
@@ -630,7 +631,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
break;
|
||||
|
||||
case ACTIVATE_SEND_INIT_CMD:
|
||||
fp_dbg ("Activate: send init seq #%d cmd #%d\n",
|
||||
fp_dbg ("Activate: send init seq #%d cmd #%d",
|
||||
priv->init_seq_idx,
|
||||
priv->init_cmd_idx);
|
||||
aesX660_send_cmd (ssm, _dev,
|
||||
@@ -640,7 +641,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
break;
|
||||
|
||||
case ACTIVATE_READ_INIT_RESPONSE:
|
||||
fp_dbg ("Activate: read init response\n");
|
||||
fp_dbg ("Activate: read init response");
|
||||
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
|
||||
break;
|
||||
|
||||
|
||||
@@ -73,22 +73,19 @@ struct _FpiDeviceElan
|
||||
/* end commands */
|
||||
|
||||
/* state */
|
||||
gboolean deactivating;
|
||||
FpiImageDeviceState dev_state;
|
||||
FpiImageDeviceState dev_state_next;
|
||||
unsigned char *last_read;
|
||||
unsigned char calib_atts_left;
|
||||
unsigned char calib_status;
|
||||
unsigned short *background;
|
||||
unsigned char frame_width;
|
||||
unsigned char frame_height;
|
||||
unsigned char raw_frame_height;
|
||||
int num_frames;
|
||||
GSList *frames;
|
||||
gboolean active;
|
||||
gboolean deactivating;
|
||||
unsigned char *last_read;
|
||||
unsigned char calib_atts_left;
|
||||
unsigned char calib_status;
|
||||
unsigned short *background;
|
||||
unsigned char frame_width;
|
||||
unsigned char frame_height;
|
||||
unsigned char raw_frame_height;
|
||||
int num_frames;
|
||||
GSList *frames;
|
||||
/* end state */
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
||||
FpImageDevice);
|
||||
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
|
||||
|
||||
static int
|
||||
@@ -487,7 +484,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
|
||||
|
||||
/* The device is inactive at this point. */
|
||||
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
self->active = FALSE;
|
||||
|
||||
if (self->deactivating)
|
||||
{
|
||||
@@ -505,16 +502,14 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
}
|
||||
|
||||
static void
|
||||
elan_stop_capture (FpDevice *dev)
|
||||
elan_stop_capture (FpiDeviceElan *self)
|
||||
{
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
elan_dev_reset_state (self);
|
||||
|
||||
FpiSsm *ssm =
|
||||
fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
|
||||
fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
|
||||
|
||||
fpi_ssm_start (ssm, stop_capture_complete);
|
||||
}
|
||||
@@ -545,8 +540,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
break;
|
||||
|
||||
case CAPTURE_READ_DATA:
|
||||
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
|
||||
|
||||
/* 0x55 - finger present
|
||||
* 0xff - device not calibrated (probably) */
|
||||
if (self->last_read && self->last_read[0] == 0x55)
|
||||
@@ -614,18 +607,21 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
fpi_image_device_session_error (dev, error);
|
||||
}
|
||||
|
||||
/* Note: We always stop capturing even if that may not be needed always.
|
||||
* Doing this between captures appears to make it at least less likely for
|
||||
* devices to end up in a bad state.
|
||||
*/
|
||||
elan_stop_capture (self);
|
||||
}
|
||||
|
||||
static void
|
||||
elan_capture (FpDevice *dev)
|
||||
elan_capture (FpiDeviceElan *self)
|
||||
{
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
elan_dev_reset_state (self);
|
||||
FpiSsm *ssm =
|
||||
fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
|
||||
|
||||
fpi_ssm_start (ssm, capture_complete);
|
||||
}
|
||||
@@ -777,33 +773,31 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
static void
|
||||
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
if (error)
|
||||
{
|
||||
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||
elan_stop_capture (FPI_DEVICE_ELAN (dev));
|
||||
}
|
||||
else
|
||||
{
|
||||
elan_capture (dev);
|
||||
elan_capture (FPI_DEVICE_ELAN (dev));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
elan_calibrate (FpDevice *dev)
|
||||
elan_calibrate (FpiDeviceElan *self)
|
||||
{
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
elan_dev_reset_state (self);
|
||||
|
||||
g_return_if_fail (!self->active);
|
||||
self->active = TRUE;
|
||||
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
||||
|
||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state,
|
||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
|
||||
CALIBRATE_NUM_STATES);
|
||||
|
||||
fpi_ssm_start (ssm, calibrate_complete);
|
||||
@@ -958,95 +952,19 @@ dev_activate (FpImageDevice *dev)
|
||||
elan_activate (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
elan_change_state (FpImageDevice *idev)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (idev);
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
FpiImageDeviceState next_state = self->dev_state_next;
|
||||
|
||||
if (self->dev_state == next_state)
|
||||
{
|
||||
fp_dbg ("already in %d", next_state);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("changing to %d", next_state);
|
||||
}
|
||||
|
||||
switch (next_state)
|
||||
{
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
||||
/* activation completed or another enroll stage started */
|
||||
self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
||||
elan_calibrate (dev);
|
||||
break;
|
||||
|
||||
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
||||
/* not used */
|
||||
break;
|
||||
|
||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
||||
elan_stop_capture (dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
elan_change_state_async (FpDevice *dev,
|
||||
void *data)
|
||||
{
|
||||
fp_dbg ("state change dev: %p", dev);
|
||||
elan_change_state (FP_IMAGE_DEVICE (dev));
|
||||
}
|
||||
|
||||
static void
|
||||
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||
{
|
||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||
GSource *timeout;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
/* Inactive and await finger off are equivalent for the elan driver. */
|
||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
|
||||
if (self->dev_state_next == state)
|
||||
fp_dbg ("change to state %d already queued", state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
|
||||
char *name;
|
||||
|
||||
/* schedule state change instead of calling it directly to allow all actions
|
||||
* related to the previous state to complete */
|
||||
self->dev_state_next = state;
|
||||
timeout = fpi_device_add_timeout (FP_DEVICE (dev), 10,
|
||||
elan_change_state_async,
|
||||
NULL, NULL);
|
||||
|
||||
name = g_strdup_printf ("dev_change_state to %d", state);
|
||||
g_source_set_name (timeout, name);
|
||||
g_free (name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
||||
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
|
||||
self->dev_state = state;
|
||||
self->dev_state_next = state;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
/* Note: We always calibrate even if that may not be needed always.
|
||||
* Doing this for each capture appears to make it at least less likely for
|
||||
* devices to end up in a bad state.
|
||||
*/
|
||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
elan_calibrate (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1056,19 +974,14 @@ dev_deactivate (FpImageDevice *dev)
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
{
|
||||
/* The device is inactive already, complete the operation immediately. */
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
if (!self->active)
|
||||
/* The device is inactive already, complete the operation immediately. */
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
else
|
||||
{
|
||||
/* The device is not yet inactive, flag that we are deactivating (and
|
||||
* need to signal back deactivation) and then ensure we will change
|
||||
* to the inactive state eventually. */
|
||||
self->deactivating = TRUE;
|
||||
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
}
|
||||
/* The device is not yet inactive, flag that we are deactivating (and
|
||||
* need to signal back deactivation).
|
||||
* Note that any running capture will be cancelled already if needed. */
|
||||
self->deactivating = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -70,6 +70,9 @@
|
||||
#define ELAN_CMD_TIMEOUT 10000
|
||||
#define ELAN_FINGER_TIMEOUT 200
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
||||
FpImageDevice);
|
||||
|
||||
struct elan_cmd
|
||||
{
|
||||
unsigned char cmd[ELAN_CMD_LEN];
|
||||
@@ -211,6 +214,7 @@ static const FpIdEntry elan_id_table[] = {
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||
};
|
||||
|
||||
@@ -218,8 +222,8 @@ static void elan_cmd_done (FpiSsm *ssm);
|
||||
static void elan_cmd_read (FpiSsm *ssm,
|
||||
FpDevice *dev);
|
||||
|
||||
static void elan_calibrate (FpDevice *dev);
|
||||
static void elan_capture (FpDevice *dev);
|
||||
static void elan_calibrate (FpiDeviceElan *self);
|
||||
static void elan_capture (FpiDeviceElan *self);
|
||||
|
||||
static void dev_change_state (FpImageDevice *dev,
|
||||
FpiImageDeviceState state);
|
||||
|
||||
1582
libfprint/drivers/goodixmoc/goodix.c
Normal file
1582
libfprint/drivers/goodixmoc/goodix.c
Normal file
File diff suppressed because it is too large
Load Diff
62
libfprint/drivers/goodixmoc/goodix.h
Normal file
62
libfprint/drivers/goodixmoc/goodix.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Goodix Moc driver for libfprint
|
||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
||||
*
|
||||
* 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"
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
|
||||
|
||||
typedef enum {
|
||||
FP_CMD_SEND = 0,
|
||||
FP_CMD_GET_ACK,
|
||||
FP_CMD_GET_DATA,
|
||||
FP_CMD_NUM_STATES,
|
||||
} FpCmdState;
|
||||
|
||||
|
||||
typedef enum {
|
||||
FP_INIT_VERSION = 0,
|
||||
FP_INIT_CONFIG,
|
||||
FP_INIT_NUM_STATES,
|
||||
} FpInitState;
|
||||
|
||||
|
||||
typedef enum {
|
||||
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
|
||||
FP_ENROLL_ENUM,
|
||||
FP_ENROLL_IDENTIFY,
|
||||
FP_ENROLL_CREATE,
|
||||
FP_ENROLL_CAPTURE,
|
||||
FP_ENROLL_UPDATE,
|
||||
FP_ENROLL_WAIT_FINGER_UP,
|
||||
FP_ENROLL_CHECK_DUPLICATE,
|
||||
FP_ENROLL_COMMIT,
|
||||
FP_ENROLL_PWR_BTN_SHIELD_OFF,
|
||||
FP_ENROLL_NUM_STATES,
|
||||
} FpEnrollState;
|
||||
|
||||
typedef enum {
|
||||
FP_VERIFY_PWR_BTN_SHIELD_ON = 0,
|
||||
FP_VERIFY_CAPTURE,
|
||||
FP_VERIFY_IDENTIFY,
|
||||
FP_VERIFY_PWR_BTN_SHIELD_OFF,
|
||||
FP_VERIFY_NUM_STATES,
|
||||
} FpVerifyState;
|
||||
463
libfprint/drivers/goodixmoc/goodix_proto.c
Normal file
463
libfprint/drivers/goodixmoc/goodix_proto.c
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Goodix Moc driver for libfprint
|
||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
||||
*
|
||||
* 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 <glib.h>
|
||||
#include "goodix_proto.h"
|
||||
|
||||
/*
|
||||
* Crc functions
|
||||
*/
|
||||
|
||||
#define WIDTH (8 * sizeof (uint32_t))
|
||||
#define FINAL_XOR_VALUE 0xFFFFFFFF
|
||||
#define REFLECT_DATA(X) ((uint8_t) reflect ((X), 8))
|
||||
#define REFLECT_REMAINDER(X) ((unsigned int) reflect ((X), WIDTH))
|
||||
|
||||
|
||||
uint8_t
|
||||
gx_proto_crc8_calc (uint8_t *lubp_date, uint32_t lui_len)
|
||||
{
|
||||
const uint8_t *data = lubp_date;
|
||||
unsigned int crc = 0;
|
||||
int i, j;
|
||||
|
||||
for (j = lui_len; j; j--, data++)
|
||||
{
|
||||
crc ^= (*data << 8);
|
||||
for (i = 8; i; i--)
|
||||
{
|
||||
if (crc & 0x8000)
|
||||
crc ^= (0x1070 << 3);
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc >>= 8;
|
||||
crc = ~crc;
|
||||
return (uint8_t) crc;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t crc;
|
||||
} gf_crc32_context;
|
||||
|
||||
static uint32_t s_crc_table[256] =
|
||||
{ 0x0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
|
||||
|
||||
static uint32_t
|
||||
reflect (uint32_t data, uint8_t n_bits)
|
||||
{
|
||||
unsigned long reflection = 0x00000000;
|
||||
uint8_t bit;
|
||||
|
||||
/*
|
||||
* Reflect the data about the center bit.
|
||||
*/
|
||||
for (bit = 0; bit < n_bits; ++bit)
|
||||
{
|
||||
/*
|
||||
* If the LSB bit is set, set the reflection of it.
|
||||
*/
|
||||
if (data & 0x01)
|
||||
reflection |= (1 << ((n_bits - 1) - bit));
|
||||
|
||||
data = (data >> 1);
|
||||
}
|
||||
|
||||
return reflection;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
crc32_init (gf_crc32_context *ctx)
|
||||
{
|
||||
ctx->crc = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static void
|
||||
crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
|
||||
{
|
||||
uint8_t data;
|
||||
uint32_t byte;
|
||||
|
||||
/*
|
||||
* Divide the message by the polynomial, a byte at a time.
|
||||
*/
|
||||
for (byte = 0; byte < n_bytes; ++byte)
|
||||
{
|
||||
data = REFLECT_DATA (message[byte]) ^ (ctx->crc >> (WIDTH - 8));
|
||||
ctx->crc = s_crc_table[data] ^ (ctx->crc << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
crc32_final (gf_crc32_context *ctx, uint8_t *md)
|
||||
{
|
||||
uint32_t crc = 0;
|
||||
|
||||
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
|
||||
crc = GUINT32_TO_LE (ctx->crc);
|
||||
memcpy (md, &crc, 4);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
gx_proto_crc32_calc (uint8_t *pchMsg, uint32_t wDataLen, uint8_t *pchMsgDst)
|
||||
{
|
||||
gf_crc32_context context = { 0 };
|
||||
|
||||
if (!pchMsg)
|
||||
return 0;
|
||||
|
||||
crc32_init (&context);
|
||||
|
||||
crc32_update (&context, pchMsg, wDataLen);
|
||||
|
||||
crc32_final (&context, pchMsgDst);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* protocol
|
||||
*
|
||||
*/
|
||||
|
||||
static uint8_t dump_seq = 0;
|
||||
|
||||
static void
|
||||
init_pack_header (
|
||||
ppack_header pheader,
|
||||
uint16_t len,
|
||||
uint16_t cmd,
|
||||
uint8_t packagenum
|
||||
)
|
||||
{
|
||||
g_assert (pheader);
|
||||
|
||||
memset (pheader, 0, sizeof (*pheader));
|
||||
pheader->cmd0 = HIBYTE (cmd);
|
||||
pheader->cmd1 = LOBYTE (cmd);
|
||||
pheader->packagenum = packagenum;
|
||||
pheader->reserved = dump_seq++;
|
||||
pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
|
||||
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
|
||||
pheader->rev_crc8 = ~pheader->crc8;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gx_proto_build_package (uint8_t *ppackage,
|
||||
uint32_t *package_len,
|
||||
uint16_t cmd,
|
||||
const uint8_t *payload,
|
||||
uint32_t payload_size)
|
||||
{
|
||||
pack_header header;
|
||||
|
||||
if (!ppackage || !package_len)
|
||||
return -1;
|
||||
|
||||
if(*package_len < (payload_size + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE))
|
||||
return -1;
|
||||
|
||||
init_pack_header (&header, payload_size, cmd, 0);
|
||||
|
||||
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
|
||||
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
|
||||
|
||||
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gx_proto_parse_header (
|
||||
uint8_t *buffer,
|
||||
uint32_t buffer_len,
|
||||
pack_header *pheader)
|
||||
{
|
||||
if (!buffer || !pheader)
|
||||
return -1;
|
||||
if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE)
|
||||
return -1;
|
||||
|
||||
memcpy (pheader, buffer, sizeof (pack_header));
|
||||
pheader->len = GUINT16_FROM_LE (pheader->len);
|
||||
if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE)
|
||||
return -1;
|
||||
pheader->len -= PACKAGE_CRC_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gx_proto_parse_fingerid (
|
||||
uint8_t * fid_buffer,
|
||||
uint16_t fid_buffer_size,
|
||||
ptemplate_format_t template
|
||||
)
|
||||
{
|
||||
uint8_t * buffer = NULL;
|
||||
uint16_t Offset = 0;
|
||||
|
||||
if (!template || !fid_buffer)
|
||||
return -1;
|
||||
|
||||
if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t))
|
||||
return -1;
|
||||
|
||||
buffer = fid_buffer;
|
||||
Offset = 0;
|
||||
|
||||
if (buffer[Offset++] != 67)
|
||||
return -1;
|
||||
fid_buffer_size--;
|
||||
|
||||
template->type = buffer[Offset++];
|
||||
fid_buffer_size--;
|
||||
template->finger_index = buffer[Offset++];
|
||||
fid_buffer_size--;
|
||||
Offset++;
|
||||
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
|
||||
Offset += sizeof (template->accountid);
|
||||
memcpy (template->tid, &buffer[Offset], sizeof (template->tid));
|
||||
Offset += sizeof (template->tid); // Offset == 68
|
||||
template->payload.size = buffer[Offset++];
|
||||
if (template->payload.size > sizeof (template->payload.data))
|
||||
return -1;
|
||||
memset (template->payload.data, 0, template->payload.size);
|
||||
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp)
|
||||
{
|
||||
uint16_t offset = 0;
|
||||
uint8_t *fingerlist = NULL;
|
||||
|
||||
if (!buffer || !presp)
|
||||
return -1;
|
||||
if (buffer_len < 1)
|
||||
return -1;
|
||||
presp->result = buffer[0];
|
||||
switch (HIBYTE (cmd))
|
||||
{
|
||||
case RESPONSE_PACKAGE_CMD:
|
||||
{
|
||||
if (buffer_len < sizeof (gxfp_parse_msg_t) + 1)
|
||||
return -1;
|
||||
presp->parse_msg.ack_cmd = buffer[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_UPDATE_CONFIG:
|
||||
{
|
||||
presp->finger_config.status = buffer[0];
|
||||
if (buffer_len >= 3)
|
||||
presp->finger_config.max_stored_prints = buffer[2];
|
||||
else
|
||||
/* to compatiable old version firmware */
|
||||
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_COMMITENROLLMENT:
|
||||
case MOC_CMD0_DELETETEMPLATE:
|
||||
/* just check result */
|
||||
break;
|
||||
|
||||
case MOC_CMD0_PWR_BTN_SHIELD:
|
||||
presp->power_button_shield_resp.resp_cmd1 = LOBYTE (cmd);
|
||||
if (buffer_len >= 2)
|
||||
{
|
||||
uint8_t support_pwr_shield = buffer[1];
|
||||
if (support_pwr_shield == 0xFF)
|
||||
g_debug ("Power button shield feature not supported!\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_GET_VERSION:
|
||||
if (buffer_len < sizeof (gxfp_version_info_t) + 1)
|
||||
return -1;
|
||||
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
|
||||
break;
|
||||
|
||||
case MOC_CMD0_CAPTURE_DATA:
|
||||
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
|
||||
{
|
||||
if (buffer_len < sizeof (gxfp_capturedata_t) + 1)
|
||||
return -1;
|
||||
presp->capture_data_resp.img_quality = buffer[1];
|
||||
presp->capture_data_resp.img_coverage = buffer[2];
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_ENROLL_INIT:
|
||||
if (buffer_len < sizeof (gxfp_enroll_init_t) + 1)
|
||||
return -1;
|
||||
if (presp->result == GX_SUCCESS)
|
||||
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
|
||||
break;
|
||||
|
||||
case MOC_CMD0_ENROLL:
|
||||
if (buffer_len < sizeof (gxfp_enroll_update_t))
|
||||
return -1;
|
||||
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
|
||||
presp->enroll_update.img_overlay = buffer[1];
|
||||
presp->enroll_update.img_preoverlay = buffer[2];
|
||||
break;
|
||||
|
||||
case MOC_CMD0_CHECK4DUPLICATE:
|
||||
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
|
||||
if (presp->check_duplicate_resp.duplicate)
|
||||
{
|
||||
if (buffer_len < 3)
|
||||
return -1;
|
||||
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
|
||||
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3)
|
||||
return -1;
|
||||
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_GETFINGERLIST:
|
||||
if (presp->result != GX_SUCCESS)
|
||||
break;
|
||||
if (buffer_len < 2)
|
||||
return -1;
|
||||
presp->finger_list_resp.finger_num = buffer[1];
|
||||
fingerlist = buffer + 2;
|
||||
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
|
||||
{
|
||||
uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
|
||||
offset += 2;
|
||||
if (buffer_len < fingerid_length + offset + 2)
|
||||
return -1;
|
||||
if (gx_proto_parse_fingerid (fingerlist + offset,
|
||||
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;
|
||||
}
|
||||
offset += fingerid_length;
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_IDENTIFY:
|
||||
{
|
||||
uint32_t score = 0;
|
||||
uint8_t study = 0;
|
||||
uint16_t fingerid_size = 0;
|
||||
presp->verify.match = (buffer[0] == 0) ? true : false;
|
||||
if (presp->verify.match)
|
||||
{
|
||||
if (buffer_len < sizeof (template_format_t) + 10)
|
||||
return -1;
|
||||
offset += 1;
|
||||
presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
||||
offset += 2;
|
||||
score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset));
|
||||
offset += 4;
|
||||
study = buffer[offset];
|
||||
offset += 1;
|
||||
fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
||||
offset += 2;
|
||||
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
|
||||
{
|
||||
presp->result = GX_FAILED;
|
||||
break;
|
||||
}
|
||||
g_debug ("match, score: %d, study: %d", score, study);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MOC_CMD0_FINGER_MODE:
|
||||
presp->finger_status.status = buffer[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t sensor_config[26] = {
|
||||
0x00, 0x00, 0x64, 0x50, 0x0f, 0x41, 0x08, 0x0a, 0x18, 0x00, 0x00, 0x23, 0x00,
|
||||
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x05, 0x05
|
||||
};
|
||||
|
||||
int
|
||||
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
|
||||
{
|
||||
uint32_t crc32_calc = 0;
|
||||
|
||||
if (!pconfig)
|
||||
return -1;
|
||||
memset (pconfig, 0, sizeof (*pconfig));
|
||||
|
||||
//NOTICE: Do not change any value!
|
||||
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
|
||||
pconfig->reserved[0] = 1;
|
||||
|
||||
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
|
||||
|
||||
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
249
libfprint/drivers/goodixmoc/goodix_proto.h
Normal file
249
libfprint/drivers/goodixmoc/goodix_proto.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Goodix Moc driver for libfprint
|
||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PACKAGE_CRC_SIZE (4)
|
||||
#define PACKAGE_HEADER_SIZE (8)
|
||||
|
||||
#define FP_MAX_FINGERNUM (20)
|
||||
|
||||
#define TEMPLATE_ID_SIZE (32)
|
||||
|
||||
#define GX_VERSION_LEN (8)
|
||||
|
||||
/* Type covert */
|
||||
#define MAKE_CMD_EX(cmd0, cmd1) ((uint16_t) (((cmd0) << 8) | (cmd1)))
|
||||
#define LOBYTE(value) ((uint8_t) (value))
|
||||
#define HIBYTE(value) ((uint8_t) (((uint16_t) (value) >> 8) & 0xFF))
|
||||
|
||||
|
||||
/* Error code */
|
||||
#define GX_SUCCESS 0x00
|
||||
#define GX_FAILED 0x80
|
||||
#define GX_ERROR_FINGER_ID_NOEXIST 0x9C
|
||||
#define GX_ERROR_TEMPLATE_INCOMPLETE 0xB8
|
||||
#define GX_ERROR_WAIT_FINGER_UP_TIMEOUT 0xC7
|
||||
#define GX_ERROR_NO_AVAILABLE_SPACE 0x8F
|
||||
|
||||
/* Command Type Define */
|
||||
#define RESPONSE_PACKAGE_CMD 0xAA
|
||||
|
||||
#define MOC_CMD0_ENROLL 0xA0
|
||||
#define MOC_CMD0_ENROLL_INIT 0xA1
|
||||
#define MOC_CMD0_CAPTURE_DATA 0xA2
|
||||
#define MOC_CMD0_CHECK4DUPLICATE 0xA3
|
||||
#define MOC_CMD0_COMMITENROLLMENT 0xA4
|
||||
|
||||
#define MOC_CMD0_IDENTIFY 0xA5
|
||||
#define MOC_CMD0_GETFINGERLIST 0xA6
|
||||
#define MOC_CMD0_DELETETEMPLATE 0xA7
|
||||
|
||||
#define MOC_CMD1_DEFAULT 0x00
|
||||
#define MOC_CMD1_UNTIL_DOWN 0x00
|
||||
#define MOC_CMD1_WHEN_DOWN 0x01
|
||||
|
||||
#define MOC_CMD1_DELETE_TEMPLATE 0x04
|
||||
#define MOC_CMD1_DELETE_ALL 0x01
|
||||
|
||||
#define MOC_CMD0_GET_VERSION 0xD0
|
||||
|
||||
#define MOC_CMD0_UPDATE_CONFIG 0xC0
|
||||
#define MOC_CMD1_NWRITE_CFG_TO_FLASH 0x00
|
||||
#define MOC_CMD1_WRITE_CFG_TO_FLASH 0x01
|
||||
|
||||
#define MOC_CMD0_FINGER_MODE 0xB0
|
||||
#define MOC_CMD1_GET_FINGER_MODE 0x00
|
||||
#define MOC_CMD1_SET_FINGER_DOWN 0x01
|
||||
#define MOC_CMD1_SET_FINGER_UP 0x02
|
||||
|
||||
#define MOC_CMD0_PWR_BTN_SHIELD 0xE0
|
||||
#define MOC_CMD1_PWR_BTN_SHIELD_OFF 0x00
|
||||
#define MOC_CMD1_PWR_BTN_SHIELD_ON 0x01
|
||||
|
||||
/* */
|
||||
|
||||
typedef struct _gxfp_version_info
|
||||
{
|
||||
uint8_t format[2];
|
||||
uint8_t fwtype[GX_VERSION_LEN];
|
||||
uint8_t fwversion[GX_VERSION_LEN];
|
||||
uint8_t customer[GX_VERSION_LEN];
|
||||
uint8_t mcu[GX_VERSION_LEN];
|
||||
uint8_t sensor[GX_VERSION_LEN];
|
||||
uint8_t algversion[GX_VERSION_LEN];
|
||||
uint8_t interface[GX_VERSION_LEN];
|
||||
uint8_t protocol[GX_VERSION_LEN];
|
||||
uint8_t flashVersion[GX_VERSION_LEN];
|
||||
uint8_t reserved[38];
|
||||
} gxfp_version_info_t, *pgxfp_version_info_t;
|
||||
|
||||
|
||||
typedef struct _gxfp_parse_msg
|
||||
{
|
||||
uint8_t ack_cmd;
|
||||
bool has_no_config;
|
||||
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
|
||||
|
||||
|
||||
typedef struct _gxfp_enroll_init
|
||||
{
|
||||
uint8_t tid[TEMPLATE_ID_SIZE];
|
||||
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct _template_format
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t finger_index;
|
||||
uint8_t accountid[32];
|
||||
uint8_t tid[32];
|
||||
struct
|
||||
{
|
||||
uint32_t size;
|
||||
uint8_t data[56];
|
||||
} payload;
|
||||
uint8_t reserve[2];
|
||||
} template_format_t, *ptemplate_format_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
typedef struct _gxfp_verify
|
||||
{
|
||||
bool match;
|
||||
uint32_t rejectdetail;
|
||||
template_format_t template;
|
||||
} gxfp_verify_t, *pgxfp_verify_t;
|
||||
|
||||
|
||||
typedef struct _gxfp_capturedata
|
||||
{
|
||||
uint8_t img_quality;
|
||||
uint8_t img_coverage;
|
||||
} gxfp_capturedata_t, *pgxfp_capturedata_t;
|
||||
|
||||
typedef struct _gxfp_check_duplicate
|
||||
{
|
||||
bool duplicate;
|
||||
template_format_t template;
|
||||
} gxfp_check_duplicate_t, *pgxfp_check_duplicate_t;
|
||||
|
||||
|
||||
typedef struct _gxfp_enroll_update
|
||||
{
|
||||
bool rollback;
|
||||
uint8_t img_overlay;
|
||||
uint8_t img_preoverlay;
|
||||
} gxfp_enroll_update_t, *Pgxfp_enroll_update_t;
|
||||
|
||||
typedef struct _gxfp_enum_fingerlist
|
||||
{
|
||||
uint8_t finger_num;
|
||||
template_format_t finger_list[FP_MAX_FINGERNUM];
|
||||
} gxfp_enum_fingerlist_t, *pgxfp_enum_fingerlist_t;
|
||||
|
||||
typedef struct _gxfp_enroll_commit
|
||||
{
|
||||
uint8_t result;
|
||||
} gxfp_enroll_commit_t, *pgxfp_enroll_commit_t;
|
||||
|
||||
typedef struct _fp_finger_status
|
||||
{
|
||||
uint8_t status;
|
||||
} fp_finger_status_t, *pfp_finger_status_t;
|
||||
|
||||
typedef struct _fp_finger_config
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t max_stored_prints;
|
||||
} fp_finger_config_t, *pfp_finger_config_t;
|
||||
|
||||
typedef struct _fp_pwr_btn_shield
|
||||
{
|
||||
uint8_t resp_cmd1;
|
||||
} fp_pwr_btn_shield_t, *pfp_pwr_btn_shield_t;
|
||||
|
||||
typedef struct _fp_cmd_response
|
||||
{
|
||||
uint8_t result;
|
||||
union
|
||||
{
|
||||
gxfp_parse_msg_t parse_msg;
|
||||
gxfp_verify_t verify;
|
||||
gxfp_enroll_init_t enroll_init;
|
||||
gxfp_capturedata_t capture_data_resp;
|
||||
gxfp_check_duplicate_t check_duplicate_resp;
|
||||
gxfp_enroll_commit_t enroll_commit;
|
||||
gxfp_enroll_update_t enroll_update;
|
||||
gxfp_enum_fingerlist_t finger_list_resp;
|
||||
gxfp_version_info_t version_info;
|
||||
fp_finger_status_t finger_status;
|
||||
fp_finger_config_t finger_config;
|
||||
fp_pwr_btn_shield_t power_button_shield_resp;
|
||||
};
|
||||
} gxfp_cmd_response_t, *pgxfp_cmd_response_t;
|
||||
|
||||
|
||||
typedef struct _pack_header
|
||||
{
|
||||
uint8_t cmd0;
|
||||
uint8_t cmd1;
|
||||
uint8_t packagenum;
|
||||
uint8_t reserved;
|
||||
uint16_t len;
|
||||
uint8_t crc8;
|
||||
uint8_t rev_crc8;
|
||||
} pack_header, *ppack_header;
|
||||
|
||||
|
||||
typedef struct _gxfp_sensor_cfg
|
||||
{
|
||||
uint8_t config[26];
|
||||
uint8_t reserved[98];
|
||||
uint8_t crc_value[4];
|
||||
} gxfp_sensor_cfg_t, *pgxfp_sensor_cfg_t;
|
||||
/* */
|
||||
|
||||
int gx_proto_build_package (uint8_t *ppackage,
|
||||
uint32_t *package_len,
|
||||
uint16_t cmd,
|
||||
const uint8_t *payload,
|
||||
uint32_t payload_size);
|
||||
|
||||
int gx_proto_parse_header (uint8_t *buffer,
|
||||
uint32_t buffer_len,
|
||||
pack_header *pheader);
|
||||
|
||||
int gx_proto_parse_body (uint16_t cmd,
|
||||
uint8_t *buffer,
|
||||
uint16_t buffer_len,
|
||||
pgxfp_cmd_response_t presponse);
|
||||
|
||||
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
|
||||
|
||||
uint8_t gx_proto_crc8_calc (uint8_t *lubp_date,
|
||||
uint32_t lui_len);
|
||||
|
||||
uint8_t gx_proto_crc32_calc (uint8_t *pchMsg,
|
||||
uint32_t wDataLen,
|
||||
uint8_t *pchMsgDst);
|
||||
@@ -27,9 +27,18 @@
|
||||
|
||||
G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
|
||||
|
||||
static void init_identify_msg (FpDevice *device);
|
||||
static void compose_and_send_identify_msg (FpDevice *device);
|
||||
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
|
||||
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xF9, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xFC, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC2, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC9, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE7, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -78,10 +87,17 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
if (msg_resp.payload[0] == 0x01)
|
||||
{
|
||||
self->finger_on_sensor = TRUE;
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_PRESENT,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->finger_on_sensor = FALSE;
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
if (self->cmd_complete_on_removal)
|
||||
{
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
@@ -108,7 +124,7 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
{
|
||||
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
|
||||
{
|
||||
fp_dbg ("Received cancellation success resonse");
|
||||
fp_dbg ("Received cancellation success response");
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
g_error_new_literal (G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED,
|
||||
@@ -193,12 +209,19 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
return;
|
||||
}
|
||||
g_clear_pointer (&error, g_error_free);
|
||||
|
||||
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error)
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
|
||||
{
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
else
|
||||
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL);
|
||||
{
|
||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
||||
0,
|
||||
NULL,
|
||||
cmd_interrupt_cb,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -325,7 +348,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
|
||||
* may only be a cancellation currently). */
|
||||
if (seq_num <= 0)
|
||||
{
|
||||
self->last_seq_num = MAX (1, self->last_seq_num + 1);
|
||||
self->last_seq_num = MAX (1, (self->last_seq_num + 1) & 0xff);
|
||||
real_seq_num = self->last_seq_num;
|
||||
if (seq_num == 0)
|
||||
self->cmd_seq_num = self->last_seq_num;
|
||||
@@ -431,6 +454,37 @@ parse_print_data (GVariant *data,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FpPrint *
|
||||
create_print (FpiDeviceSynaptics *self,
|
||||
guint8 *user_id,
|
||||
guint8 finger_id)
|
||||
{
|
||||
FpPrint *print;
|
||||
g_autofree gchar *user_id_safe;
|
||||
GVariant *data = NULL;
|
||||
GVariant *uid = NULL;
|
||||
|
||||
user_id_safe = g_strndup ((char *) user_id, BMKT_MAX_USER_ID_LEN);
|
||||
|
||||
print = fp_print_new (FP_DEVICE (self));
|
||||
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
user_id_safe,
|
||||
strlen (user_id_safe),
|
||||
1);
|
||||
data = g_variant_new ("(y@ay)",
|
||||
finger_id,
|
||||
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", user_id_safe, NULL);
|
||||
|
||||
fpi_print_fill_from_user_id (print, user_id_safe);
|
||||
|
||||
return print;
|
||||
}
|
||||
|
||||
static void
|
||||
list_msg_cb (FpiDeviceSynaptics *self,
|
||||
bmkt_response_t *resp,
|
||||
@@ -483,10 +537,7 @@ list_msg_cb (FpiDeviceSynaptics *self,
|
||||
|
||||
for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
||||
{
|
||||
GVariant *data = NULL;
|
||||
GVariant *uid = NULL;
|
||||
FpPrint *print;
|
||||
gchar *userid;
|
||||
|
||||
if (get_enroll_templates_resp->templates[n].user_id_len == 0)
|
||||
continue;
|
||||
@@ -499,23 +550,9 @@ list_msg_cb (FpiDeviceSynaptics *self,
|
||||
get_enroll_templates_resp->templates[n].user_id,
|
||||
get_enroll_templates_resp->templates[n].finger_id);
|
||||
|
||||
userid = (gchar *) get_enroll_templates_resp->templates[n].user_id;
|
||||
|
||||
print = fp_print_new (FP_DEVICE (self));
|
||||
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
get_enroll_templates_resp->templates[n].user_id,
|
||||
get_enroll_templates_resp->templates[n].user_id_len,
|
||||
1);
|
||||
data = g_variant_new ("(y@ay)",
|
||||
get_enroll_templates_resp->templates[n].finger_id,
|
||||
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", get_enroll_templates_resp->templates[n].user_id, NULL);
|
||||
|
||||
fpi_print_fill_from_user_id (print, userid);
|
||||
print = create_print (self,
|
||||
get_enroll_templates_resp->templates[n].user_id,
|
||||
get_enroll_templates_resp->templates[n].finger_id);
|
||||
|
||||
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
|
||||
}
|
||||
@@ -585,6 +622,9 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
||||
switch (resp->response_id)
|
||||
{
|
||||
case BMKT_RSP_VERIFY_READY:
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_NEEDED,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
fp_info ("Place Finger on the Sensor!");
|
||||
break;
|
||||
|
||||
@@ -626,7 +666,7 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
||||
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
|
||||
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
|
||||
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
verify_complete_after_finger_removal (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -658,6 +698,212 @@ verify (FpDevice *device)
|
||||
synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
identify_complete_after_finger_removal (FpiDeviceSynaptics *self)
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
|
||||
if (self->finger_on_sensor)
|
||||
{
|
||||
fp_dbg ("delaying identify report until after finger removal!");
|
||||
self->cmd_complete_on_removal = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
identify_msg_cb (FpiDeviceSynaptics *self,
|
||||
bmkt_response_t *resp,
|
||||
GError *error)
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_identify_complete (device, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp == NULL && self->cmd_complete_on_removal)
|
||||
{
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (resp != NULL);
|
||||
|
||||
switch (resp->response_id)
|
||||
{
|
||||
case BMKT_RSP_ID_READY:
|
||||
fp_info ("Place Finger on the Sensor!");
|
||||
break;
|
||||
|
||||
case BMKT_RSP_SEND_NEXT_USER_ID:
|
||||
{
|
||||
compose_and_send_identify_msg (device);
|
||||
break;
|
||||
}
|
||||
|
||||
case BMKT_RSP_ID_FAIL:
|
||||
if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
|
||||
{
|
||||
fp_info ("Match error occurred");
|
||||
fpi_device_identify_report (device, NULL, NULL,
|
||||
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||
identify_complete_after_finger_removal (self);
|
||||
}
|
||||
else if (resp->result == BMKT_FP_NO_MATCH)
|
||||
{
|
||||
fp_info ("Print didn't match");
|
||||
fpi_device_identify_report (device, NULL, NULL, NULL);
|
||||
identify_complete_after_finger_removal (self);
|
||||
}
|
||||
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
|
||||
{
|
||||
fp_info ("Print is not in database");
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_warn ("identify has failed: %d", resp->result);
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected result from device %d",
|
||||
resp->result));
|
||||
}
|
||||
break;
|
||||
|
||||
case BMKT_RSP_ID_OK:
|
||||
{
|
||||
FpPrint *print = NULL;
|
||||
GPtrArray *prints = NULL;
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
gboolean found = FALSE;
|
||||
guint index;
|
||||
|
||||
print = create_print (self,
|
||||
resp->response.id_resp.user_id,
|
||||
resp->response.id_resp.finger_id);
|
||||
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
|
||||
found = g_ptr_array_find_with_equal_func (prints,
|
||||
print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index);
|
||||
|
||||
if (found)
|
||||
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
|
||||
else
|
||||
fpi_device_identify_report (device, NULL, print, NULL);
|
||||
|
||||
identify_complete_after_finger_removal (self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
identify (FpDevice *device)
|
||||
{
|
||||
init_identify_msg (device);
|
||||
compose_and_send_identify_msg (device);
|
||||
}
|
||||
|
||||
static void
|
||||
init_identify_msg (FpDevice *device)
|
||||
{
|
||||
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
||||
|
||||
self->id_idx = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
compose_and_send_identify_msg (FpDevice *device)
|
||||
{
|
||||
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
||||
FpPrint *print = NULL;
|
||||
GPtrArray *prints = NULL;
|
||||
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
guint8 finger;
|
||||
const guint8 *user_id;
|
||||
gsize user_id_len = 0;
|
||||
g_autofree guint8 *payload = NULL;
|
||||
guint8 payload_len = 0;
|
||||
guint8 payloadOffset = 0;
|
||||
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
if (prints->len > UINT8_MAX)
|
||||
{
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
||||
return;
|
||||
}
|
||||
if(self->id_idx >= prints->len)
|
||||
{
|
||||
fp_warn ("Device asked for more prints than we are providing.");
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected index"));
|
||||
return;
|
||||
}
|
||||
print = g_ptr_array_index (prints, self->id_idx);
|
||||
g_object_get (print, "fpi-data", &data, NULL);
|
||||
g_debug ("data is %p", data);
|
||||
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
|
||||
{
|
||||
fpi_device_identify_complete (device,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
||||
return;
|
||||
}
|
||||
if(self->id_idx == 0)
|
||||
{
|
||||
/*
|
||||
* Construct payload.
|
||||
* 1st byte is total number of IDs in list.
|
||||
* 2nd byte is number of IDs in list.
|
||||
* 1 byte for each ID length, maximum id length is 100.
|
||||
* user_id_len bytes of each ID
|
||||
*/
|
||||
payload_len = 2 + 1 + user_id_len;
|
||||
payload = g_malloc0 (payload_len);
|
||||
payload[payloadOffset] = prints->len;
|
||||
payloadOffset += 1;
|
||||
payload[payloadOffset] = 1; /* send one id per message */
|
||||
payloadOffset += 1;
|
||||
payload[payloadOffset] = user_id_len;
|
||||
payloadOffset += 1;
|
||||
memcpy (&payload[payloadOffset], user_id, user_id_len);
|
||||
payloadOffset += user_id_len;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
synaptics_sensor_cmd (self, 0, BMKT_CMD_ID_USER_IN_ORDER, payload, payloadOffset, identify_msg_cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* 1st byte is the number of IDs
|
||||
* 1 byte for each ID length
|
||||
* id_length bytes for each ID
|
||||
*/
|
||||
payload_len = 1 + 1 + user_id_len;
|
||||
payload = g_malloc0 (payload_len);
|
||||
payload[payloadOffset] = 1; /* send one id per message */
|
||||
payloadOffset += 1;
|
||||
payload[payloadOffset] = user_id_len;
|
||||
payloadOffset += 1;
|
||||
memcpy (&payload[payloadOffset], user_id, user_id_len);
|
||||
payloadOffset += user_id_len;
|
||||
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_ID_NEXT_USER, payload, payloadOffset, NULL);
|
||||
}
|
||||
self->id_idx++;
|
||||
}
|
||||
static void
|
||||
enroll_msg_cb (FpiDeviceSynaptics *self,
|
||||
bmkt_response_t *resp,
|
||||
@@ -679,6 +925,9 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
|
||||
case BMKT_RSP_ENROLL_READY:
|
||||
{
|
||||
self->enroll_stage = 0;
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_NEEDED,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
fp_info ("Place Finger on the Sensor!");
|
||||
break;
|
||||
}
|
||||
@@ -884,6 +1133,44 @@ delete_print (FpDevice *device)
|
||||
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
prob_msg_cb (FpiDeviceSynaptics *self,
|
||||
bmkt_response_t *resp,
|
||||
GError *error)
|
||||
{
|
||||
GUsbDevice *usb_dev = NULL;
|
||||
g_autofree gchar *serial = NULL;
|
||||
|
||||
usb_dev = fpi_device_get_usb_device (FP_DEVICE (self));
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
serial = g_strdup ("emulated-device");
|
||||
else
|
||||
serial = g_usb_device_get_string_descriptor (usb_dev,
|
||||
g_usb_device_get_serial_number_index (usb_dev),
|
||||
&error);
|
||||
|
||||
if (resp->result == BMKT_SUCCESS)
|
||||
{
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Probe fingerprint sensor failed with %d!", resp->result);
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dev_probe (FpDevice *device)
|
||||
{
|
||||
@@ -897,6 +1184,7 @@ dev_probe (FpDevice *device)
|
||||
const guint8 *data;
|
||||
gboolean read_ok = TRUE;
|
||||
g_autofree gchar *serial = NULL;
|
||||
gboolean retry = TRUE;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
@@ -914,35 +1202,43 @@ dev_probe (FpDevice *device)
|
||||
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
||||
goto err_close;
|
||||
|
||||
/* TODO: Do not do this synchronous. */
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
||||
goto err_close;
|
||||
|
||||
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
||||
goto err_close;
|
||||
|
||||
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
|
||||
|
||||
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
|
||||
while(1)
|
||||
{
|
||||
g_warning ("Transfer in response to version query was too short");
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
g_warning ("Device responded with error: %d", status);
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
/* TODO: Do not do this synchronous. */
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
||||
goto err_close;
|
||||
|
||||
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
|
||||
transfer = fpi_usb_transfer_new (device);
|
||||
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
|
||||
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
||||
goto err_close;
|
||||
|
||||
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
|
||||
|
||||
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
|
||||
{
|
||||
g_warning ("Transfer in response to version query was too short");
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
g_warning ("Device responded with error: %d retry: %d", status, retry);
|
||||
if(retry)
|
||||
{
|
||||
retry = FALSE;
|
||||
continue;
|
||||
}
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||
goto err_close;
|
||||
}
|
||||
break;
|
||||
}
|
||||
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
|
||||
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
|
||||
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
|
||||
@@ -975,40 +1271,7 @@ dev_probe (FpDevice *device)
|
||||
fp_dbg ("Target: %d", self->mis_version.target);
|
||||
fp_dbg ("Product: %d", self->mis_version.product);
|
||||
|
||||
|
||||
/* We need at least firmware version 10.1, and for 10.1 build 2989158 */
|
||||
if (self->mis_version.version_major < 10 ||
|
||||
self->mis_version.version_minor < 1 ||
|
||||
(self->mis_version.version_major == 10 &&
|
||||
self->mis_version.version_minor == 1 &&
|
||||
self->mis_version.build_num < 2989158))
|
||||
{
|
||||
fp_warn ("Firmware version %d.%d with build number %d is unsupported",
|
||||
self->mis_version.version_major,
|
||||
self->mis_version.version_minor,
|
||||
self->mis_version.build_num);
|
||||
|
||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||
"Unsupported firmware version "
|
||||
"(%d.%d with build number %d)",
|
||||
self->mis_version.version_major,
|
||||
self->mis_version.version_minor,
|
||||
self->mis_version.build_num);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
/* This is the same as the serial_number from above, hex encoded and somewhat reordered */
|
||||
/* Should we add in more, e.g. the chip revision? */
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
serial = g_strdup ("emulated-device");
|
||||
else
|
||||
serial = g_usb_device_get_string_descriptor (usb_dev,
|
||||
g_usb_device_get_serial_number_index (usb_dev),
|
||||
&error);
|
||||
|
||||
g_usb_device_close (usb_dev, NULL);
|
||||
|
||||
fpi_device_probe_complete (device, serial, NULL, error);
|
||||
synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, prob_msg_cb);
|
||||
|
||||
return;
|
||||
|
||||
@@ -1142,6 +1405,7 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
|
||||
dev_class->close = dev_exit;
|
||||
dev_class->probe = dev_probe;
|
||||
dev_class->verify = verify;
|
||||
dev_class->identify = identify;
|
||||
dev_class->enroll = enroll;
|
||||
dev_class->delete = delete_print;
|
||||
dev_class->cancel = cancel;
|
||||
|
||||
@@ -110,6 +110,7 @@ struct _FpiDeviceSynaptics
|
||||
FpiSsm *cmd_ssm;
|
||||
FpiUsbTransfer *cmd_pending_transfer;
|
||||
gboolean cmd_complete_on_removal;
|
||||
guint8 id_idx;
|
||||
|
||||
bmkt_sensor_version_t mis_version;
|
||||
|
||||
|
||||
@@ -47,17 +47,11 @@ enum {
|
||||
enum sonly_kill_transfers_action {
|
||||
NOT_KILLING = 0,
|
||||
|
||||
/* abort a SSM with an error code */
|
||||
ABORT_SSM,
|
||||
|
||||
/* report an image session error */
|
||||
IMG_SESSION_ERROR,
|
||||
|
||||
/* iterate a SSM to the next state */
|
||||
ITERATE_SSM,
|
||||
|
||||
/* call a callback */
|
||||
EXEC_CALLBACK,
|
||||
};
|
||||
|
||||
enum sonly_fs {
|
||||
@@ -97,13 +91,9 @@ struct _FpiDeviceUpeksonly
|
||||
|
||||
enum sonly_kill_transfers_action killing_transfers;
|
||||
GError *kill_error;
|
||||
union
|
||||
{
|
||||
FpiSsm *kill_ssm;
|
||||
void (*kill_cb)(FpImageDevice *dev);
|
||||
};
|
||||
FpiSsm *kill_ssm;
|
||||
|
||||
struct fpi_line_asmbl_ctx assembling_ctx;
|
||||
struct fpi_line_asmbl_ctx assembling_ctx;
|
||||
};
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceUpeksonly, fpi_device_upeksonly, FPI,
|
||||
DEVICE_UPEKSONLY, FpImageDevice);
|
||||
@@ -176,11 +166,6 @@ last_transfer_killed (FpImageDevice *dev)
|
||||
|
||||
switch (self->killing_transfers)
|
||||
{
|
||||
case ABORT_SSM:
|
||||
fp_dbg ("abort ssm error %s", self->kill_error->message);
|
||||
fpi_ssm_mark_failed (self->kill_ssm, g_steal_pointer (&self->kill_error));
|
||||
return;
|
||||
|
||||
case ITERATE_SSM:
|
||||
fp_dbg ("iterate ssm");
|
||||
fpi_ssm_next_state (self->kill_ssm);
|
||||
@@ -531,6 +516,14 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: The old code assume 4096 bytes are received each time
|
||||
* but there is no reason we need to enforce that. However, we
|
||||
* always need full lines. */
|
||||
if (transfer->actual_length % 64 != 0)
|
||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Data packets need to be multiple of 64 bytes, got %zi bytes",
|
||||
transfer->actual_length);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_warn ("bad status %s, terminating session", error->message);
|
||||
@@ -551,7 +544,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
* the first 2 bytes are a sequence number
|
||||
* then there are 62 bytes for image data
|
||||
*/
|
||||
for (i = 0; i < 4096; i += 64)
|
||||
for (i = 0; i + 64 <= transfer->actual_length; i += 64)
|
||||
{
|
||||
if (!is_capturing (self))
|
||||
return;
|
||||
@@ -560,7 +553,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
if (is_capturing (self))
|
||||
{
|
||||
fpi_usb_transfer_submit (transfer,
|
||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
||||
0,
|
||||
self->img_cancellable,
|
||||
img_data_cb,
|
||||
@@ -588,6 +581,8 @@ write_regs_finished (struct write_regs_data *wrdata, GError *error)
|
||||
fpi_ssm_next_state (wrdata->ssm);
|
||||
else
|
||||
fpi_ssm_mark_failed (wrdata->ssm, error);
|
||||
|
||||
g_free (wrdata);
|
||||
}
|
||||
|
||||
static void write_regs_iterate (struct write_regs_data *wrdata);
|
||||
@@ -634,9 +629,9 @@ write_regs_iterate (struct write_regs_data *wrdata)
|
||||
1);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = wrdata->ssm;
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL);
|
||||
|
||||
transfer->buffer[0] = regwrite->value;
|
||||
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, wrdata);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -675,10 +670,10 @@ sm_write_reg (FpiSsm *ssm,
|
||||
1);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
transfer->buffer[0] = value;
|
||||
|
||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
|
||||
transfer->buffer[0] = value;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -908,7 +903,7 @@ capsm_fire_bulk (FpiSsm *ssm,
|
||||
self->img_cancellable = g_cancellable_new ();
|
||||
for (i = 0; i < self->img_transfers->len; i++)
|
||||
{
|
||||
fpi_usb_transfer_submit (g_ptr_array_index (self->img_transfers, i),
|
||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (g_ptr_array_index (self->img_transfers, i)),
|
||||
0,
|
||||
self->img_cancellable,
|
||||
img_data_cb,
|
||||
@@ -1406,8 +1401,12 @@ dev_activate (FpImageDevice *dev)
|
||||
self->capturing = FALSE;
|
||||
|
||||
self->num_flying = 0;
|
||||
self->img_transfers = g_ptr_array_new_with_free_func ((GFreeFunc) fpi_usb_transfer_unref);
|
||||
|
||||
for (i = 0; i < self->img_transfers->len; i++)
|
||||
/* This might seem odd, but we do need multiple in-flight URBs so that
|
||||
* we never stop polling the device for more data.
|
||||
*/
|
||||
for (i = 0; i < NUM_BULK_TRANSFERS; i++)
|
||||
{
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ finger_present (unsigned char *img, size_t len, int sum_threshold)
|
||||
if (img[i] < 160)
|
||||
sum++;
|
||||
|
||||
fp_dbg ("finger_present: sum is %d\n", sum);
|
||||
fp_dbg ("finger_present: sum is %d", sum);
|
||||
return sum < sum_threshold ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("data transfer status %s\n", error->message);
|
||||
fp_dbg ("data transfer status %s", error->message);
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_dbg ("req transfer status %s\n", error->message);
|
||||
fp_dbg ("req transfer status %s", error->message);
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
@@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_err ("Device variant %lu is not known\n", driver_data);
|
||||
fp_err ("Device variant %lu is not known", driver_data);
|
||||
g_assert_not_reached ();
|
||||
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
return;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define UPEKTC_CMD_LEN 0x40
|
||||
|
||||
@@ -78,6 +78,7 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
|
||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
static void
|
||||
upektc_img_submit_req (FpiSsm *ssm,
|
||||
FpImageDevice *dev,
|
||||
@@ -193,7 +194,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
if (self->deactivating)
|
||||
{
|
||||
fp_dbg ("Deactivate requested\n");
|
||||
fp_dbg ("Deactivate requested");
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +209,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
|
||||
{
|
||||
fp_dbg ("Terminating SSM\n");
|
||||
fp_dbg ("Terminating SSM");
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
return;
|
||||
}
|
||||
@@ -219,7 +220,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||
if (response_size > transfer->actual_length)
|
||||
{
|
||||
fp_dbg ("response_size is %lu, actual_length is %d\n",
|
||||
fp_dbg ("response_size is %lu, actual_length is %d",
|
||||
response_size, (gint) transfer->actual_length);
|
||||
fp_dbg ("Waiting for rest of transfer");
|
||||
BUG_ON (self->response_rest);
|
||||
@@ -237,7 +238,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
{
|
||||
/* No finger */
|
||||
case 0x28:
|
||||
fp_dbg ("18th byte is %.2x\n", data[18]);
|
||||
fp_dbg ("18th byte is %.2x", data[18]);
|
||||
switch (data[18])
|
||||
{
|
||||
case 0x0c:
|
||||
@@ -254,7 +255,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
case 0x1e:
|
||||
/* short scan */
|
||||
fp_err ("short scan, aborting\n");
|
||||
fp_err ("short scan, aborting");
|
||||
fpi_image_device_retry_scan (dev,
|
||||
FP_DEVICE_RETRY_TOO_SHORT);
|
||||
fpi_image_device_report_finger_status (dev,
|
||||
@@ -265,7 +266,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
case 0x1d:
|
||||
/* too much horisontal movement */
|
||||
fp_err ("too much horisontal movement, aborting\n");
|
||||
fp_err ("too much horisontal movement, aborting");
|
||||
fpi_image_device_retry_scan (dev,
|
||||
FP_DEVICE_RETRY_CENTER_FINGER);
|
||||
fpi_image_device_report_finger_status (dev,
|
||||
@@ -276,7 +277,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
default:
|
||||
/* some error happened, cancel scan */
|
||||
fp_err ("something bad happened, stop scan\n");
|
||||
fp_err ("something bad happened, stop scan");
|
||||
fpi_image_device_retry_scan (dev,
|
||||
FP_DEVICE_RETRY);
|
||||
fpi_image_device_report_finger_status (dev,
|
||||
@@ -307,7 +308,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
||||
data);
|
||||
BUG_ON (self->image_size != IMAGE_SIZE);
|
||||
fp_dbg ("Image size is %lu\n",
|
||||
fp_dbg ("Image size is %lu",
|
||||
self->image_size);
|
||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
||||
img->flags |= FPI_IMAGE_PARTIAL;
|
||||
@@ -320,7 +321,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_err ("Unknown response!\n");
|
||||
fp_err ("Unknown response!");
|
||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
break;
|
||||
}
|
||||
@@ -331,7 +332,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_err ("Not handled response!\n");
|
||||
fp_err ("Not handled response!");
|
||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,15 +527,6 @@ initsm_read_msg_response_cb (FpiSsm *ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected response subcommand"));
|
||||
}
|
||||
else if (seq != upekdev->seq)
|
||||
{
|
||||
fp_err ("expected response to cmd seq=%02x, got response to %02x "
|
||||
"in state %d", upekdev->seq, seq,
|
||||
fpi_ssm_get_cur_state (ssm));
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected sequence number in response"));
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_ssm_next_state (ssm);
|
||||
|
||||
@@ -81,7 +81,7 @@ static const struct uru4k_dev_profile
|
||||
{
|
||||
const char *name;
|
||||
gboolean auth_cr;
|
||||
gboolean encryption;
|
||||
gboolean image_not_flipped;
|
||||
} uru4k_dev_info[] = {
|
||||
[MS_KBD] = {
|
||||
.name = "Microsoft Keyboard with Fingerprint Reader",
|
||||
@@ -106,7 +106,7 @@ static const struct uru4k_dev_profile
|
||||
[DP_URU4000B] = {
|
||||
.name = "Digital Persona U.are.U 4000B",
|
||||
.auth_cr = FALSE,
|
||||
.encryption = TRUE,
|
||||
.image_not_flipped = TRUE, /* See comment in the code where it is used. */
|
||||
},
|
||||
};
|
||||
|
||||
@@ -375,6 +375,10 @@ stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb)
|
||||
g_cancellable_cancel (self->irq_cancellable);
|
||||
self->irqs_stopped_cb = cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
cb (dev);
|
||||
}
|
||||
}
|
||||
|
||||
/***** STATE CHANGING *****/
|
||||
@@ -412,18 +416,6 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||
{
|
||||
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
||||
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
self->activate_state = state;
|
||||
if (self->img_transfer != NULL)
|
||||
return;
|
||||
@@ -663,7 +655,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
case IMAGING_CAPTURE:
|
||||
self->img_lines_done = 0;
|
||||
self->img_block = 0;
|
||||
fpi_usb_transfer_submit (self->img_transfer, 0, NULL, image_transfer_cb, NULL);
|
||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (self->img_transfer),
|
||||
0,
|
||||
NULL,
|
||||
image_transfer_cb,
|
||||
NULL);
|
||||
|
||||
break;
|
||||
|
||||
@@ -680,17 +676,17 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
||||
return;
|
||||
}
|
||||
if (!self->profile->encryption)
|
||||
|
||||
/* Detect whether image is encrypted (by checking how noisy it is) */
|
||||
dev2 = calc_dev2 (img);
|
||||
fp_dbg ("dev2: %d", dev2);
|
||||
if (dev2 < ENC_THRESHOLD)
|
||||
{
|
||||
dev2 = calc_dev2 (img);
|
||||
fp_dbg ("dev2: %d", dev2);
|
||||
if (dev2 < ENC_THRESHOLD)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE);
|
||||
return;
|
||||
}
|
||||
fp_info ("image seems to be encrypted");
|
||||
fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE);
|
||||
return;
|
||||
}
|
||||
fp_info ("image seems to be encrypted");
|
||||
|
||||
buf[0] = img->key_number;
|
||||
buf[1] = self->img_enc_seed;
|
||||
buf[2] = self->img_enc_seed >> 8;
|
||||
@@ -723,7 +719,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
num_lines);
|
||||
if (flags & BLOCKF_CHANGE_KEY)
|
||||
{
|
||||
fp_dbg ("changing encryption keys.\n");
|
||||
fp_dbg ("changing encryption keys.");
|
||||
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
|
||||
img->key_number++;
|
||||
self->img_enc_seed = rand ();
|
||||
@@ -769,7 +765,13 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
}
|
||||
|
||||
fpimg->flags = FPI_IMAGE_COLORS_INVERTED;
|
||||
if (!self->profile->encryption)
|
||||
/* NOTE: For some reason all but U4000B (or rather U4500?) flipped the
|
||||
* image, we retain this behaviour here, but it is not clear whether it
|
||||
* is correct.
|
||||
* It may be that there are different models with the same USB ID that
|
||||
* behave differently.
|
||||
*/
|
||||
if (self->profile->image_not_flipped)
|
||||
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||
fpi_image_device_image_captured (dev, fpimg);
|
||||
|
||||
@@ -793,8 +795,7 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
if (error)
|
||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||
|
||||
/* Freed by callback or cancellation */
|
||||
self->img_transfer = NULL;
|
||||
g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref);
|
||||
|
||||
g_free (self->img_data);
|
||||
self->img_data = NULL;
|
||||
@@ -1176,7 +1177,10 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||
static void
|
||||
dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
/* This is started/handled by execute_state_change in order to delay the
|
||||
* action until after the image transfer has completed.
|
||||
* We just need to override the function so that the complete handler is
|
||||
* not called automatically. */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1187,7 +1191,7 @@ execute_state_change (FpImageDevice *dev)
|
||||
|
||||
switch (self->activate_state)
|
||||
{
|
||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
|
||||
fp_dbg ("deactivating");
|
||||
self->irq_cb = NULL;
|
||||
self->irq_cb_data = NULL;
|
||||
@@ -1242,6 +1246,12 @@ execute_state_change (FpImageDevice *dev)
|
||||
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
|
||||
change_state_write_reg_cb, NULL);
|
||||
break;
|
||||
|
||||
/* Ignored states */
|
||||
case FPI_IMAGE_DEVICE_STATE_IDLE:
|
||||
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
|
||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
}
|
||||
|
||||
/* Send data to EP1, the only out endpoint */
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
static void
|
||||
async_write (FpiSsm *ssm,
|
||||
FpDevice *dev,
|
||||
@@ -117,9 +118,10 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
int ep = transfer->endpoint;
|
||||
|
||||
/* In normal case endpoint is empty */
|
||||
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
|
||||
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
|
||||
(g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
|
||||
{
|
||||
g_error_free (error);
|
||||
g_clear_error (&error);
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,18 +147,6 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Complete loop sequential state machine */
|
||||
static void
|
||||
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
g_warning ("State machine completed with an error: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
/* Free sequential state machine */
|
||||
}
|
||||
|
||||
/* Exec init sequential state machine */
|
||||
static void
|
||||
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
@@ -176,19 +164,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
static void
|
||||
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpiSsm *ssm_loop;
|
||||
|
||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
||||
if (!error)
|
||||
{
|
||||
/* Notify activate complete */
|
||||
|
||||
/* Start loop ssm */
|
||||
ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES);
|
||||
fpi_ssm_start (ssm_loop, m_loop_complete);
|
||||
}
|
||||
|
||||
/* Free sequential state machine */
|
||||
}
|
||||
|
||||
/* Activate device */
|
||||
@@ -213,6 +189,19 @@ dev_deactivate (FpImageDevice *dev)
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||
{
|
||||
FpiSsm *ssm_loop;
|
||||
|
||||
if (state != FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
return;
|
||||
|
||||
/* Start a capture operation. */
|
||||
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
|
||||
fpi_ssm_start (ssm_loop, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open (FpImageDevice *dev)
|
||||
{
|
||||
@@ -273,6 +262,7 @@ fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
||||
img_class->img_close = dev_close;
|
||||
img_class->activate = dev_activate;
|
||||
img_class->deactivate = dev_deactivate;
|
||||
img_class->change_state = dev_change_state;
|
||||
|
||||
img_class->bz3_threshold = 24;
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
|
||||
*out = g_steal_pointer (&transfer);
|
||||
}
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 2, 3)
|
||||
static void
|
||||
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
||||
{
|
||||
@@ -212,11 +213,9 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||
*len = 1;
|
||||
return data;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0B:
|
||||
return vfs301_proto_generate_0B (subtype, len);
|
||||
break;
|
||||
|
||||
case 0x02D0:
|
||||
{
|
||||
@@ -232,22 +231,18 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
||||
return translate_str (dataLs[subtype - 1], len);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0220:
|
||||
switch (subtype)
|
||||
{
|
||||
case 1:
|
||||
return translate_str (vfs301_0220_01, len);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
return translate_str (vfs301_0220_02, len);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
return translate_str (vfs301_0220_03, len);
|
||||
break;
|
||||
|
||||
case 0xFA00:
|
||||
case 0x2C01:
|
||||
@@ -270,7 +265,6 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||
field[3] = field[1];
|
||||
|
||||
return data;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -438,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) x, sizeof (x)
|
||||
#define RAW_DATA(x) g_memdup (x, sizeof (x)), sizeof (x)
|
||||
|
||||
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
||||
|
||||
@@ -508,30 +502,30 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
|
||||
FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
FpDeviceVfs301 *dev = user_data;
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Error receiving data: %s", error->message);
|
||||
g_error_free (error);
|
||||
dev->recv_progress = VFS301_FAILURE;
|
||||
self->recv_progress = VFS301_FAILURE;
|
||||
return;
|
||||
}
|
||||
else if (transfer->actual_length < transfer->length)
|
||||
{
|
||||
/* TODO: process the data anyway? */
|
||||
dev->recv_progress = VFS301_ENDED;
|
||||
self->recv_progress = VFS301_ENDED;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
FpiUsbTransfer *new;
|
||||
if (!vfs301_proto_process_data (dev,
|
||||
if (!vfs301_proto_process_data (self,
|
||||
transfer->length == VFS301_FP_RECV_LEN_1,
|
||||
transfer->buffer,
|
||||
transfer->actual_length))
|
||||
{
|
||||
dev->recv_progress = VFS301_ENDED;
|
||||
self->recv_progress = VFS301_ENDED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
/* There are many similar blocks in the data below, also the data are
|
||||
* self-similar (looks like some config blocks? pokes like in vfs101?) */
|
||||
|
||||
@@ -1621,56 +1623,56 @@ static const unsigned char vfs301_24[] = { /* 119 B */
|
||||
#define vfs301_02D0_ALIGNED_BLOB \
|
||||
PACKET ("0200", "8005", \
|
||||
"FF830720" "5F820720" "FF830720" \
|
||||
"5F820720" "FF830720" "5F820720" "FF830720" \
|
||||
"5F820720" "FF830720" "5F820720" "FF8B0720" \
|
||||
"608A0720" "FF930720" "61920720" "FF9B0720" \
|
||||
"629A0720" "FFA30720" "63A20720" "FFAB0720" \
|
||||
"64AA0720" "FFB30720" "65B20720" "FFBB0720" \
|
||||
"66BA0720" "FFC30720" "67C20720" "FFCB0720" \
|
||||
"68CA0720" "FFD30720" "69D20720" "FFDB0720" \
|
||||
"6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \
|
||||
"6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \
|
||||
"6EFA0720" "FF850720" "6F840720" "FF8D0720" \
|
||||
"708C0720" "FF950720" "71940720" "FF9D0720" \
|
||||
"729C0720" "FFA50720" "73A40720" "FFAD0720" \
|
||||
"74AC0720" "FFB50720" "75B40720" "FFBD0720" \
|
||||
"76BC0720" "FFC50720" "77C40720" "FFCD0720" \
|
||||
"78CC0720" "FFD50720" "79D40720" "FFDD0720" \
|
||||
"7ADC0720" "FFE50720" "7BE40720" "FFED0720" \
|
||||
"7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \
|
||||
"7EFC0720" "FF870720" "7F860720" "FF8F0720" \
|
||||
"808E0720" "FF970720" "81960720" "FF9F0720" \
|
||||
"829E0720" "FFA70720" "83A60720" "FFAF0720" \
|
||||
"84AE0720" "FFB70720" "85B60720" "FFBF0720" \
|
||||
"86BE0720" "FFC70720" "87C60720" "FFCF0720" \
|
||||
"88CE0720" "FFD70720" "89D60720" "FFDF0720" \
|
||||
"8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \
|
||||
"8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \
|
||||
"8EFE0720" \
|
||||
"FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \
|
||||
"FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \
|
||||
"FFDF0720" "8ADE0720" "FFD70720" "89D60720" \
|
||||
"FFCF0720" "88CE0720" "FFC70720" "87C60720" \
|
||||
"FFBF0720" "86BE0720" "FFB70720" "85B60720" \
|
||||
"FFAF0720" "84AE0720" "FFA70720" "83A60720" \
|
||||
"FF9F0720" "829E0720" "FF970720" "81960720" \
|
||||
"FF8F0720" "808E0720" "FF870720" "7F860720" \
|
||||
"FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \
|
||||
"FFED0720" "7CEC0720" "FFE50720" "7BE40720" \
|
||||
"FFDD0720" "7ADC0720" "FFD50720" "79D40720" \
|
||||
"FFCD0720" "78CC0720" "FFC50720" "77C40720" \
|
||||
"FFBD0720" "76BC0720" "FFB50720" "75B40720" \
|
||||
"FFAD0720" "74AC0720" "FFA50720" "73A40720" \
|
||||
"FF9D0720" "729C0720" "FF950720" "71940720" \
|
||||
"FF8D0720" "708C0720" "FF850720" "6F840720" \
|
||||
"FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \
|
||||
"FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \
|
||||
"FFDB0720" "6ADA0720" "FFD30720" "69D20720" \
|
||||
"FFCB0720" "68CA0720" "FFC30720" "67C20720" \
|
||||
"FFBB0720" "66BA0720" "FFB30720" "65B20720" \
|
||||
"FFAB0720" "64AA0720" "FFA30720" "63A20720" \
|
||||
"FF9B0720" "629A0720" "FF930720" "61920720" \
|
||||
"FF8B0720" "608A0720" "FF830720" "5F820720" \
|
||||
"5F820720" "FF830720" "5F820720" "FF830720" \
|
||||
"5F820720" "FF830720" "5F820720" "FF8B0720" \
|
||||
"608A0720" "FF930720" "61920720" "FF9B0720" \
|
||||
"629A0720" "FFA30720" "63A20720" "FFAB0720" \
|
||||
"64AA0720" "FFB30720" "65B20720" "FFBB0720" \
|
||||
"66BA0720" "FFC30720" "67C20720" "FFCB0720" \
|
||||
"68CA0720" "FFD30720" "69D20720" "FFDB0720" \
|
||||
"6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \
|
||||
"6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \
|
||||
"6EFA0720" "FF850720" "6F840720" "FF8D0720" \
|
||||
"708C0720" "FF950720" "71940720" "FF9D0720" \
|
||||
"729C0720" "FFA50720" "73A40720" "FFAD0720" \
|
||||
"74AC0720" "FFB50720" "75B40720" "FFBD0720" \
|
||||
"76BC0720" "FFC50720" "77C40720" "FFCD0720" \
|
||||
"78CC0720" "FFD50720" "79D40720" "FFDD0720" \
|
||||
"7ADC0720" "FFE50720" "7BE40720" "FFED0720" \
|
||||
"7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \
|
||||
"7EFC0720" "FF870720" "7F860720" "FF8F0720" \
|
||||
"808E0720" "FF970720" "81960720" "FF9F0720" \
|
||||
"829E0720" "FFA70720" "83A60720" "FFAF0720" \
|
||||
"84AE0720" "FFB70720" "85B60720" "FFBF0720" \
|
||||
"86BE0720" "FFC70720" "87C60720" "FFCF0720" \
|
||||
"88CE0720" "FFD70720" "89D60720" "FFDF0720" \
|
||||
"8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \
|
||||
"8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \
|
||||
"8EFE0720" \
|
||||
"FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \
|
||||
"FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \
|
||||
"FFDF0720" "8ADE0720" "FFD70720" "89D60720" \
|
||||
"FFCF0720" "88CE0720" "FFC70720" "87C60720" \
|
||||
"FFBF0720" "86BE0720" "FFB70720" "85B60720" \
|
||||
"FFAF0720" "84AE0720" "FFA70720" "83A60720" \
|
||||
"FF9F0720" "829E0720" "FF970720" "81960720" \
|
||||
"FF8F0720" "808E0720" "FF870720" "7F860720" \
|
||||
"FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \
|
||||
"FFED0720" "7CEC0720" "FFE50720" "7BE40720" \
|
||||
"FFDD0720" "7ADC0720" "FFD50720" "79D40720" \
|
||||
"FFCD0720" "78CC0720" "FFC50720" "77C40720" \
|
||||
"FFBD0720" "76BC0720" "FFB50720" "75B40720" \
|
||||
"FFAD0720" "74AC0720" "FFA50720" "73A40720" \
|
||||
"FF9D0720" "729C0720" "FF950720" "71940720" \
|
||||
"FF8D0720" "708C0720" "FF850720" "6F840720" \
|
||||
"FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \
|
||||
"FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \
|
||||
"FFDB0720" "6ADA0720" "FFD30720" "69D20720" \
|
||||
"FFCB0720" "68CA0720" "FFC30720" "67C20720" \
|
||||
"FFBB0720" "66BA0720" "FFB30720" "65B20720" \
|
||||
"FFAB0720" "64AA0720" "FFA30720" "63A20720" \
|
||||
"FF9B0720" "629A0720" "FF930720" "61920720" \
|
||||
"FF8B0720" "608A0720" "FF830720" "5F820720" \
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
|
||||
@@ -1871,49 +1873,49 @@ const char *vfs301_0220_01[] = {
|
||||
"A46C0420"
|
||||
"A46C0400"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420" "83688420" "83688420"
|
||||
"83688420" "83688420"
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
@@ -2268,55 +2270,55 @@ const char *vfs301_02D0_04[] = {
|
||||
* any troubles. */
|
||||
PACKET ("0200", "8005",
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
"FFF30720" "80F20720" "FFF30720" "80F20720"
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
@@ -2437,55 +2439,55 @@ const char *vfs301_02D0_05[] = {
|
||||
* any troubles. */
|
||||
PACKET ("0200", "8005",
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
"FFF34720" "80F24720" "FFF34720" "80F24720"
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
|
||||
|
||||
@@ -815,13 +815,11 @@ dev_close (FpImageDevice *dev)
|
||||
GError *error = NULL;
|
||||
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
|
||||
|
||||
;
|
||||
|
||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||
0, 0, &error);
|
||||
|
||||
g_free (self->capture_buffer);
|
||||
g_slist_free_full (self->rows, g_free);
|
||||
g_slist_free_full (g_steal_pointer (&self->rows), g_free);
|
||||
|
||||
fpi_image_device_close_complete (dev, error);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
#define VFS5011_LINE_SIZE 240
|
||||
#define VFS5011_IMAGE_WIDTH 160
|
||||
|
||||
|
||||
355
libfprint/drivers/virtual-device-listener.c
Normal file
355
libfprint/drivers/virtual-device-listener.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Socket utilities for "simple" device debugging
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_device_connection"
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gunixsocketaddress.h>
|
||||
|
||||
#include "virtual-device-private.h"
|
||||
|
||||
struct _FpDeviceVirtualListener
|
||||
{
|
||||
GSocketListener parent_instance;
|
||||
|
||||
GSocketConnection *connection;
|
||||
GCancellable *cancellable;
|
||||
guint cancellable_id;
|
||||
|
||||
FpDeviceVirtualListenerConnectionCb ready_cb;
|
||||
gpointer ready_cb_data;
|
||||
|
||||
gint socket_fd;
|
||||
gint client_fd;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
|
||||
|
||||
static void start_listen (FpDeviceVirtualListener *self);
|
||||
|
||||
FpDeviceVirtualListener *
|
||||
fp_device_virtual_listener_new (void)
|
||||
{
|
||||
return g_object_new (fp_device_virtual_listener_get_type (), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_device_virtual_listener_dispose (GObject *object)
|
||||
{
|
||||
FpDeviceVirtualListener *self = FP_DEVICE_VIRTUAL_LISTENER (object);
|
||||
|
||||
if (self->cancellable_id)
|
||||
{
|
||||
g_cancellable_disconnect (self->cancellable, self->cancellable_id);
|
||||
self->cancellable_id = 0;
|
||||
}
|
||||
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
self->ready_cb = NULL;
|
||||
|
||||
G_OBJECT_CLASS (fp_device_virtual_listener_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_device_virtual_listener_class_init (FpDeviceVirtualListenerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = fp_device_virtual_listener_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
fp_device_virtual_listener_init (FpDeviceVirtualListener *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualListener *self = user_data;
|
||||
GSocketConnection *connection;
|
||||
|
||||
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
|
||||
res,
|
||||
NULL,
|
||||
&error);
|
||||
if (!connection)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
g_warning ("Error accepting a new connection: %s", error->message);
|
||||
start_listen (self);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Always allow further connections.
|
||||
* If we get a new one, we generally just close the old connection. */
|
||||
start_listen (self);
|
||||
if (self->connection)
|
||||
{
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
}
|
||||
|
||||
self->connection = connection;
|
||||
fp_dbg ("Got a new connection!");
|
||||
|
||||
self->ready_cb (self, self->ready_cb_data);
|
||||
}
|
||||
|
||||
static void
|
||||
start_listen (FpDeviceVirtualListener *self)
|
||||
{
|
||||
g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
|
||||
self->cancellable,
|
||||
new_connection_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
on_cancelled (GCancellable *cancellable,
|
||||
FpDeviceVirtualListener *self)
|
||||
{
|
||||
fp_device_virtual_listener_connection_close (self);
|
||||
g_socket_listener_close (G_SOCKET_LISTENER (self));
|
||||
g_clear_object (&self->cancellable);
|
||||
self->ready_cb = NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fp_device_virtual_listener_start (FpDeviceVirtualListener *self,
|
||||
const char *address,
|
||||
GCancellable *cancellable,
|
||||
FpDeviceVirtualListenerConnectionCb cb,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GSocketAddress) addr = NULL;
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
|
||||
g_return_val_if_fail (cb != NULL, FALSE);
|
||||
g_return_val_if_fail (self->ready_cb == NULL, FALSE);
|
||||
|
||||
self->client_fd = -1;
|
||||
|
||||
g_socket_listener_set_backlog (G_SOCKET_LISTENER (self), 1);
|
||||
|
||||
/* Remove any left over socket. */
|
||||
g_unlink (address);
|
||||
|
||||
addr = g_unix_socket_address_new (address);
|
||||
|
||||
if (!g_socket_listener_add_address (G_SOCKET_LISTENER (self),
|
||||
addr,
|
||||
G_SOCKET_TYPE_STREAM,
|
||||
G_SOCKET_PROTOCOL_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
error))
|
||||
{
|
||||
g_warning ("Could not listen on unix socket: %s", (*error)->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
self->ready_cb = cb;
|
||||
self->ready_cb_data = user_data;
|
||||
self->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
||||
|
||||
if (self->cancellable)
|
||||
self->cancellable_id = g_cancellable_connect (self->cancellable,
|
||||
G_CALLBACK (on_cancelled), self, NULL);
|
||||
|
||||
start_listen (self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *self)
|
||||
{
|
||||
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
|
||||
|
||||
if (!self->connection)
|
||||
return FALSE;
|
||||
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_stream_read_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
FpDeviceVirtualListener *self = g_task_get_source_object (task);
|
||||
gboolean all;
|
||||
gboolean success;
|
||||
gsize bytes;
|
||||
|
||||
all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "all"));
|
||||
|
||||
if (all)
|
||||
{
|
||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||
}
|
||||
else
|
||||
{
|
||||
gssize sbytes;
|
||||
|
||||
sbytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
|
||||
bytes = sbytes;
|
||||
success = (sbytes >= 0);
|
||||
}
|
||||
|
||||
if (g_task_return_error_if_cancelled (task))
|
||||
return;
|
||||
|
||||
/* If we are cancelled, just return immediately. */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
|
||||
{
|
||||
g_task_return_int (task, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this error is for an old connection (that should be closed already),
|
||||
* then just give up immediately with a CLOSED error.
|
||||
*/
|
||||
if (self->connection &&
|
||||
g_io_stream_get_input_stream (G_IO_STREAM (self->connection)) != G_INPUT_STREAM (source_object))
|
||||
{
|
||||
g_task_return_new_error (task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_CLOSED,
|
||||
"Error on old connection, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success || bytes == 0)
|
||||
{
|
||||
/* We accept it if someone tries to read twice and just return that error. */
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||
{
|
||||
if (self->connection)
|
||||
{
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Got empty data");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_task_return_int (task, bytes);
|
||||
}
|
||||
|
||||
void
|
||||
fp_device_virtual_listener_read (FpDeviceVirtualListener *self,
|
||||
gboolean all,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
GInputStream *stream;
|
||||
|
||||
g_return_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self));
|
||||
|
||||
task = g_task_new (self, self->cancellable, callback, user_data);
|
||||
g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all));
|
||||
|
||||
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
|
||||
"Listener not connected to any stream");
|
||||
return;
|
||||
}
|
||||
|
||||
stream = g_io_stream_get_input_stream (G_IO_STREAM (self->connection));
|
||||
if (all)
|
||||
{
|
||||
g_input_stream_read_all_async (stream, buffer, count,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
on_stream_read_cb,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_input_stream_read_async (stream, buffer, count,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
on_stream_read_cb,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
}
|
||||
|
||||
gsize
|
||||
fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (result, self), 0);
|
||||
|
||||
return g_task_propagate_int (G_TASK (result), error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self,
|
||||
const char *buffer,
|
||||
gsize count,
|
||||
GError **error)
|
||||
{
|
||||
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
|
||||
"Listener not connected to any stream");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (self->connection)),
|
||||
buffer,
|
||||
count,
|
||||
NULL,
|
||||
self->cancellable,
|
||||
error);
|
||||
}
|
||||
109
libfprint/drivers/virtual-device-private.h
Normal file
109
libfprint/drivers/virtual-device-private.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Virtual driver for "simple" device debugging
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the non-image based drivers. A small
|
||||
* python script is provided to connect to it via a socket, allowing
|
||||
* prints to registered programmatically.
|
||||
* Using this, it is possible to test libfprint and fprintd.
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fpi-device.h"
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, FP, DEVICE_VIRTUAL_LISTENER, GSocketListener)
|
||||
|
||||
typedef void (*FpDeviceVirtualListenerConnectionCb) (FpDeviceVirtualListener *listener,
|
||||
gpointer user_data);
|
||||
|
||||
FpDeviceVirtualListener * fp_device_virtual_listener_new (void);
|
||||
|
||||
gboolean fp_device_virtual_listener_start (FpDeviceVirtualListener *listener,
|
||||
const char *address,
|
||||
GCancellable *cancellable,
|
||||
FpDeviceVirtualListenerConnectionCb cb,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
gboolean fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *listener);
|
||||
|
||||
void fp_device_virtual_listener_read (FpDeviceVirtualListener *listener,
|
||||
gboolean all,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gsize fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *listener,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
gboolean fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self,
|
||||
const char *buffer,
|
||||
gsize count,
|
||||
GError **error);
|
||||
|
||||
|
||||
struct _FpDeviceVirtualDevice
|
||||
{
|
||||
FpDevice parent;
|
||||
|
||||
FpDeviceVirtualListener *listener;
|
||||
GCancellable *cancellable;
|
||||
|
||||
char recv_buf[MAX_LINE_LEN];
|
||||
|
||||
GPtrArray *pending_commands;
|
||||
|
||||
GHashTable *prints_storage;
|
||||
|
||||
guint wait_command_id;
|
||||
guint sleep_timeout_id;
|
||||
guint enroll_stages_passed;
|
||||
gboolean match_reported;
|
||||
gboolean supports_cancellation;
|
||||
gboolean injected_synthetic_cmd;
|
||||
gboolean ignore_wait;
|
||||
gboolean keep_alive;
|
||||
};
|
||||
|
||||
/* Not really final here, but we can do this to share the FpDeviceVirtualDevice
|
||||
* contents without having to use a shared private struct instead. */
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP, DEVICE_VIRTUAL_DEVICE, FpDevice)
|
||||
|
||||
struct _FpDeviceVirtualDeviceStorage
|
||||
{
|
||||
FpDeviceVirtualDevice parent;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice)
|
||||
|
||||
|
||||
char * process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError **error);
|
||||
char * start_scan_command (FpDeviceVirtualDevice *self,
|
||||
GError **error);
|
||||
gboolean should_wait_for_command (FpDeviceVirtualDevice *self,
|
||||
GError *error);
|
||||
gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self,
|
||||
const char *scan_id,
|
||||
GError *error);
|
||||
247
libfprint/drivers/virtual-device-storage.c
Normal file
247
libfprint/drivers/virtual-device-storage.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Virtual driver for "simple" device debugging with storage
|
||||
*
|
||||
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the non-image based drivers. A small
|
||||
* python script is provided to connect to it via a socket, allowing
|
||||
* prints to registered programmatically.
|
||||
* Using this, it is possible to test libfprint and fprintd.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_device_storage"
|
||||
|
||||
#include "virtual-device-private.h"
|
||||
#include "fpi-log.h"
|
||||
|
||||
G_DEFINE_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, fpi_device_virtual_device_get_type ())
|
||||
|
||||
static GPtrArray * get_stored_prints (FpDeviceVirtualDevice * self);
|
||||
|
||||
static void
|
||||
dev_identify (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
g_autofree char *scan_id = NULL;
|
||||
|
||||
scan_id = start_scan_command (self, &error);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||
return;
|
||||
|
||||
if (scan_id)
|
||||
{
|
||||
g_autoptr(GPtrArray) stored = get_stored_prints (self);
|
||||
GPtrArray *prints;
|
||||
GVariant *data = NULL;
|
||||
FpPrint *new_scan;
|
||||
FpPrint *match = NULL;
|
||||
guint idx;
|
||||
|
||||
new_scan = fp_print_new (dev);
|
||||
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
|
||||
fpi_print_set_device_stored (new_scan, TRUE);
|
||||
data = g_variant_new_string (scan_id);
|
||||
g_object_set (new_scan, "fpi-data", data, NULL);
|
||||
|
||||
fpi_device_get_identify_data (dev, &prints);
|
||||
g_debug ("Trying to identify print '%s' against a gallery of %u prints", scan_id, prints->len);
|
||||
|
||||
if (!g_ptr_array_find_with_equal_func (stored,
|
||||
new_scan,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
NULL))
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND);
|
||||
else if (g_ptr_array_find_with_equal_func (prints,
|
||||
new_scan,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&idx))
|
||||
match = g_ptr_array_index (prints, idx);
|
||||
|
||||
if (!self->match_reported)
|
||||
{
|
||||
self->match_reported = TRUE;
|
||||
fpi_device_identify_report (dev,
|
||||
match,
|
||||
new_scan,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
else if (error && error->domain == FP_DEVICE_RETRY)
|
||||
{
|
||||
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
if (should_wait_to_sleep (self, scan_id, error))
|
||||
return;
|
||||
|
||||
self->match_reported = FALSE;
|
||||
fpi_device_identify_complete (dev, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
struct ListData
|
||||
{
|
||||
FpDevice *dev;
|
||||
GPtrArray *res;
|
||||
};
|
||||
|
||||
static void
|
||||
dev_list_insert_print (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct ListData *data = user_data;
|
||||
FpPrint *print = fp_print_new (data->dev);
|
||||
GVariant *var = NULL;
|
||||
|
||||
fpi_print_fill_from_user_id (print, key);
|
||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||
var = g_variant_new_string (key);
|
||||
g_object_set (print, "fpi-data", var, NULL);
|
||||
g_object_ref_sink (print);
|
||||
|
||||
g_ptr_array_add (data->res, print);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
get_stored_prints (FpDeviceVirtualDevice *self)
|
||||
{
|
||||
GPtrArray * prints_list;
|
||||
struct ListData data;
|
||||
|
||||
prints_list = g_ptr_array_new_full (g_hash_table_size (self->prints_storage),
|
||||
g_object_unref);
|
||||
data.dev = FP_DEVICE (self);
|
||||
data.res = prints_list;
|
||||
|
||||
g_hash_table_foreach (self->prints_storage, dev_list_insert_print, &data);
|
||||
|
||||
return prints_list;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_list (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GPtrArray) prints_list = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
|
||||
process_cmds (vdev, FALSE, &error);
|
||||
if (should_wait_for_command (vdev, error))
|
||||
return;
|
||||
|
||||
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
fpi_device_list_complete (dev, NULL, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_list_complete (dev, get_stored_prints (vdev), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_delete (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
FpPrint *print = NULL;
|
||||
const char *id = NULL;
|
||||
|
||||
process_cmds (vdev, FALSE, &error);
|
||||
if (should_wait_for_command (vdev, error))
|
||||
return;
|
||||
|
||||
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
fpi_device_delete_complete (dev, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_get_delete_data (dev, &print);
|
||||
|
||||
g_object_get (print, "fpi-data", &data, NULL);
|
||||
if (data == NULL)
|
||||
{
|
||||
fpi_device_delete_complete (dev,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
||||
return;
|
||||
}
|
||||
|
||||
id = g_variant_get_string (data, NULL);
|
||||
|
||||
fp_dbg ("Deleting print %s for user %s",
|
||||
id,
|
||||
fp_print_get_username (print));
|
||||
|
||||
if (g_hash_table_remove (vdev->prints_storage, id))
|
||||
fpi_device_delete_complete (dev, NULL);
|
||||
else
|
||||
fpi_device_delete_complete (dev,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self)
|
||||
{
|
||||
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (self);
|
||||
|
||||
vdev->prints_storage = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_storage_finalize (GObject *object)
|
||||
{
|
||||
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (object);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
g_clear_pointer (&vdev->prints_storage, g_hash_table_destroy);
|
||||
G_OBJECT_CLASS (fpi_device_virtual_device_storage_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE" },
|
||||
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_IDENT" },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_storage_class_init (FpDeviceVirtualDeviceStorageClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fpi_device_virtual_device_storage_finalize;
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual device with storage and identification for debugging";
|
||||
dev_class->id_table = driver_ids;
|
||||
|
||||
dev_class->identify = dev_identify;
|
||||
dev_class->list = dev_list;
|
||||
dev_class->delete = dev_delete;
|
||||
}
|
||||
779
libfprint/drivers/virtual-device.c
Normal file
779
libfprint/drivers/virtual-device.c
Normal file
@@ -0,0 +1,779 @@
|
||||
/*
|
||||
* Virtual driver for "simple" device debugging
|
||||
*
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the non-image based drivers. A small
|
||||
* python script is provided to connect to it via a socket, allowing
|
||||
* prints to registered programmatically.
|
||||
* Using this, it is possible to test libfprint and fprintd.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_device"
|
||||
|
||||
#include "virtual-device-private.h"
|
||||
#include "fpi-log.h"
|
||||
|
||||
G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE)
|
||||
|
||||
#define INSERT_CMD_PREFIX "INSERT "
|
||||
#define REMOVE_CMD_PREFIX "REMOVE "
|
||||
#define SCAN_CMD_PREFIX "SCAN "
|
||||
#define ERROR_CMD_PREFIX "ERROR "
|
||||
#define RETRY_CMD_PREFIX "RETRY "
|
||||
#define FINGER_CMD_PREFIX "FINGER "
|
||||
#define SLEEP_CMD_PREFIX "SLEEP "
|
||||
#define SET_ENROLL_STAGES_PREFIX "SET_ENROLL_STAGES "
|
||||
#define SET_SCAN_TYPE_PREFIX "SET_SCAN_TYPE "
|
||||
#define SET_CANCELLATION_PREFIX "SET_CANCELLATION_ENABLED "
|
||||
#define SET_KEEP_ALIVE_PREFIX "SET_KEEP_ALIVE "
|
||||
|
||||
#define LIST_CMD "LIST"
|
||||
#define UNPLUG_CMD "UNPLUG"
|
||||
|
||||
static void
|
||||
maybe_continue_current_action (FpDeviceVirtualDevice *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
|
||||
if (self->sleep_timeout_id)
|
||||
return;
|
||||
|
||||
switch (fpi_device_get_current_action (dev))
|
||||
{
|
||||
case FPI_DEVICE_ACTION_ENROLL:
|
||||
FP_DEVICE_GET_CLASS (self)->enroll (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_VERIFY:
|
||||
FP_DEVICE_GET_CLASS (self)->verify (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_IDENTIFY:
|
||||
FP_DEVICE_GET_CLASS (self)->identify (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_LIST:
|
||||
FP_DEVICE_GET_CLASS (self)->list (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_DELETE:
|
||||
FP_DEVICE_GET_CLASS (self)->delete (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_OPEN:
|
||||
FP_DEVICE_GET_CLASS (self)->open (dev);
|
||||
break;
|
||||
|
||||
case FPI_DEVICE_ACTION_CLOSE:
|
||||
FP_DEVICE_GET_CLASS (self)->close (dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sleep_timeout_cb (gpointer data)
|
||||
{
|
||||
FpDeviceVirtualDevice *self = data;
|
||||
|
||||
self->sleep_timeout_id = 0;
|
||||
|
||||
if (g_cancellable_is_cancelled (self->cancellable))
|
||||
return FALSE;
|
||||
|
||||
g_debug ("Sleeping completed");
|
||||
maybe_continue_current_action (self);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char *
|
||||
process_cmds (FpDeviceVirtualDevice * self,
|
||||
gboolean scan,
|
||||
GError **error)
|
||||
{
|
||||
if (g_cancellable_is_cancelled (self->cancellable) ||
|
||||
(fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE &&
|
||||
g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self)))))
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Operation was cancelled");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (self->pending_commands->len > 0)
|
||||
{
|
||||
gchar *cmd = g_ptr_array_index (self->pending_commands, 0);
|
||||
|
||||
g_debug ("Processing command %s", cmd);
|
||||
|
||||
/* These are always processed. */
|
||||
if (g_str_has_prefix (cmd, INSERT_CMD_PREFIX))
|
||||
{
|
||||
g_assert (self->prints_storage);
|
||||
g_hash_table_add (self->prints_storage,
|
||||
g_strdup (cmd + strlen (INSERT_CMD_PREFIX)));
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
continue;
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX))
|
||||
{
|
||||
g_assert (self->prints_storage);
|
||||
if (!g_hash_table_remove (self->prints_storage,
|
||||
cmd + strlen (REMOVE_CMD_PREFIX)))
|
||||
g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX));
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
continue;
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
|
||||
{
|
||||
guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10);
|
||||
|
||||
g_debug ("Sleeping %lums", sleep_ms);
|
||||
self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self);
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX))
|
||||
{
|
||||
g_propagate_error (error,
|
||||
fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10)));
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we are not scanning, then we have to stop here. */
|
||||
if (!scan)
|
||||
{
|
||||
g_warning ("Could not process command: %s", cmd);
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
|
||||
{
|
||||
char *res = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
return res;
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX))
|
||||
{
|
||||
g_propagate_error (error,
|
||||
fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10)));
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
return NULL;
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX))
|
||||
{
|
||||
gboolean finger_present;
|
||||
|
||||
finger_present = g_ascii_strtoull (cmd + strlen (FINGER_CMD_PREFIX), NULL, 10) != 0;
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE,
|
||||
finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Could not process command: %s", cmd);
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* No commands left, throw a timeout error. */
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No commands left that can be run!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
write_key_to_listener (void *key, void *val, void *user_data)
|
||||
{
|
||||
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (user_data);
|
||||
|
||||
if (!fp_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
|
||||
!fp_device_virtual_listener_write_sync (listener, "\n", 1, NULL))
|
||||
g_warning ("Error writing reply to LIST command");
|
||||
}
|
||||
|
||||
static void
|
||||
recv_instruction_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||
gsize bytes;
|
||||
|
||||
bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
|
||||
fp_dbg ("Got instructions of length %ld", bytes);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
g_warning ("Error receiving instruction data: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
FpDeviceVirtualDevice *self;
|
||||
g_autofree char *cmd = NULL;
|
||||
|
||||
self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
|
||||
|
||||
cmd = g_strndup (self->recv_buf, bytes);
|
||||
fp_dbg ("Received command %s", cmd);
|
||||
|
||||
if (g_str_has_prefix (cmd, LIST_CMD))
|
||||
{
|
||||
if (self->prints_storage)
|
||||
g_hash_table_foreach (self->prints_storage, write_key_to_listener, listener);
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, UNPLUG_CMD))
|
||||
{
|
||||
fpi_device_remove (FP_DEVICE (self));
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX))
|
||||
{
|
||||
guint stages;
|
||||
|
||||
stages = g_ascii_strtoull (cmd + strlen (SET_ENROLL_STAGES_PREFIX), NULL, 10);
|
||||
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), stages);
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, SET_SCAN_TYPE_PREFIX))
|
||||
{
|
||||
const char *scan_type = cmd + strlen (SET_SCAN_TYPE_PREFIX);
|
||||
g_autoptr(GEnumClass) scan_types = g_type_class_ref (fp_scan_type_get_type ());
|
||||
GEnumValue *value = g_enum_get_value_by_nick (scan_types, scan_type);
|
||||
|
||||
if (value)
|
||||
fpi_device_set_scan_type (FP_DEVICE (self), value->value);
|
||||
else
|
||||
g_warning ("Scan type '%s' not found", scan_type);
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, SET_CANCELLATION_PREFIX))
|
||||
{
|
||||
self->supports_cancellation = g_ascii_strtoull (
|
||||
cmd + strlen (SET_CANCELLATION_PREFIX), NULL, 10) != 0;
|
||||
|
||||
g_debug ("Cancellation support toggled: %d",
|
||||
self->supports_cancellation);
|
||||
}
|
||||
else if (g_str_has_prefix (cmd, SET_KEEP_ALIVE_PREFIX))
|
||||
{
|
||||
self->keep_alive = g_ascii_strtoull (
|
||||
cmd + strlen (SET_KEEP_ALIVE_PREFIX), NULL, 10) != 0;
|
||||
|
||||
g_debug ("Keep alive toggled: %d", self->keep_alive);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd));
|
||||
g_clear_handle_id (&self->wait_command_id, g_source_remove);
|
||||
|
||||
maybe_continue_current_action (self);
|
||||
}
|
||||
}
|
||||
|
||||
fp_device_virtual_listener_connection_close (listener);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_instruction (FpDeviceVirtualDevice *self)
|
||||
{
|
||||
fp_device_virtual_listener_read (self->listener,
|
||||
FALSE,
|
||||
self->recv_buf,
|
||||
sizeof (self->recv_buf),
|
||||
recv_instruction_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
on_listener_connected (FpDeviceVirtualListener *listener,
|
||||
gpointer user_data)
|
||||
{
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
|
||||
|
||||
recv_instruction (self);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_init (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GCancellable) cancellable = NULL;
|
||||
g_autoptr(FpDeviceVirtualListener) listener = NULL;
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
process_cmds (self, FALSE, &error);
|
||||
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
fpi_device_open_complete (dev, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
else if (self->sleep_timeout_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (self->listener)
|
||||
{
|
||||
fpi_device_open_complete (dev, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
listener = fp_device_virtual_listener_new ();
|
||||
cancellable = g_cancellable_new ();
|
||||
|
||||
if (!fp_device_virtual_listener_start (listener,
|
||||
fpi_device_get_virtual_env (FP_DEVICE (self)),
|
||||
cancellable,
|
||||
on_listener_connected,
|
||||
self,
|
||||
&error))
|
||||
{
|
||||
fpi_device_open_complete (dev, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
self->listener = g_steal_pointer (&listener);
|
||||
self->cancellable = g_steal_pointer (&cancellable);
|
||||
|
||||
fpi_device_open_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wait_for_command_timeout (gpointer data)
|
||||
{
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
|
||||
GError *error = NULL;
|
||||
|
||||
self->wait_command_id = 0;
|
||||
|
||||
switch (fpi_device_get_current_action (FP_DEVICE (self)))
|
||||
{
|
||||
case FPI_DEVICE_ACTION_LIST:
|
||||
case FPI_DEVICE_ACTION_DELETE:
|
||||
self->ignore_wait = TRUE;
|
||||
maybe_continue_current_action (self);
|
||||
self->ignore_wait = FALSE;
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!");
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
should_wait_for_command (FpDeviceVirtualDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
if (!error && self->sleep_timeout_id)
|
||||
return TRUE;
|
||||
|
||||
if (self->ignore_wait)
|
||||
return FALSE;
|
||||
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
return FALSE;
|
||||
|
||||
if (self->wait_command_id)
|
||||
return FALSE;
|
||||
|
||||
self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *
|
||||
start_scan_command (FpDeviceVirtualDevice *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
g_autofree char *scan_id = NULL;
|
||||
|
||||
if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE)
|
||||
self->injected_synthetic_cmd = FALSE;
|
||||
|
||||
scan_id = process_cmds (self, TRUE, &local_error);
|
||||
|
||||
if (!self->sleep_timeout_id)
|
||||
{
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NEEDED,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
}
|
||||
|
||||
if (should_wait_for_command (self, local_error))
|
||||
{
|
||||
g_assert (!scan_id);
|
||||
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
|
||||
"Still waiting for command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (local_error)
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
else
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_PRESENT,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
|
||||
return g_steal_pointer (&scan_id);
|
||||
}
|
||||
|
||||
gboolean
|
||||
should_wait_to_sleep (FpDeviceVirtualDevice *self,
|
||||
const char *scan_id,
|
||||
GError *error)
|
||||
{
|
||||
const gchar *cmd;
|
||||
|
||||
if (self->sleep_timeout_id)
|
||||
return TRUE;
|
||||
|
||||
if (!self->pending_commands->len)
|
||||
return FALSE;
|
||||
|
||||
cmd = g_ptr_array_index (self->pending_commands, 0);
|
||||
|
||||
if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
g_free (process_cmds (self, FALSE, &local_error));
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return FALSE;
|
||||
|
||||
g_assert (!self->injected_synthetic_cmd);
|
||||
g_assert (self->sleep_timeout_id != 0);
|
||||
|
||||
if (!self->pending_commands->len)
|
||||
{
|
||||
g_autofree char *injected_cmd = NULL;
|
||||
|
||||
if (scan_id)
|
||||
injected_cmd = g_strconcat (SCAN_CMD_PREFIX, scan_id, NULL);
|
||||
else if (error && error->domain == FP_DEVICE_ERROR)
|
||||
injected_cmd = g_strdup_printf (ERROR_CMD_PREFIX " %d", error->code);
|
||||
else if (error && error->domain == FP_DEVICE_RETRY)
|
||||
injected_cmd = g_strdup_printf (RETRY_CMD_PREFIX " %d", error->code);
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
g_debug ("Sleeping now, command queued for later: %s", injected_cmd);
|
||||
|
||||
g_ptr_array_insert (self->pending_commands, 0, g_steal_pointer (&injected_cmd));
|
||||
self->injected_synthetic_cmd = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return self->sleep_timeout_id != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_verify (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
g_autofree char *scan_id = NULL;
|
||||
|
||||
scan_id = start_scan_command (self, &error);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||
return;
|
||||
|
||||
if (scan_id)
|
||||
{
|
||||
GVariant *data = NULL;
|
||||
FpPrint *new_scan;
|
||||
FpPrint *print;
|
||||
gboolean success;
|
||||
|
||||
g_debug ("Virtual device scanned print %s", scan_id);
|
||||
fpi_device_get_verify_data (dev, &print);
|
||||
|
||||
new_scan = fp_print_new (dev);
|
||||
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
|
||||
if (self->prints_storage)
|
||||
fpi_print_set_device_stored (new_scan, TRUE);
|
||||
data = g_variant_new_string (scan_id);
|
||||
g_object_set (new_scan, "fpi-data", data, NULL);
|
||||
|
||||
if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id))
|
||||
{
|
||||
error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND);
|
||||
success = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = fp_print_equal (print, new_scan);
|
||||
}
|
||||
|
||||
if (!self->match_reported)
|
||||
{
|
||||
self->match_reported = TRUE;
|
||||
fpi_device_verify_report (dev,
|
||||
success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL,
|
||||
new_scan,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
g_debug ("Virtual device scan failed with error: %s", error->message);
|
||||
}
|
||||
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
if (error && error->domain == FP_DEVICE_RETRY)
|
||||
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
|
||||
|
||||
if (should_wait_to_sleep (self, scan_id, error))
|
||||
return;
|
||||
|
||||
self->match_reported = FALSE;
|
||||
fpi_device_verify_complete (dev, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
static void
|
||||
dev_enroll (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
FpPrint *print = NULL;
|
||||
g_autofree char *id = NULL;
|
||||
|
||||
id = start_scan_command (self, &error);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||
return;
|
||||
|
||||
fpi_device_get_enroll_data (dev, &print);
|
||||
|
||||
if (id)
|
||||
{
|
||||
GVariant *data;
|
||||
gboolean completed;
|
||||
|
||||
if (self->prints_storage && g_hash_table_contains (self->prints_storage, id))
|
||||
{
|
||||
if (should_wait_to_sleep (self, id, error))
|
||||
return;
|
||||
|
||||
fpi_device_enroll_complete (dev, NULL,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->enroll_stages_passed == 0)
|
||||
{
|
||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||
data = g_variant_new_string (id);
|
||||
g_object_set (print, "fpi-data", data, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean changed;
|
||||
|
||||
g_object_get (print, "fpi-data", &data, NULL);
|
||||
changed = !g_str_equal (id, g_variant_get_string (data, NULL));
|
||||
g_variant_unref (data);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
g_set_error (&error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL, "ID Mismatch");
|
||||
fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL,
|
||||
g_steal_pointer (&error));
|
||||
|
||||
if (!should_wait_to_sleep (self, id, error))
|
||||
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self->enroll_stages_passed++;
|
||||
completed = self->enroll_stages_passed == fp_device_get_nr_enroll_stages (FP_DEVICE (self));
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
completed ?
|
||||
FP_FINGER_STATUS_NEEDED :
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
fpi_device_enroll_progress (dev, self->enroll_stages_passed, print, NULL);
|
||||
|
||||
if (completed)
|
||||
{
|
||||
if (self->prints_storage)
|
||||
{
|
||||
fpi_print_set_device_stored (print, TRUE);
|
||||
g_hash_table_add (self->prints_storage, g_strdup (id));
|
||||
}
|
||||
|
||||
fpi_device_enroll_complete (dev, g_object_ref (print), NULL);
|
||||
self->enroll_stages_passed = 0;
|
||||
}
|
||||
else if (!should_wait_to_sleep (self, id, error))
|
||||
{
|
||||
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
|
||||
if (error && error->domain == FP_DEVICE_RETRY)
|
||||
{
|
||||
fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL, g_steal_pointer (&error));
|
||||
|
||||
if (!should_wait_to_sleep (self, id, error))
|
||||
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (should_wait_to_sleep (self, id, error))
|
||||
return;
|
||||
|
||||
self->enroll_stages_passed = 0;
|
||||
fpi_device_enroll_complete (dev, NULL, g_steal_pointer (&error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dev_cancel (FpDevice *dev)
|
||||
{
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
|
||||
if (self->injected_synthetic_cmd)
|
||||
{
|
||||
self->injected_synthetic_cmd = FALSE;
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
}
|
||||
|
||||
if (!self->supports_cancellation)
|
||||
return;
|
||||
|
||||
g_debug ("Got cancellation!");
|
||||
g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
|
||||
|
||||
maybe_continue_current_action (self);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_listener (FpDeviceVirtualDevice *self)
|
||||
{
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
g_clear_object (&self->listener);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_deinit (FpDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||
|
||||
process_cmds (self, FALSE, &error);
|
||||
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
fpi_device_close_complete (dev, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
else if (self->sleep_timeout_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_handle_id (&self->wait_command_id, g_source_remove);
|
||||
g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
|
||||
|
||||
if (!self->keep_alive)
|
||||
stop_listener (self);
|
||||
|
||||
fpi_device_close_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_finalize (GObject *object)
|
||||
{
|
||||
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (object);
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
stop_listener (self);
|
||||
g_clear_pointer (&self->pending_commands, g_ptr_array_unref);
|
||||
G_OBJECT_CLASS (fpi_device_virtual_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_init (FpDeviceVirtualDevice *self)
|
||||
{
|
||||
self->supports_cancellation = TRUE;
|
||||
self->pending_commands = g_ptr_array_new_with_free_func (g_free);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_DEVICE", },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass)
|
||||
{
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fpi_device_virtual_device_finalize;
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual device for debugging";
|
||||
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
|
||||
dev_class->id_table = driver_ids;
|
||||
dev_class->nr_enroll_stages = 5;
|
||||
|
||||
dev_class->open = dev_init;
|
||||
dev_class->close = dev_deinit;
|
||||
dev_class->verify = dev_verify;
|
||||
dev_class->enroll = dev_enroll;
|
||||
dev_class->cancel = dev_cancel;
|
||||
}
|
||||
@@ -29,35 +29,27 @@
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "virtual-device-private.h"
|
||||
|
||||
#include "../fpi-image.h"
|
||||
#include "../fpi-image-device.h"
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixsocketaddress.h>
|
||||
|
||||
struct _FpDeviceVirtualImage
|
||||
{
|
||||
FpImageDevice parent;
|
||||
FpImageDevice parent;
|
||||
|
||||
GSocketListener *listener;
|
||||
GSocketConnection *connection;
|
||||
GCancellable *cancellable;
|
||||
FpDeviceVirtualListener *listener;
|
||||
GCancellable *cancellable;
|
||||
|
||||
gint socket_fd;
|
||||
gint client_fd;
|
||||
|
||||
gboolean automatic_finger;
|
||||
FpImage *recv_img;
|
||||
gint recv_img_hdr[2];
|
||||
gboolean automatic_finger;
|
||||
FpImage *recv_img;
|
||||
gint recv_img_hdr[2];
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
|
||||
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
|
||||
|
||||
static void start_listen (FpDeviceVirtualImage *dev);
|
||||
static void recv_image (FpDeviceVirtualImage *dev,
|
||||
GInputStream *stream);
|
||||
static void recv_image (FpDeviceVirtualImage *self);
|
||||
|
||||
static void
|
||||
recv_image_img_recv_cb (GObject *source_object,
|
||||
@@ -65,27 +57,16 @@ recv_image_img_recv_cb (GObject *source_object,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||
FpDeviceVirtualImage *self;
|
||||
FpImageDevice *device;
|
||||
gboolean success;
|
||||
gsize bytes = 0;
|
||||
gsize bytes;
|
||||
|
||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||
bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
|
||||
|
||||
if (!success || bytes == 0)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
g_warning ("Error receiving header for image data: %s", error->message);
|
||||
}
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
return;
|
||||
}
|
||||
if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
|
||||
return;
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
device = FP_IMAGE_DEVICE (self);
|
||||
@@ -97,7 +78,7 @@ recv_image_img_recv_cb (GObject *source_object,
|
||||
fpi_image_device_report_finger_status (device, FALSE);
|
||||
|
||||
/* And, listen for more images from the same client. */
|
||||
recv_image (self, G_INPUT_STREAM (source_object));
|
||||
recv_image (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -107,33 +88,30 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpDeviceVirtualImage *self;
|
||||
gboolean success;
|
||||
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||
gsize bytes;
|
||||
|
||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||
bytes = fp_device_virtual_listener_read_finish (listener, res, &error);
|
||||
|
||||
if (!success || bytes == 0)
|
||||
if (error)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
|
||||
return;
|
||||
g_warning ("Error receiving header for image data: %s", error->message);
|
||||
}
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) ||
|
||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||
return;
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
g_warning ("Error receiving header for image data: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bytes)
|
||||
return;
|
||||
|
||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
|
||||
{
|
||||
g_warning ("Image header suggests an unrealistically large image, disconnecting client.");
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
fp_device_virtual_listener_connection_close (listener);
|
||||
}
|
||||
|
||||
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
||||
@@ -162,133 +140,90 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||
!!self->recv_img_hdr[1]);
|
||||
break;
|
||||
|
||||
case -5:
|
||||
/* -5 causes the device to disappear (no further data) */
|
||||
fpi_device_remove (FP_DEVICE (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* disconnect client, it didn't play fair */
|
||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||
g_clear_object (&self->connection);
|
||||
fp_device_virtual_listener_connection_close (listener);
|
||||
}
|
||||
|
||||
/* And, listen for more images from the same client. */
|
||||
recv_image (self, G_INPUT_STREAM (source_object));
|
||||
recv_image (self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
|
||||
g_debug ("image data: %p", self->recv_img->data);
|
||||
g_input_stream_read_all_async (G_INPUT_STREAM (source_object),
|
||||
(guint8 *) self->recv_img->data,
|
||||
self->recv_img->width * self->recv_img->height,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
recv_image_img_recv_cb,
|
||||
self);
|
||||
fp_device_virtual_listener_read (listener,
|
||||
TRUE,
|
||||
(guint8 *) self->recv_img->data,
|
||||
self->recv_img->width * self->recv_img->height,
|
||||
recv_image_img_recv_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
|
||||
recv_image (FpDeviceVirtualImage *self)
|
||||
{
|
||||
g_input_stream_read_all_async (stream,
|
||||
dev->recv_img_hdr,
|
||||
sizeof (dev->recv_img_hdr),
|
||||
G_PRIORITY_DEFAULT,
|
||||
dev->cancellable,
|
||||
recv_image_hdr_recv_cb,
|
||||
dev);
|
||||
fp_device_virtual_listener_read (self->listener,
|
||||
TRUE,
|
||||
self->recv_img_hdr,
|
||||
sizeof (self->recv_img_hdr),
|
||||
recv_image_hdr_recv_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
on_listener_connected (FpDeviceVirtualListener *listener,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
GSocketConnection *connection;
|
||||
GInputStream *stream;
|
||||
FpDeviceVirtualImage *dev = user_data;
|
||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||
FpiImageDeviceState state;
|
||||
|
||||
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
|
||||
res,
|
||||
NULL,
|
||||
&error);
|
||||
if (!connection)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
self->automatic_finger = TRUE;
|
||||
|
||||
g_warning ("Error accepting a new connection: %s", error->message);
|
||||
start_listen (dev);
|
||||
}
|
||||
g_object_get (self,
|
||||
"fpi-image-device-state", &state,
|
||||
NULL);
|
||||
/* Only read if we are in AWAIT_FINGER_* or CAPTURE states */
|
||||
if (state <= FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
|
||||
return;
|
||||
|
||||
/* Always further connections (but we disconnect them immediately
|
||||
* if we already have a connection). */
|
||||
start_listen (dev);
|
||||
if (dev->connection)
|
||||
{
|
||||
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
|
||||
g_object_unref (connection);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->connection = connection;
|
||||
dev->automatic_finger = TRUE;
|
||||
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
|
||||
|
||||
recv_image (dev, stream);
|
||||
|
||||
fp_dbg ("Got a new connection!");
|
||||
}
|
||||
|
||||
static void
|
||||
start_listen (FpDeviceVirtualImage *dev)
|
||||
{
|
||||
g_socket_listener_accept_async (dev->listener,
|
||||
dev->cancellable,
|
||||
new_connection_cb,
|
||||
dev);
|
||||
recv_image (self);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_init (FpImageDevice *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GSocketListener) listener = NULL;
|
||||
g_autoptr(FpDeviceVirtualListener) listener = NULL;
|
||||
g_autoptr(GCancellable) cancellable = NULL;
|
||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||
const char *env;
|
||||
|
||||
g_autoptr(GSocketAddress) addr = NULL;
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->client_fd = -1;
|
||||
listener = fp_device_virtual_listener_new ();
|
||||
cancellable = g_cancellable_new ();
|
||||
|
||||
env = fpi_device_get_virtual_env (FP_DEVICE (self));
|
||||
|
||||
listener = g_socket_listener_new ();
|
||||
g_socket_listener_set_backlog (listener, 1);
|
||||
|
||||
/* Remove any left over socket. */
|
||||
g_unlink (env);
|
||||
|
||||
addr = g_unix_socket_address_new (env);
|
||||
|
||||
if (!g_socket_listener_add_address (listener,
|
||||
addr,
|
||||
G_SOCKET_TYPE_STREAM,
|
||||
G_SOCKET_PROTOCOL_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
&error))
|
||||
if (!fp_device_virtual_listener_start (listener,
|
||||
fpi_device_get_virtual_env (FP_DEVICE (self)),
|
||||
cancellable,
|
||||
on_listener_connected,
|
||||
self,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Could not listen on unix socket: %s", error->message);
|
||||
|
||||
fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error));
|
||||
|
||||
fpi_image_device_open_complete (dev, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
self->listener = g_steal_pointer (&listener);
|
||||
self->cancellable = g_cancellable_new ();
|
||||
self->cancellable = g_steal_pointer (&cancellable);
|
||||
|
||||
start_listen (self);
|
||||
|
||||
fpi_image_device_open_complete (dev, NULL);
|
||||
/* Delay result to open up the possibility of testing race conditions. */
|
||||
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -301,14 +236,58 @@ dev_deinit (FpImageDevice *dev)
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
g_clear_object (&self->listener);
|
||||
g_clear_object (&self->connection);
|
||||
|
||||
fpi_image_device_close_complete (dev, NULL);
|
||||
/* Delay result to open up the possibility of testing race conditions. */
|
||||
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_activate (FpImageDevice *dev)
|
||||
{
|
||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||
|
||||
/* Start reading (again). */
|
||||
recv_image (self);
|
||||
|
||||
fpi_image_device_activate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_notify_removed_cb (FpDevice *dev)
|
||||
{
|
||||
FpiImageDeviceState state;
|
||||
gboolean removed;
|
||||
|
||||
g_object_get (dev,
|
||||
"fpi-image-device-state", &state,
|
||||
"removed", &removed,
|
||||
NULL);
|
||||
|
||||
if (!removed || state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
return;
|
||||
|
||||
/* This error will be converted to an FP_DEVICE_ERROR_REMOVED by the
|
||||
* surrounding layers. */
|
||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev),
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
|
||||
{
|
||||
/* NOTE: This is not nice, but we can generally rely on the underlying
|
||||
* system to throw errors on the transport layer.
|
||||
*/
|
||||
g_signal_connect (self,
|
||||
"notify::removed",
|
||||
G_CALLBACK (dev_notify_removed_cb),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
@@ -329,4 +308,7 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
|
||||
|
||||
img_class->img_open = dev_init;
|
||||
img_class->img_close = dev_deinit;
|
||||
|
||||
img_class->activate = dev_activate;
|
||||
img_class->deactivate = dev_deactivate;
|
||||
}
|
||||
|
||||
676
libfprint/drivers/virtual-sdcp.c
Normal file
676
libfprint/drivers/virtual-sdcp.c
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Virtual driver for SDCP device debugging
|
||||
*
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual test driver to test the basic SDCP functionality.
|
||||
* It uses the test binaries from Microsoft, which were extended to allow
|
||||
* a simple chat with the device.
|
||||
* The environment variable contains the to be executed binary including
|
||||
* arguments. This binary should be compiled from the code in
|
||||
* https://github.com/Microsoft/SecureDeviceConnectionProtocol
|
||||
* or, until it is merged upstream
|
||||
* https://github.com/benzea/SecureDeviceConnectionProtocol
|
||||
*
|
||||
* Note that using this as an external executable has the advantage that we
|
||||
* do not need to link against mbedtls or any other crypto library.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_sdcp"
|
||||
|
||||
#include "fpi-log.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
#include "../fpi-sdcp-device.h"
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
struct _FpDeviceVirtualSdcp
|
||||
{
|
||||
FpSdcpDevice parent;
|
||||
|
||||
GSubprocess *proc;
|
||||
GOutputStream *proc_stdin;
|
||||
GInputStream *proc_stdout;
|
||||
|
||||
/* Only valid while a read/write is pending */
|
||||
GByteArray *msg_out;
|
||||
GByteArray *msg_in;
|
||||
|
||||
GByteArray *connect_msg;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FPI, DEVICE_VIRTUAL_SDCP, FpSdcpDevice)
|
||||
G_DEFINE_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FP_TYPE_SDCP_DEVICE)
|
||||
|
||||
guint8 ca_1[] = {
|
||||
0x30, 0x82, 0x03, 0xFD, 0x30, 0x82, 0x03, 0x82, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33,
|
||||
0x00, 0x00, 0x00, 0x07, 0xE8, 0x9D, 0x61, 0x62, 0x4D, 0x46, 0x0F, 0x95, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x07, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x81,
|
||||
0x84, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
|
||||
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67,
|
||||
0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65,
|
||||
0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15,
|
||||
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25,
|
||||
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x53, 0x65,
|
||||
0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x50, 0x43, 0x41,
|
||||
0x20, 0x32, 0x30, 0x31, 0x38, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x31, 0x33, 0x31, 0x31,
|
||||
0x39, 0x35, 0x34, 0x35, 0x33, 0x5A, 0x17, 0x0D, 0x32, 0x38, 0x30, 0x31, 0x33, 0x31, 0x32, 0x30,
|
||||
0x30, 0x34, 0x35, 0x33, 0x5A, 0x30, 0x7D, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
|
||||
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57,
|
||||
0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55,
|
||||
0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06,
|
||||
0x03, 0x55, 0x04, 0x0A, 0x13, 0x15, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20,
|
||||
0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x27, 0x30, 0x25, 0x06,
|
||||
0x03, 0x55, 0x04, 0x03, 0x13, 0x1E, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48, 0x65,
|
||||
0x6C, 0x6C, 0x6F, 0x20, 0x31, 0x39, 0x42, 0x39, 0x32, 0x39, 0x36, 0x35, 0x20, 0x43, 0x41, 0x20,
|
||||
0x32, 0x30, 0x31, 0x38, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,
|
||||
0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xBE,
|
||||
0x4B, 0x90, 0x6E, 0x24, 0xFC, 0xA1, 0x53, 0xC8, 0xA7, 0x3C, 0x70, 0xE8, 0x97, 0xCD, 0x1B, 0x31,
|
||||
0xE4, 0x95, 0x91, 0x7A, 0x58, 0xA2, 0x86, 0xA8, 0x70, 0xF6, 0x09, 0x30, 0x77, 0x99, 0x3D, 0x10,
|
||||
0xDF, 0xF7, 0x95, 0x0F, 0x68, 0x83, 0xE6, 0xA4, 0x11, 0x7C, 0xDA, 0x82, 0xE7, 0x0B, 0x8B, 0xF2,
|
||||
0x9D, 0x6B, 0x5B, 0xF5, 0x3E, 0x77, 0xB4, 0xC1, 0x0E, 0x49, 0x00, 0x83, 0xBA, 0x94, 0xF8, 0xA3,
|
||||
0x82, 0x01, 0xD7, 0x30, 0x82, 0x01, 0xD3, 0x30, 0x10, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01,
|
||||
0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E,
|
||||
0x04, 0x16, 0x04, 0x14, 0x13, 0x93, 0xC8, 0xCD, 0xF2, 0x23, 0x9A, 0x2D, 0xC6, 0x9B, 0x2A, 0xEB,
|
||||
0x9A, 0xAB, 0x99, 0x0B, 0x56, 0x04, 0x5E, 0x7C, 0x30, 0x65, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04,
|
||||
0x5E, 0x30, 0x5C, 0x30, 0x06, 0x06, 0x04, 0x55, 0x1D, 0x20, 0x00, 0x30, 0x52, 0x06, 0x0C, 0x2B,
|
||||
0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x4C, 0x83, 0x7D, 0x01, 0x01, 0x30, 0x42, 0x30, 0x40, 0x06,
|
||||
0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x3A,
|
||||
0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E,
|
||||
0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x44, 0x6F, 0x63, 0x73, 0x2F,
|
||||
0x52, 0x65, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x6F, 0x72, 0x79, 0x2E, 0x68, 0x74, 0x6D, 0x00, 0x30,
|
||||
0x19, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x0C, 0x1E, 0x0A,
|
||||
0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D,
|
||||
0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
|
||||
0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04,
|
||||
0x18, 0x30, 0x16, 0x80, 0x14, 0xDA, 0xCA, 0x4B, 0xD0, 0x4C, 0x56, 0x03, 0x27, 0x5F, 0x97, 0xEB,
|
||||
0x75, 0xA3, 0x02, 0xC3, 0xBF, 0x45, 0x9C, 0xF8, 0xB1, 0x30, 0x68, 0x06, 0x03, 0x55, 0x1D, 0x1F,
|
||||
0x04, 0x61, 0x30, 0x5F, 0x30, 0x5D, 0xA0, 0x5B, 0xA0, 0x59, 0x86, 0x57, 0x68, 0x74, 0x74, 0x70,
|
||||
0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74,
|
||||
0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x63, 0x72, 0x6C, 0x2F,
|
||||
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x25, 0x32, 0x30, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x25,
|
||||
0x32, 0x30, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x25, 0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x25, 0x32, 0x30, 0x50, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x38, 0x2E,
|
||||
0x63, 0x72, 0x6C, 0x30, 0x75, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
|
||||
0x69, 0x30, 0x67, 0x30, 0x65, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86,
|
||||
0x59, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72,
|
||||
0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73,
|
||||
0x2F, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2F, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x25, 0x32,
|
||||
0x30, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x25, 0x32, 0x30, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x25,
|
||||
0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32, 0x30, 0x50, 0x43, 0x41, 0x25,
|
||||
0x32, 0x30, 0x32, 0x30, 0x31, 0x38, 0x2E, 0x63, 0x72, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86,
|
||||
0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0x87, 0xB6,
|
||||
0x82, 0xF3, 0xDA, 0xBE, 0xB1, 0x7B, 0x98, 0x7D, 0x3D, 0x0A, 0x90, 0xA8, 0xF5, 0xBF, 0x15, 0xC3,
|
||||
0xEE, 0x8A, 0x4E, 0xC0, 0x7B, 0x10, 0x1D, 0xA9, 0xE3, 0x0B, 0xEC, 0x2C, 0x53, 0x4E, 0xA7, 0xBD,
|
||||
0xF1, 0x6C, 0xAD, 0x18, 0x55, 0xBA, 0x25, 0x73, 0x55, 0xB7, 0x5B, 0x12, 0x24, 0xF4, 0x02, 0x31,
|
||||
0x00, 0xAF, 0x02, 0x9C, 0x4B, 0x92, 0xD0, 0x72, 0xA5, 0x80, 0xCA, 0x69, 0x2B, 0x38, 0x50, 0x64,
|
||||
0xD8, 0x58, 0x9E, 0xEA, 0xD6, 0x35, 0xCF, 0x68, 0x98, 0x92, 0x81, 0x09, 0x61, 0xC2, 0xBD, 0xB1,
|
||||
0x4C, 0x7F, 0xAE, 0x55, 0x7B, 0xFC, 0x22, 0xDD, 0xD6, 0xB7, 0x7C, 0xB5, 0xA8, 0x18, 0x5D, 0x33,
|
||||
0x04
|
||||
};
|
||||
guint8 ca_2[] = {
|
||||
0x30, 0x82, 0x04, 0x56, 0x30, 0x82, 0x03, 0xDC, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33,
|
||||
0x00, 0x00, 0x00, 0x03, 0x6C, 0xCF, 0xED, 0xE2, 0x44, 0x70, 0x19, 0xBF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x30, 0x81,
|
||||
0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
|
||||
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67,
|
||||
0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65,
|
||||
0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15,
|
||||
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x3E, 0x30, 0x3C, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x35,
|
||||
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x44, 0x65,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79,
|
||||
0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x31, 0x32, 0x35, 0x31,
|
||||
0x39, 0x34, 0x39, 0x33, 0x38, 0x5A, 0x17, 0x0D, 0x33, 0x33, 0x30, 0x31, 0x32, 0x35, 0x31, 0x39,
|
||||
0x35, 0x39, 0x33, 0x38, 0x5A, 0x30, 0x81, 0x84, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
||||
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A,
|
||||
0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03,
|
||||
0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C,
|
||||
0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74,
|
||||
0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x2E, 0x30, 0x2C,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48,
|
||||
0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x20, 0x50, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x38, 0x30, 0x76, 0x30, 0x10,
|
||||
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
|
||||
0x03, 0x62, 0x00, 0x04, 0x1D, 0xDD, 0x08, 0x02, 0x03, 0x25, 0x75, 0x20, 0xE2, 0x71, 0x8B, 0xAD,
|
||||
0x28, 0x09, 0x82, 0xE9, 0x06, 0xEE, 0x83, 0xC5, 0x3A, 0x6C, 0x4B, 0x71, 0x92, 0x50, 0x4E, 0x20,
|
||||
0xE9, 0x72, 0xB4, 0xFC, 0x53, 0x2A, 0xEF, 0x5D, 0xCC, 0x9A, 0xB4, 0xCD, 0x76, 0xB8, 0x94, 0x97,
|
||||
0x44, 0xB2, 0x71, 0x0E, 0xC9, 0xB1, 0x16, 0x03, 0xA1, 0x65, 0x2B, 0xB9, 0xE8, 0x5D, 0x5F, 0xF2,
|
||||
0x30, 0x2E, 0xDD, 0xB1, 0x2B, 0x20, 0xFC, 0xBE, 0x00, 0x88, 0xEA, 0x1F, 0xA7, 0x7F, 0x99, 0x84,
|
||||
0x98, 0x7C, 0x71, 0x3E, 0x4D, 0x34, 0x83, 0x69, 0x9B, 0x08, 0xCB, 0x78, 0xB2, 0x4B, 0xBD, 0xD7,
|
||||
0x3E, 0xBE, 0x67, 0xA0, 0xA3, 0x82, 0x01, 0xFC, 0x30, 0x82, 0x01, 0xF8, 0x30, 0x10, 0x06, 0x09,
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1D,
|
||||
0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xDA, 0xCA, 0x4B, 0xD0, 0x4C, 0x56, 0x03,
|
||||
0x27, 0x5F, 0x97, 0xEB, 0x75, 0xA3, 0x02, 0xC3, 0xBF, 0x45, 0x9C, 0xF8, 0xB1, 0x30, 0x65, 0x06,
|
||||
0x03, 0x55, 0x1D, 0x20, 0x04, 0x5E, 0x30, 0x5C, 0x30, 0x06, 0x06, 0x04, 0x55, 0x1D, 0x20, 0x00,
|
||||
0x30, 0x52, 0x06, 0x0C, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x4C, 0x83, 0x7D, 0x01, 0x01,
|
||||
0x30, 0x42, 0x30, 0x40, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x34,
|
||||
0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F,
|
||||
0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F,
|
||||
0x44, 0x6F, 0x63, 0x73, 0x2F, 0x52, 0x65, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x6F, 0x72, 0x79, 0x2E,
|
||||
0x68, 0x74, 0x6D, 0x00, 0x30, 0x19, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14,
|
||||
0x02, 0x04, 0x0C, 0x1E, 0x0A, 0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30,
|
||||
0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0F, 0x06, 0x03,
|
||||
0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1F, 0x06,
|
||||
0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x14, 0xDA, 0x5B, 0xF1, 0x0E, 0x66,
|
||||
0x47, 0xD1, 0x5D, 0x13, 0x5F, 0x5B, 0x7A, 0xEB, 0xEB, 0x5F, 0x01, 0x08, 0xB5, 0x49, 0x30, 0x7A,
|
||||
0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x73, 0x30, 0x71, 0x30, 0x6F, 0xA0, 0x6D, 0xA0, 0x6B, 0x86,
|
||||
0x69, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72,
|
||||
0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73,
|
||||
0x2F, 0x63, 0x72, 0x6C, 0x2F, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x25, 0x32,
|
||||
0x30, 0x45, 0x43, 0x43, 0x25, 0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32,
|
||||
0x30, 0x52, 0x6F, 0x6F, 0x74, 0x25, 0x32, 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x25,
|
||||
0x32, 0x30, 0x32, 0x30, 0x31, 0x37, 0x2E, 0x63, 0x72, 0x6C, 0x30, 0x81, 0x87, 0x06, 0x08, 0x2B,
|
||||
0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x7B, 0x30, 0x79, 0x30, 0x77, 0x06, 0x08, 0x2B,
|
||||
0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x6B, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
|
||||
0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F,
|
||||
0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2F, 0x4D,
|
||||
0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x25, 0x32, 0x30, 0x45, 0x43, 0x43, 0x25, 0x32,
|
||||
0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32, 0x30, 0x52, 0x6F, 0x6F, 0x74, 0x25,
|
||||
0x32, 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x25, 0x32, 0x30,
|
||||
0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x37,
|
||||
0x2E, 0x63, 0x72, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03,
|
||||
0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x30, 0x56, 0x2A, 0xAD, 0x72, 0x4C, 0xB9, 0x8C, 0xB3, 0x23,
|
||||
0x80, 0xF5, 0x5F, 0xF8, 0x21, 0x94, 0x66, 0x0F, 0x76, 0x77, 0xE2, 0x7B, 0x03, 0xDD, 0x30, 0x5E,
|
||||
0xCB, 0x90, 0xCA, 0x78, 0xE6, 0x0B, 0x2D, 0x12, 0xE5, 0xF7, 0x67, 0x31, 0x58, 0x71, 0xE6, 0xF3,
|
||||
0x64, 0xC1, 0x04, 0xB3, 0x8B, 0xE9, 0xE2, 0x02, 0x31, 0x00, 0xB9, 0x20, 0x61, 0xB9, 0xD0, 0x5E,
|
||||
0x3A, 0xA4, 0xA2, 0x8A, 0xFE, 0x1D, 0xFC, 0x27, 0x61, 0x0B, 0x98, 0x16, 0x8C, 0x02, 0x9C, 0x20,
|
||||
0x7F, 0xEE, 0xF3, 0xCB, 0x1F, 0x0A, 0x37, 0x62, 0xB1, 0x8E, 0xCE, 0xD9, 0x9A, 0x9E, 0xAC, 0xE6,
|
||||
0x1A, 0xD4, 0xB8, 0xF1, 0xA8, 0x2B, 0xB1, 0xB4, 0x40, 0x9B
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
msg_written_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source_object);
|
||||
FpiSsm *ssm = user_data;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (fpi_ssm_get_device (ssm));
|
||||
|
||||
g_clear_pointer (&self->msg_out, g_byte_array_unref);
|
||||
g_assert (self->msg_out == NULL);
|
||||
|
||||
if (!g_output_stream_write_all_finish (stream, res, NULL, &error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
msg_received_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GInputStream *stream = G_INPUT_STREAM (source_object);
|
||||
FpiSsm *ssm = user_data;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (fpi_ssm_get_device (ssm));
|
||||
gsize read;
|
||||
|
||||
g_assert (self->msg_out == NULL);
|
||||
|
||||
if (!g_input_stream_read_all_finish (stream, res, &read, &error) ||
|
||||
read != self->msg_in->len)
|
||||
{
|
||||
g_clear_pointer (&self->msg_in, g_byte_array_unref);
|
||||
|
||||
if (!error)
|
||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Received EOF while reading from test binary.");
|
||||
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
enum {
|
||||
SEND_MESSAGE,
|
||||
RECV_MESSAGE,
|
||||
SEND_RECV_STATES
|
||||
};
|
||||
|
||||
static void
|
||||
send_recv_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||
{
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case SEND_MESSAGE:
|
||||
g_output_stream_write_all_async (self->proc_stdin,
|
||||
self->msg_out->data,
|
||||
self->msg_out->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||
msg_written_cb,
|
||||
ssm);
|
||||
break;
|
||||
|
||||
case RECV_MESSAGE:
|
||||
g_input_stream_read_all_async (self->proc_stdout,
|
||||
self->msg_in->data,
|
||||
self->msg_in->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||
msg_received_cb,
|
||||
ssm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
connect_2_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) recv_data = NULL;
|
||||
g_autoptr(GBytes) r_d = NULL;
|
||||
g_autoptr(FpiSdcpClaim) claim = NULL;
|
||||
g_autoptr(GBytes) mac = NULL;
|
||||
g_autoptr(GBytes) ca_1_bytes = NULL, ca_2_bytes = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
guint16 cert_size;
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), NULL, NULL, NULL, error);
|
||||
g_clear_pointer (&self->connect_msg, g_byte_array_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&cert_size, self->connect_msg->data + 32, 2);
|
||||
g_byte_array_append (self->connect_msg, self->msg_in->data, self->msg_in->len);
|
||||
g_clear_pointer (&self->msg_in, g_byte_array_unref);
|
||||
/* Double check that the size is correct. */
|
||||
g_assert (self->connect_msg->len == 32 + (2 + cert_size + 65 + 65 + 32 + 64 + 64) + 32);
|
||||
recv_data = g_byte_array_free_to_bytes (g_steal_pointer (&self->connect_msg));
|
||||
|
||||
claim = fpi_sdcp_claim_new ();
|
||||
r_d = g_bytes_new_from_bytes (recv_data, 0, 32);
|
||||
claim->cert_m = g_bytes_new_from_bytes (recv_data, 34, cert_size);
|
||||
claim->pk_d = g_bytes_new_from_bytes (recv_data, 34 + cert_size, 65);
|
||||
claim->pk_f = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65, 65);
|
||||
claim->h_f = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65, 32);
|
||||
claim->s_m = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32, 64);
|
||||
claim->s_d = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32 + 64, 64);
|
||||
mac = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32 + 64 + 64, 32);
|
||||
|
||||
ca_1_bytes = g_bytes_new_static (ca_1, G_N_ELEMENTS (ca_1));
|
||||
ca_2_bytes = g_bytes_new_static (ca_2, G_N_ELEMENTS (ca_2));
|
||||
|
||||
fpi_sdcp_device_set_intermediat_cas (FP_SDCP_DEVICE (dev),
|
||||
ca_1_bytes,
|
||||
ca_2_bytes);
|
||||
|
||||
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), r_d, claim, mac, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_1_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
guint16 cert_size;
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), NULL, NULL, NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->connect_msg, g_byte_array_unref);
|
||||
self->connect_msg = g_steal_pointer (&self->msg_in);
|
||||
|
||||
memcpy (&cert_size, self->connect_msg->data + 32, 2);
|
||||
|
||||
/* Nothing to send and the rest to receive. */
|
||||
self->msg_out = g_byte_array_new ();
|
||||
self->msg_in = g_byte_array_new ();
|
||||
g_byte_array_set_size (self->msg_in, 32 + (2 + cert_size + 65 + 65 + 32 + 64 + 64) + 32 - self->connect_msg->len);
|
||||
|
||||
/* New SSM */
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "connect 2");
|
||||
fpi_ssm_start (ssm, connect_2_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
connect (FpSdcpDevice *dev)
|
||||
{
|
||||
g_autoptr(GBytes) r_h = NULL;
|
||||
g_autoptr(GBytes) pk_h = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_assert (self->proc);
|
||||
g_assert (self->connect_msg == NULL);
|
||||
|
||||
fpi_sdcp_device_get_connect_data (dev, &r_h, &pk_h);
|
||||
|
||||
self->msg_out = g_byte_array_new ();
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "C", 1);
|
||||
g_byte_array_append (self->msg_out,
|
||||
g_bytes_get_data (r_h, NULL),
|
||||
g_bytes_get_size (r_h));
|
||||
g_byte_array_append (self->msg_out,
|
||||
g_bytes_get_data (pk_h, NULL),
|
||||
g_bytes_get_size (pk_h));
|
||||
|
||||
self->msg_in = g_byte_array_new ();
|
||||
g_byte_array_set_size (self->msg_in, 34);
|
||||
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "connect");
|
||||
fpi_ssm_start (ssm, connect_1_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
reconnect_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) mac = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_reconnect_complete (FP_SDCP_DEVICE (dev), mac, error);
|
||||
return;
|
||||
}
|
||||
|
||||
mac = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
|
||||
|
||||
fpi_sdcp_device_reconnect_complete (FP_SDCP_DEVICE (dev), mac, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
reconnect (FpSdcpDevice *dev)
|
||||
{
|
||||
g_autoptr(GBytes) r_h = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_assert (self->proc);
|
||||
|
||||
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
|
||||
|
||||
self->msg_out = g_byte_array_new ();
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "R", 1);
|
||||
g_byte_array_append (self->msg_out,
|
||||
g_bytes_get_data (r_h, NULL),
|
||||
g_bytes_get_size (r_h));
|
||||
|
||||
self->msg_in = g_byte_array_new ();
|
||||
g_byte_array_set_size (self->msg_in, 32);
|
||||
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "connect 2");
|
||||
fpi_ssm_start (ssm, reconnect_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
enroll_begin_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) nonce = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), error);
|
||||
return;
|
||||
}
|
||||
|
||||
nonce = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
|
||||
|
||||
fpi_sdcp_device_enroll_set_nonce (FP_SDCP_DEVICE (dev), nonce);
|
||||
|
||||
/* Claim that we completed one enroll step. */
|
||||
fpi_device_enroll_progress (dev, 1, NULL, NULL);
|
||||
|
||||
/* And signal that we are ready to commit. */
|
||||
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
enroll_begin (FpSdcpDevice *dev)
|
||||
{
|
||||
g_autoptr(GBytes) r_h = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_assert (self->proc);
|
||||
|
||||
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
|
||||
|
||||
self->msg_out = g_byte_array_new ();
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "E", 1);
|
||||
|
||||
/* Expect 32 byte nonce */
|
||||
self->msg_in = g_byte_array_new ();
|
||||
g_byte_array_set_size (self->msg_in, 32);
|
||||
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "enroll_begin");
|
||||
fpi_ssm_start (ssm, enroll_begin_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
enroll_commit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
|
||||
g_clear_pointer (&self->msg_in, g_byte_array_unref);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Signal that we have committed. We don't expect a response
|
||||
* from the virtual device (even though that is kind of broken).
|
||||
*/
|
||||
fpi_sdcp_device_enroll_commit_complete (FP_SDCP_DEVICE (dev), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
enroll_commit (FpSdcpDevice *dev, GBytes *id_in)
|
||||
{
|
||||
g_autoptr(GBytes) r_h = NULL;
|
||||
g_autoptr(GBytes) id = id_in;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_assert (self->proc);
|
||||
|
||||
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
|
||||
|
||||
self->msg_out = g_byte_array_new ();
|
||||
self->msg_in = g_byte_array_new ();
|
||||
if (id)
|
||||
{
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "F", 1);
|
||||
g_byte_array_append (self->msg_out,
|
||||
g_bytes_get_data (id, NULL),
|
||||
g_bytes_get_size (id));
|
||||
|
||||
/* NOTE: No response from device, assume commit works. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cancel enroll (does not receive a reply) */
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "G", 1);
|
||||
|
||||
/* NOTE: No response from device, assume cancellation works. */
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "enroll_commit");
|
||||
fpi_ssm_start (ssm, enroll_commit_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
identify_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) reply = NULL;
|
||||
g_autoptr(GBytes) id = NULL;
|
||||
g_autoptr(GBytes) mac = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_identify_complete (FP_SDCP_DEVICE (dev), NULL, NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
reply = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
|
||||
id = g_bytes_new_from_bytes (reply, 0, 32);
|
||||
mac = g_bytes_new_from_bytes (reply, 32, 32);
|
||||
|
||||
fpi_sdcp_device_identify_complete (FP_SDCP_DEVICE (self), id, mac, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
identify (FpSdcpDevice *dev)
|
||||
{
|
||||
g_autoptr(GBytes) nonce = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
FpiSsm *ssm;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
g_assert (self->proc);
|
||||
|
||||
fpi_sdcp_device_get_identify_data (dev, &nonce);
|
||||
|
||||
self->msg_out = g_byte_array_new ();
|
||||
g_byte_array_append (self->msg_out, (const guint8 *) "I", 1);
|
||||
g_byte_array_append (self->msg_out, g_bytes_get_data (nonce, NULL), g_bytes_get_size (nonce));
|
||||
|
||||
/* Expect 64 byte nonce */
|
||||
self->msg_in = g_byte_array_new ();
|
||||
g_byte_array_set_size (self->msg_in, 64);
|
||||
|
||||
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, "identify");
|
||||
fpi_ssm_start (ssm, identify_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
probe (FpDevice *dev)
|
||||
{
|
||||
g_auto(GStrv) argv = NULL;
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
|
||||
GError *error = NULL;
|
||||
const char *env;
|
||||
|
||||
/* We launch the test binary alread at probe time and quit only when
|
||||
* the object is finalized. This allows testing reconnect properly.
|
||||
*
|
||||
* Also, we'll fail probe if something goes wrong executing it.
|
||||
*/
|
||||
env = fpi_device_get_virtual_env (FP_DEVICE (self));
|
||||
|
||||
if (!g_shell_parse_argv (env, NULL, &argv, &error))
|
||||
goto out;
|
||||
|
||||
self->proc = g_subprocess_newv ((const char * const *) argv,
|
||||
G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
|
||||
&error);
|
||||
if (!self->proc)
|
||||
goto out;
|
||||
|
||||
self->proc_stdin = g_object_ref (g_subprocess_get_stdin_pipe (self->proc));
|
||||
self->proc_stdout = g_object_ref (g_subprocess_get_stdout_pipe (self->proc));
|
||||
|
||||
|
||||
out:
|
||||
fpi_device_probe_complete (dev, "virtual-sdcp", NULL, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_close (FpDevice *dev)
|
||||
{
|
||||
/* No-op, needs to be defined. */
|
||||
fpi_device_close_complete (dev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_init (FpDeviceVirtualSdcp *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_finalize (GObject *obj)
|
||||
{
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (obj);
|
||||
|
||||
/* Just kill the subprocess, no need to be graceful here. */
|
||||
if (self->proc)
|
||||
g_subprocess_force_exit (self->proc);
|
||||
|
||||
g_clear_object (&self->proc);
|
||||
g_clear_object (&self->proc_stdin);
|
||||
g_clear_object (&self->proc_stdout);
|
||||
|
||||
G_OBJECT_CLASS (fpi_device_virtual_sdcp_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_SDCP" },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_class_init (FpDeviceVirtualSdcpClass *klass)
|
||||
{
|
||||
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpSdcpDeviceClass *sdcp_class = FP_SDCP_DEVICE_CLASS (klass);
|
||||
|
||||
obj_class->finalize = fpi_device_virtual_sdcp_finalize;
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual SDCP device talking to MS test code";
|
||||
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
|
||||
dev_class->id_table = driver_ids;
|
||||
dev_class->nr_enroll_stages = 1;
|
||||
|
||||
/* The SDCP base class may need to override this in the long run */
|
||||
dev_class->probe = probe;
|
||||
dev_class->close = dev_close;
|
||||
|
||||
sdcp_class->connect = connect;
|
||||
sdcp_class->reconnect = reconnect;
|
||||
|
||||
sdcp_class->enroll_begin = enroll_begin;
|
||||
sdcp_class->enroll_commit = enroll_commit;
|
||||
|
||||
sdcp_class->identify = identify;
|
||||
}
|
||||
@@ -86,6 +86,60 @@ is_driver_allowed (const gchar *driver)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FpContext *context;
|
||||
FpDevice *device;
|
||||
} RemoveDeviceData;
|
||||
|
||||
static gboolean
|
||||
remove_device_idle_cb (RemoveDeviceData *data)
|
||||
{
|
||||
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
|
||||
guint idx = 0;
|
||||
|
||||
g_return_val_if_fail (g_ptr_array_find (priv->devices, data->device, &idx), G_SOURCE_REMOVE);
|
||||
|
||||
g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device);
|
||||
g_ptr_array_remove_index_fast (priv->devices, idx);
|
||||
|
||||
g_free (data);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_device (FpContext *context, FpDevice *device)
|
||||
{
|
||||
RemoveDeviceData *data;
|
||||
|
||||
data = g_new (RemoveDeviceData, 1);
|
||||
data->context = context;
|
||||
data->device = device;
|
||||
|
||||
g_idle_add ((GSourceFunc) remove_device_idle_cb, data);
|
||||
}
|
||||
|
||||
static void
|
||||
device_remove_on_notify_open_cb (FpContext *context, GParamSpec *pspec, FpDevice *device)
|
||||
{
|
||||
remove_device (context, device);
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed_cb (FpContext *context, FpDevice *device)
|
||||
{
|
||||
gboolean open = FALSE;
|
||||
|
||||
g_object_get (device, "open", &open, NULL);
|
||||
|
||||
/* Wait for device close if the device is currently still open. */
|
||||
if (open)
|
||||
g_signal_connect_swapped (device, "notify::open", (GCallback) device_remove_on_notify_open_cb, context);
|
||||
else
|
||||
remove_device (context, device);
|
||||
}
|
||||
|
||||
static void
|
||||
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
@@ -110,6 +164,9 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
|
||||
}
|
||||
|
||||
g_ptr_array_add (priv->devices, device);
|
||||
|
||||
g_signal_connect_swapped (device, "removed", (GCallback) device_removed_cb, context);
|
||||
|
||||
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
||||
}
|
||||
|
||||
@@ -189,12 +246,7 @@ usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx
|
||||
continue;
|
||||
|
||||
if (fpi_device_get_usb_device (dev) == device)
|
||||
{
|
||||
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
|
||||
g_ptr_array_remove_index_fast (priv->devices, i);
|
||||
|
||||
return;
|
||||
}
|
||||
fpi_device_remove (dev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +262,8 @@ fp_context_finalize (GObject *object)
|
||||
g_clear_object (&priv->cancellable);
|
||||
g_clear_pointer (&priv->drivers, g_array_unref);
|
||||
|
||||
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
||||
if (priv->usb_ctx)
|
||||
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
||||
g_clear_object (&priv->usb_ctx);
|
||||
|
||||
G_OBJECT_CLASS (fp_context_parent_class)->finalize (object);
|
||||
@@ -247,6 +300,10 @@ fp_context_class_init (FpContextClass *klass)
|
||||
* @device: A #FpDevice
|
||||
*
|
||||
* This signal is emitted when a fingerprint reader is removed.
|
||||
*
|
||||
* It is guaranteed that the device has been closed before this signal
|
||||
* is emitted. See the #FpDevice removed signal documentation for more
|
||||
* information.
|
||||
**/
|
||||
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
@@ -289,7 +346,7 @@ fp_context_init (FpContext *self)
|
||||
priv->usb_ctx = g_usb_context_new (&error);
|
||||
if (!priv->usb_ctx)
|
||||
{
|
||||
fp_warn ("Could not initialise USB Subsystem: %s", error->message);
|
||||
g_message ("Could not initialise USB Subsystem: %s", error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -342,7 +399,8 @@ fp_context_enumerate (FpContext *context)
|
||||
priv->enumerated = TRUE;
|
||||
|
||||
/* USB devices are handled from callbacks */
|
||||
g_usb_context_enumerate (priv->usb_ctx);
|
||||
if (priv->usb_ctx)
|
||||
g_usb_context_enumerate (priv->usb_ctx);
|
||||
|
||||
/* Handle Virtual devices based on environment variables */
|
||||
for (i = 0; i < priv->drivers->len; i++)
|
||||
|
||||
@@ -29,6 +29,7 @@ typedef struct
|
||||
GUsbDevice *usb_device;
|
||||
const gchar *virtual_env;
|
||||
|
||||
gboolean is_removed;
|
||||
gboolean is_open;
|
||||
|
||||
gchar *device_id;
|
||||
@@ -49,7 +50,8 @@ typedef struct
|
||||
GSource *current_task_idle_return_source;
|
||||
|
||||
/* State for tasks */
|
||||
gboolean wait_for_finger;
|
||||
gboolean wait_for_finger;
|
||||
FpFingerStatusFlags finger_status;
|
||||
} FpDevicePrivate;
|
||||
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ enum {
|
||||
PROP_DEVICE_ID,
|
||||
PROP_NAME,
|
||||
PROP_OPEN,
|
||||
PROP_REMOVED,
|
||||
PROP_NR_ENROLL_STAGES,
|
||||
PROP_SCAN_TYPE,
|
||||
PROP_FINGER_STATUS,
|
||||
PROP_FPI_ENVIRON,
|
||||
PROP_FPI_USB_DEVICE,
|
||||
PROP_FPI_DRIVER_DATA,
|
||||
@@ -54,6 +56,13 @@ enum {
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
enum {
|
||||
REMOVED_SIGNAL,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS] = { 0, };
|
||||
|
||||
/**
|
||||
* fp_device_retry_quark:
|
||||
*
|
||||
@@ -84,6 +93,8 @@ fp_device_cancel_in_idle_cb (gpointer user_data)
|
||||
|
||||
cls->cancel (self);
|
||||
|
||||
fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
@@ -174,15 +185,19 @@ fp_device_get_property (GObject *object,
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_NR_ENROLL_STAGES:
|
||||
g_value_set_int (value, priv->nr_enroll_stages);
|
||||
g_value_set_uint (value, priv->nr_enroll_stages);
|
||||
break;
|
||||
|
||||
case PROP_SCAN_TYPE:
|
||||
g_value_set_enum (value, priv->scan_type);
|
||||
break;
|
||||
|
||||
case PROP_FINGER_STATUS:
|
||||
g_value_set_flags (value, priv->finger_status);
|
||||
break;
|
||||
|
||||
case PROP_DRIVER:
|
||||
g_value_set_static_string (value, FP_DEVICE_GET_CLASS (priv)->id);
|
||||
g_value_set_static_string (value, FP_DEVICE_GET_CLASS (self)->id);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_ID:
|
||||
@@ -197,6 +212,10 @@ fp_device_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->is_open);
|
||||
break;
|
||||
|
||||
case PROP_REMOVED:
|
||||
g_value_set_boolean (value, priv->is_removed);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@@ -310,6 +329,13 @@ fp_device_class_init (FpDeviceClass *klass)
|
||||
FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_FINGER_STATUS] =
|
||||
g_param_spec_flags ("finger-status",
|
||||
"FingerStatus",
|
||||
"The status of the finger",
|
||||
FP_TYPE_FINGER_STATUS_FLAGS, FP_FINGER_STATUS_NONE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_DRIVER] =
|
||||
g_param_spec_string ("driver",
|
||||
"Driver",
|
||||
@@ -337,6 +363,41 @@ fp_device_class_init (FpDeviceClass *klass)
|
||||
"Whether the device is open or not", FALSE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_REMOVED] =
|
||||
g_param_spec_boolean ("removed",
|
||||
"Removed",
|
||||
"Whether the device has been removed from the system", FALSE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
/**
|
||||
* FpDevice::removed:
|
||||
* @device: the #FpDevice instance that emitted the signal
|
||||
*
|
||||
* This signal is emitted after the device has been removed and no operation
|
||||
* is pending anymore.
|
||||
*
|
||||
* The API user is still required to close a removed device. The above
|
||||
* guarantee means that the call to close the device can be made immediately
|
||||
* from the signal handler.
|
||||
*
|
||||
* The close operation will return FP_DEVICE_ERROR_REMOVED, but the device
|
||||
* will still be considered closed afterwards.
|
||||
*
|
||||
* The device will only be removed from the #FpContext after it has been
|
||||
* closed by the API user.
|
||||
**/
|
||||
signals[REMOVED_SIGNAL] = g_signal_new ("removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
/* Private properties */
|
||||
|
||||
/**
|
||||
* FpDevice::fpi-environ: (skip)
|
||||
*
|
||||
@@ -469,6 +530,26 @@ fp_device_get_scan_type (FpDevice *device)
|
||||
return priv->scan_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_get_finger_status:
|
||||
* @device: A #FpDevice
|
||||
*
|
||||
* Retrieves the finger status flags for the device.
|
||||
* This can be used by the UI to present the relevant feedback, although it
|
||||
* is not guaranteed to be a relevant value when not performing any action.
|
||||
*
|
||||
* Returns: The current #FpFingerStatusFlags
|
||||
*/
|
||||
FpFingerStatusFlags
|
||||
fp_device_get_finger_status (FpDevice *device)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_return_val_if_fail (FP_IS_DEVICE (device), FP_FINGER_STATUS_NONE);
|
||||
|
||||
return priv->finger_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_get_nr_enroll_stages:
|
||||
* @device: A #FpDevice
|
||||
@@ -603,6 +684,7 @@ fp_device_open (FpDevice *device,
|
||||
priv->current_action = FPI_DEVICE_ACTION_OPEN;
|
||||
priv->current_task = g_steal_pointer (&task);
|
||||
maybe_cancel_on_cancelled (device, cancellable);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
FP_DEVICE_GET_CLASS (device)->open (device);
|
||||
}
|
||||
@@ -710,7 +792,7 @@ fp_device_close_finish (FpDevice *device,
|
||||
* in. The driver may make use of this metadata, when e.g. storing the print on
|
||||
* device memory. It is undefined whether this print is filled in by the driver
|
||||
* and returned, or whether the driver will return a newly created print after
|
||||
* enrollment successed.
|
||||
* enrollment succeeded.
|
||||
*/
|
||||
void
|
||||
fp_device_enroll (FpDevice *device,
|
||||
@@ -897,7 +979,7 @@ fp_device_verify_finish (FpDevice *device,
|
||||
|
||||
data = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
*print = data->print;
|
||||
*print = data ? data->print : NULL;
|
||||
if (*print)
|
||||
g_object_ref (*print);
|
||||
}
|
||||
@@ -936,6 +1018,7 @@ fp_device_identify (FpDevice *device,
|
||||
g_autoptr(GTask) task = NULL;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
FpMatchData *data;
|
||||
int i;
|
||||
|
||||
task = g_task_new (device, cancellable, callback, user_data);
|
||||
if (g_task_return_error_if_cancelled (task))
|
||||
@@ -960,7 +1043,13 @@ fp_device_identify (FpDevice *device,
|
||||
maybe_cancel_on_cancelled (device, cancellable);
|
||||
|
||||
data = g_new0 (FpMatchData, 1);
|
||||
data->gallery = g_ptr_array_ref (prints);
|
||||
/* 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
|
||||
* GPtrArray afterwards.
|
||||
*/
|
||||
data->gallery = g_ptr_array_new_full (prints->len, g_object_unref);
|
||||
for (i = 0; i < prints->len; i++)
|
||||
g_ptr_array_add (data->gallery, g_object_ref (g_ptr_array_index (prints, i)));
|
||||
data->match_cb = match_cb;
|
||||
data->match_data = match_data;
|
||||
data->match_destroy = match_destroy;
|
||||
@@ -1003,13 +1092,13 @@ fp_device_identify_finish (FpDevice *device,
|
||||
|
||||
if (print)
|
||||
{
|
||||
*print = data->print;
|
||||
*print = data ? data->print : NULL;
|
||||
if (*print)
|
||||
g_object_ref (*print);
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
*match = data->match;
|
||||
*match = data ? data->match : NULL;
|
||||
if (*match)
|
||||
g_object_ref (*match);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,9 @@ typedef enum {
|
||||
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
||||
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
|
||||
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
|
||||
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
|
||||
* @FP_DEVICE_ERROR_REMOVED: The device has been removed.
|
||||
* @FP_DEVICE_ERROR_UNTRUSTED: Device cannot be trusted
|
||||
*
|
||||
* Error codes for device operations. More specific errors from other domains
|
||||
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||
@@ -104,6 +107,10 @@ typedef enum {
|
||||
FP_DEVICE_ERROR_DATA_INVALID,
|
||||
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
||||
FP_DEVICE_ERROR_DATA_FULL,
|
||||
FP_DEVICE_ERROR_DATA_DUPLICATE,
|
||||
/* Leave some room to add more DATA related errors */
|
||||
FP_DEVICE_ERROR_REMOVED = 0x100,
|
||||
FP_DEVICE_ERROR_UNTRUSTED,
|
||||
} FpDeviceError;
|
||||
|
||||
GQuark fp_device_retry_quark (void);
|
||||
@@ -168,6 +175,7 @@ const gchar *fp_device_get_device_id (FpDevice *device);
|
||||
const gchar *fp_device_get_name (FpDevice *device);
|
||||
gboolean fp_device_is_open (FpDevice *device);
|
||||
FpScanType fp_device_get_scan_type (FpDevice *device);
|
||||
FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device);
|
||||
gint fp_device_get_nr_enroll_stages (FpDevice *device);
|
||||
|
||||
gboolean fp_device_supports_identify (FpDevice *device);
|
||||
|
||||
@@ -27,17 +27,19 @@ typedef struct
|
||||
{
|
||||
FpiImageDeviceState state;
|
||||
gboolean active;
|
||||
gboolean cancelling;
|
||||
|
||||
gboolean enroll_await_on_pending;
|
||||
gboolean finger_present;
|
||||
|
||||
gint enroll_stage;
|
||||
|
||||
guint pending_activation_timeout_id;
|
||||
gboolean pending_activation_timeout_waiting_finger_off;
|
||||
gboolean minutiae_scan_active;
|
||||
GError *action_error;
|
||||
FpImage *capture_image;
|
||||
|
||||
gint bz3_threshold;
|
||||
} FpImageDevicePrivate;
|
||||
|
||||
|
||||
void fpi_image_device_activate (FpImageDevice *image_device);
|
||||
void fpi_image_device_deactivate (FpImageDevice *image_device);
|
||||
void fpi_image_device_deactivate (FpImageDevice *image_device,
|
||||
gboolean cancelling);
|
||||
|
||||
@@ -56,27 +56,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
||||
**/
|
||||
|
||||
/* Static helper functions */
|
||||
|
||||
static gboolean
|
||||
pending_activation_timeout (gpointer user_data)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
priv->pending_activation_timeout_id = 0;
|
||||
|
||||
if (priv->pending_activation_timeout_waiting_finger_off)
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||
"Remove finger before requesting another scan operation"));
|
||||
else
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/* Callbacks/vfuncs */
|
||||
static void
|
||||
fp_image_device_open (FpDevice *device)
|
||||
@@ -95,26 +74,14 @@ fp_image_device_close (FpDevice *device)
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
/* In the close case we may need to wait/force deactivation first.
|
||||
* Three possible cases:
|
||||
* 1. We are inactive
|
||||
* -> immediately close
|
||||
* 2. We are waiting for finger off
|
||||
* -> immediately deactivate
|
||||
* 3. We are deactivating
|
||||
* -> handled by deactivate_complete */
|
||||
|
||||
if (!priv->active)
|
||||
cls->img_close (self);
|
||||
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
fpi_image_device_deactivate (self);
|
||||
g_assert (priv->active == FALSE);
|
||||
cls->img_close (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_cancel_action (FpDevice *device)
|
||||
{
|
||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (device);
|
||||
@@ -125,17 +92,7 @@ fp_image_device_cancel_action (FpDevice *device)
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
priv->cancelling = TRUE;
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->cancelling = FALSE;
|
||||
|
||||
/* XXX: Some nicer way of doing this would be good. */
|
||||
fpi_device_action_error (FP_DEVICE (self),
|
||||
g_error_new (G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED,
|
||||
"Device operation was cancelled"));
|
||||
}
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -171,27 +128,9 @@ fp_image_device_start_capture_action (FpDevice *device)
|
||||
}
|
||||
|
||||
priv->enroll_stage = 0;
|
||||
priv->enroll_await_on_pending = FALSE;
|
||||
|
||||
/* The device might still be deactivating from a previous call.
|
||||
* In that situation, try to wait for a bit before reporting back an
|
||||
* error (which will usually say that the user should remove the
|
||||
* finger).
|
||||
*/
|
||||
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
|
||||
{
|
||||
g_debug ("Got a new request while the device was still active");
|
||||
g_assert (priv->pending_activation_timeout_id == 0);
|
||||
priv->pending_activation_timeout_id =
|
||||
g_timeout_add (100, pending_activation_timeout, device);
|
||||
|
||||
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
priv->pending_activation_timeout_waiting_finger_off = TRUE;
|
||||
else
|
||||
priv->pending_activation_timeout_waiting_finger_off = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
/* The internal state machine guarantees both of these. */
|
||||
g_assert (!priv->finger_present);
|
||||
g_assert (!priv->minutiae_scan_active);
|
||||
|
||||
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
||||
* to be called when done (or immediately). */
|
||||
@@ -208,7 +147,6 @@ fp_image_device_finalize (GObject *object)
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
g_assert (priv->active == FALSE);
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fp-device.h>
|
||||
#include "fp-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||
gint map_w, map_h;
|
||||
gint bw, bh, bd;
|
||||
gint r;
|
||||
g_autofree LFSPARMS *lfsparms;
|
||||
g_autofree LFSPARMS *lfsparms = NULL;
|
||||
|
||||
/* Normalize the image first */
|
||||
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
||||
|
||||
@@ -281,7 +281,7 @@ fp_print_class_init (FpPrintClass *klass)
|
||||
"Type",
|
||||
"Private: The type of the print data",
|
||||
FPI_TYPE_PRINT_TYPE,
|
||||
FPI_PRINT_RAW,
|
||||
FPI_PRINT_UNDEFINED,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
@@ -582,7 +582,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||
if (g_strcmp0 (self->device_id, other->device_id))
|
||||
return FALSE;
|
||||
|
||||
if (self->type == FPI_PRINT_RAW)
|
||||
if (self->type == FPI_PRINT_RAW || self->type == FPI_PRINT_SDCP)
|
||||
{
|
||||
return g_variant_equal (self->data, other->data);
|
||||
}
|
||||
@@ -667,36 +667,25 @@ fp_print_serialize (FpPrint *print,
|
||||
for (i = 0; i < print->prints->len; i++)
|
||||
{
|
||||
struct xyt_struct *xyt = g_ptr_array_index (print->prints, i);
|
||||
gint j;
|
||||
gint32 *col = g_new (gint32, xyt->nrows);
|
||||
|
||||
g_variant_builder_open (&nested, G_VARIANT_TYPE ("(aiaiai)"));
|
||||
|
||||
for (j = 0; j < xyt->nrows; j++)
|
||||
col[j] = GINT32_TO_LE (xyt->xcol[j]);
|
||||
g_variant_builder_add_value (&nested,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||
col,
|
||||
xyt->xcol,
|
||||
xyt->nrows,
|
||||
sizeof (col[0])));
|
||||
|
||||
for (j = 0; j < xyt->nrows; j++)
|
||||
col[j] = GINT32_TO_LE (xyt->ycol[j]);
|
||||
sizeof (xyt->xcol[0])));
|
||||
g_variant_builder_add_value (&nested,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||
col,
|
||||
xyt->ycol,
|
||||
xyt->nrows,
|
||||
sizeof (col[0])));
|
||||
|
||||
for (j = 0; j < xyt->nrows; j++)
|
||||
col[j] = GINT32_TO_LE (xyt->thetacol[j]);
|
||||
sizeof (xyt->ycol[0])));
|
||||
g_variant_builder_add_value (&nested,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||
col,
|
||||
xyt->thetacol,
|
||||
xyt->nrows,
|
||||
sizeof (col[0])));
|
||||
sizeof (xyt->thetacol[0])));
|
||||
g_variant_builder_close (&nested);
|
||||
g_free (col);
|
||||
}
|
||||
|
||||
g_variant_builder_close (&nested);
|
||||
@@ -819,6 +808,7 @@ fp_print_deserialize (const guchar *data,
|
||||
"device-id", device_id,
|
||||
"device-stored", device_stored,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
||||
for (i = 0; i < g_variant_n_children (prints); i++)
|
||||
{
|
||||
@@ -857,7 +847,7 @@ fp_print_deserialize (const guchar *data,
|
||||
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
||||
}
|
||||
}
|
||||
else if (type == FPI_PRINT_RAW)
|
||||
else if (type == FPI_PRINT_RAW || type == FPI_PRINT_SDCP)
|
||||
{
|
||||
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
||||
|
||||
@@ -868,6 +858,7 @@ fp_print_deserialize (const guchar *data,
|
||||
"device-stored", device_stored,
|
||||
"fpi-data", fp_data,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -886,8 +877,7 @@ fp_print_deserialize (const guchar *data,
|
||||
return g_steal_pointer (&result);
|
||||
|
||||
invalid_format:
|
||||
*error = g_error_new_literal (G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"Data could not be parsed");
|
||||
return FALSE;
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
"Data could not be parsed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -66,12 +66,19 @@ typedef enum {
|
||||
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
|
||||
} FpFinger;
|
||||
|
||||
FpPrint *fp_print_new (FpDevice *device);
|
||||
/**
|
||||
* FpFingerStatusFlags:
|
||||
* @FP_FINGER_STATUS_NONE: Sensor has not the finger on it, nor requires it
|
||||
* @FP_FINGER_STATUS_NEEDED: Sensor waits for the finger
|
||||
* @FP_FINGER_STATUS_PRESENT: Sensor has the finger on it
|
||||
*/
|
||||
typedef enum {
|
||||
FP_FINGER_STATUS_NONE = 0,
|
||||
FP_FINGER_STATUS_NEEDED = 1 << 0,
|
||||
FP_FINGER_STATUS_PRESENT = 1 << 1,
|
||||
} FpFingerStatusFlags;
|
||||
|
||||
FpPrint *fp_print_new_from_data (guchar *data,
|
||||
gsize length);
|
||||
gboolean fp_print_to_data (guchar **data,
|
||||
gsize length);
|
||||
FpPrint *fp_print_new (FpDevice *device);
|
||||
|
||||
const gchar *fp_print_get_driver (FpPrint *print);
|
||||
const gchar *fp_print_get_device_id (FpPrint *print);
|
||||
|
||||
58
libfprint/fp-sdcp-device-private.h
Normal file
58
libfprint/fp-sdcp-device-private.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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-sdcp-device.h"
|
||||
|
||||
#include <nss.h>
|
||||
#include <keyhi.h>
|
||||
#include <keythi.h>
|
||||
#include <pk11pub.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GError *enroll_pre_commit_error;
|
||||
|
||||
/* XXX: Do we want a separate SDCP session object?
|
||||
*/
|
||||
|
||||
GPtrArray *intermediate_cas;
|
||||
|
||||
/* Host random for the connection */
|
||||
guint8 host_random[32];
|
||||
|
||||
NSSInitContext *nss_init_context;
|
||||
PK11SlotInfo *slot;
|
||||
SECKEYPrivateKey *host_key_private;
|
||||
SECKEYPublicKey *host_key_public;
|
||||
|
||||
/* Master secret is required for reconnects.
|
||||
* TODO: We probably want to serialize this to disk so it can survive
|
||||
* fprintd idle shutdown. */
|
||||
PK11SymKey *master_secret;
|
||||
PK11SymKey *mac_secret;
|
||||
|
||||
} FpSdcpDevicePrivate;
|
||||
|
||||
void fpi_sdcp_device_connect (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_reconnect (FpSdcpDevice *self);
|
||||
|
||||
void fpi_sdcp_device_enroll (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_identify (FpSdcpDevice *self);
|
||||
141
libfprint/fp-sdcp-device.c
Normal file
141
libfprint/fp-sdcp-device.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "sdcp_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fp-sdcp-device-private.h"
|
||||
|
||||
/**
|
||||
* SECTION: fp-sdcp-device
|
||||
* @title: FpSdcpDevice
|
||||
* @short_description: SDCP device subclass
|
||||
*
|
||||
* This is a base class for devices implementing the SDCP security protocol.
|
||||
*/
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpSdcpDevice, fp_sdcp_device, FP_TYPE_DEVICE)
|
||||
|
||||
#if 0
|
||||
/* XXX: We'll very likely want/need some properties on this class. */
|
||||
enum {
|
||||
PROP_0,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
#endif
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Callbacks/vfuncs */
|
||||
static void
|
||||
fp_sdcp_device_open (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
/* Try a reconnect if we still have the mac secret. */
|
||||
if (priv->mac_secret)
|
||||
fpi_sdcp_device_reconnect (self);
|
||||
else
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_enroll (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_enroll (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_identify (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_identify (self);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
static void
|
||||
fp_sdcp_device_finalize (GObject *object)
|
||||
{
|
||||
FpSdcpDevice *self = (FpSdcpDevice *) object;
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->intermediate_cas, g_ptr_array_unref);
|
||||
g_clear_pointer (&priv->slot, PK11_FreeSlot);
|
||||
g_clear_pointer (&priv->host_key_private, SECKEY_DestroyPrivateKey);
|
||||
g_clear_pointer (&priv->host_key_public, SECKEY_DestroyPublicKey);
|
||||
g_clear_pointer (&priv->master_secret, PK11_FreeSymKey);
|
||||
g_clear_pointer (&priv->mac_secret, PK11_FreeSymKey);
|
||||
g_clear_pointer (&priv->nss_init_context, NSS_ShutdownContext);
|
||||
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_constructed (GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->constructed (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_class_init (FpSdcpDeviceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_sdcp_device_finalize;
|
||||
object_class->get_property = fp_sdcp_device_get_property;
|
||||
object_class->constructed = fp_sdcp_device_constructed;
|
||||
|
||||
fp_device_class->open = fp_sdcp_device_open;
|
||||
fp_device_class->enroll = fp_sdcp_device_enroll;
|
||||
fp_device_class->verify = fp_sdcp_device_identify;
|
||||
fp_device_class->identify = fp_sdcp_device_identify;
|
||||
|
||||
#if 0
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_init (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
priv->intermediate_cas = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
|
||||
}
|
||||
29
libfprint/fp-sdcp-device.h
Normal file
29
libfprint/fp-sdcp-device.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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 <fp-device.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_SDCP_DEVICE (fp_sdcp_device_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpSdcpDevice, fp_sdcp_device, FP, SDCP_DEVICE, FpDevice)
|
||||
|
||||
G_END_DECLS
|
||||
@@ -23,6 +23,7 @@
|
||||
#if !GLIB_CHECK_VERSION (2, 57, 0)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
|
||||
#else
|
||||
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
|
||||
@@ -37,3 +38,9 @@ typedef struct _FpDeviceClass FpDeviceClass;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
|
||||
#endif
|
||||
|
||||
#if __GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 1)
|
||||
#define FP_GNUC_ACCESS(m, p, s) __attribute__((access (m, p, s)))
|
||||
#else
|
||||
#define FP_GNUC_ACCESS(m, p, s)
|
||||
#endif
|
||||
|
||||
@@ -135,6 +135,18 @@ fpi_device_error_new (FpDeviceError error)
|
||||
msg = "Print was not found on the devices storage.";
|
||||
break;
|
||||
|
||||
case FP_DEVICE_ERROR_DATA_DUPLICATE:
|
||||
msg = "This finger has already enrolled, please try a different finger";
|
||||
break;
|
||||
|
||||
case FP_DEVICE_ERROR_REMOVED:
|
||||
msg = "This device has been removed from the system.";
|
||||
break;
|
||||
|
||||
case FP_DEVICE_ERROR_UNTRUSTED:
|
||||
msg = "Could not verify integrity of the device, it cannot be trusted!";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warning ("Unsupported error, returning general error instead!");
|
||||
error = FP_DEVICE_ERROR_GENERAL;
|
||||
@@ -208,6 +220,7 @@ fpi_device_set_nr_enroll_stages (FpDevice *device,
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (enroll_stages > 0);
|
||||
|
||||
priv->nr_enroll_stages = enroll_stages;
|
||||
g_object_notify (G_OBJECT (device), "nr-enroll-stages");
|
||||
@@ -391,7 +404,7 @@ fpi_device_action_is_cancelled (FpDevice *device)
|
||||
|
||||
cancellable = g_task_get_cancellable (priv->current_task);
|
||||
|
||||
return cancellable ? g_cancellable_is_cancelled (cancellable) : FALSE;
|
||||
return g_cancellable_is_cancelled (cancellable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,6 +585,49 @@ fpi_device_get_cancellable (FpDevice *device)
|
||||
return g_task_get_cancellable (priv->current_task);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_removed_on_task_completed (FpDevice *device)
|
||||
{
|
||||
g_signal_emit_by_name (device, "removed");
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_remove:
|
||||
* @device: The #FpDevice
|
||||
*
|
||||
* Called to signal to the #FpDevice that it has been unplugged (physically
|
||||
* removed from the system).
|
||||
*
|
||||
* For USB devices, this API is called automatically by #FpContext.
|
||||
*/
|
||||
void
|
||||
fpi_device_remove (FpDevice *device)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (!priv->is_removed);
|
||||
|
||||
priv->is_removed = TRUE;
|
||||
|
||||
g_object_notify (G_OBJECT (device), "removed");
|
||||
|
||||
/* If there is a pending action, we wait for it to fail, otherwise we
|
||||
* immediately emit the "removed" signal. */
|
||||
if (priv->current_task)
|
||||
{
|
||||
g_signal_connect_object (priv->current_task,
|
||||
"notify::completed",
|
||||
(GCallback) emit_removed_on_task_completed,
|
||||
device,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_emit_by_name (device, "removed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_action_error:
|
||||
* @device: The #FpDevice
|
||||
@@ -593,7 +649,11 @@ fpi_device_action_error (FpDevice *device,
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_debug ("Device reported generic error during action; action was: %i", priv->current_action);
|
||||
g_autofree char *action_str = NULL;
|
||||
|
||||
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_debug ("Device reported generic error (%s) during action; action was: %s",
|
||||
error->message, action_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -682,15 +742,49 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
|
||||
{
|
||||
FpDeviceTaskReturnData *data = user_data;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
|
||||
g_autofree char *action_str = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_debug ("Completing action %d in idle!", priv->current_action);
|
||||
|
||||
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_debug ("Completing action %s in idle!", action_str);
|
||||
|
||||
task = g_steal_pointer (&priv->current_task);
|
||||
action = priv->current_action;
|
||||
priv->current_action = FPI_DEVICE_ACTION_NONE;
|
||||
priv->current_task_idle_return_source = NULL;
|
||||
|
||||
if (action == FPI_DEVICE_ACTION_OPEN &&
|
||||
data->type != FP_DEVICE_TASK_RETURN_ERROR)
|
||||
{
|
||||
priv->is_open = TRUE;
|
||||
g_object_notify (G_OBJECT (data->device), "open");
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_CLOSE)
|
||||
{
|
||||
/* Always consider the device closed. Drivers should try hard to close the
|
||||
* device. Generally, e.g. cancellations should be ignored.
|
||||
*/
|
||||
priv->is_open = FALSE;
|
||||
g_object_notify (G_OBJECT (data->device), "open");
|
||||
}
|
||||
|
||||
/* Return FP_DEVICE_ERROR_REMOVED if the device is removed,
|
||||
* with the exception of a successful open, which is an odd corner case. */
|
||||
if (priv->is_removed &&
|
||||
((action != FPI_DEVICE_ACTION_OPEN) ||
|
||||
(action == FPI_DEVICE_ACTION_OPEN && data->type == FP_DEVICE_TASK_RETURN_ERROR)))
|
||||
{
|
||||
g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
|
||||
|
||||
/* NOTE: The removed signal will be emitted from the GTask
|
||||
* notify::completed if that is necessary. */
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
switch (data->type)
|
||||
{
|
||||
case FP_DEVICE_TASK_RETURN_INT:
|
||||
@@ -702,16 +796,17 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_OBJECT:
|
||||
g_task_return_pointer (task, data->result, g_object_unref);
|
||||
g_task_return_pointer (task, g_steal_pointer (&data->result),
|
||||
g_object_unref);
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
|
||||
g_task_return_pointer (task, data->result,
|
||||
g_task_return_pointer (task, g_steal_pointer (&data->result),
|
||||
(GDestroyNotify) g_ptr_array_unref);
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_ERROR:
|
||||
g_task_return_error (task, data->result);
|
||||
g_task_return_error (task, g_steal_pointer (&data->result));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -724,6 +819,30 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
|
||||
static void
|
||||
fpi_device_task_return_data_free (FpDeviceTaskReturnData *data)
|
||||
{
|
||||
if (data->result)
|
||||
{
|
||||
switch (data->type)
|
||||
{
|
||||
case FP_DEVICE_TASK_RETURN_INT:
|
||||
case FP_DEVICE_TASK_RETURN_BOOL:
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_OBJECT:
|
||||
g_clear_object ((GObject **) &data->result);
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
|
||||
g_clear_pointer ((GPtrArray **) &data->result, g_ptr_array_unref);
|
||||
break;
|
||||
|
||||
case FP_DEVICE_TASK_RETURN_ERROR:
|
||||
g_clear_error ((GError **) &data->result);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
g_object_unref (data->device);
|
||||
g_free (data);
|
||||
}
|
||||
@@ -776,6 +895,7 @@ fpi_device_probe_complete (FpDevice *device,
|
||||
g_debug ("Device reported probe completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -818,12 +938,7 @@ fpi_device_open_complete (FpDevice *device, GError *error)
|
||||
g_debug ("Device reported open completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
priv->is_open = TRUE;
|
||||
g_object_notify (G_OBJECT (device), "open");
|
||||
}
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
|
||||
@@ -851,6 +966,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
|
||||
g_debug ("Device reported close completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
switch (priv->type)
|
||||
{
|
||||
@@ -875,16 +991,10 @@ fpi_device_close_complete (FpDevice *device, GError *error)
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
priv->is_open = FALSE;
|
||||
g_object_notify (G_OBJECT (device), "open");
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
|
||||
GUINT_TO_POINTER (TRUE));
|
||||
}
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
|
||||
GUINT_TO_POINTER (TRUE));
|
||||
else
|
||||
{
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
|
||||
}
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -907,12 +1017,14 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
||||
g_debug ("Device reported enroll completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if (FP_IS_PRINT (print))
|
||||
{
|
||||
FpiPrintType print_type;
|
||||
g_autofree char *finger_str = NULL;
|
||||
|
||||
g_object_get (print, "fpi-type", &print_type, NULL);
|
||||
if (print_type == FPI_PRINT_UNDEFINED)
|
||||
@@ -926,6 +1038,9 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
||||
return;
|
||||
}
|
||||
|
||||
finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
|
||||
g_debug ("Print for finger %s enrolled", finger_str);
|
||||
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
|
||||
}
|
||||
else
|
||||
@@ -974,6 +1089,7 @@ fpi_device_verify_complete (FpDevice *device,
|
||||
data = g_task_get_task_data (priv->current_task);
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -1033,6 +1149,7 @@ fpi_device_identify_complete (FpDevice *device,
|
||||
data = g_task_get_task_data (priv->current_task);
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -1048,7 +1165,7 @@ fpi_device_identify_complete (FpDevice *device,
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, GINT_TO_POINTER (TRUE));
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, GUINT_TO_POINTER (TRUE));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1089,6 +1206,7 @@ fpi_device_capture_complete (FpDevice *device,
|
||||
g_debug ("Device reported capture completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -1134,6 +1252,7 @@ fpi_device_delete_complete (FpDevice *device,
|
||||
g_debug ("Device reported deletion completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (!error)
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
|
||||
@@ -1168,6 +1287,7 @@ fpi_device_list_complete (FpDevice *device,
|
||||
g_debug ("Device reported listing completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
|
||||
if (prints && error)
|
||||
{
|
||||
@@ -1383,3 +1503,59 @@ fpi_device_identify_report (FpDevice *device,
|
||||
if (call_cb && data->match_cb)
|
||||
data->match_cb (device, data->match, data->print, data->match_data, data->error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_report_finger_status:
|
||||
* @device: The #FpDevice
|
||||
* @finger_status: The current #FpFingerStatusFlags to report
|
||||
*
|
||||
* Report the finger status for the @device.
|
||||
* This can be used by UI to give a feedback
|
||||
*
|
||||
* Returns: %TRUE if changed
|
||||
*/
|
||||
gboolean
|
||||
fpi_device_report_finger_status (FpDevice *device,
|
||||
FpFingerStatusFlags finger_status)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
g_autofree char *status_string = NULL;
|
||||
|
||||
if (priv->finger_status == finger_status)
|
||||
return FALSE;
|
||||
|
||||
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
|
||||
fp_dbg ("Device reported finger status change: %s", status_string);
|
||||
|
||||
priv->finger_status = finger_status;
|
||||
g_object_notify (G_OBJECT (device), "finger-status");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_report_finger_status_changes:
|
||||
* @device: The #FpDevice
|
||||
* @added_status: The #FpFingerStatusFlags to add
|
||||
* @removed_status: The #FpFingerStatusFlags to remove
|
||||
*
|
||||
* Report the finger status for the @device adding the @added_status flags
|
||||
* and removing the @removed_status flags.
|
||||
*
|
||||
* This can be used by UI to give a feedback
|
||||
*
|
||||
* Returns: %TRUE if changed
|
||||
*/
|
||||
gboolean
|
||||
fpi_device_report_finger_status_changes (FpDevice *device,
|
||||
FpFingerStatusFlags added_status,
|
||||
FpFingerStatusFlags removed_status)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
FpFingerStatusFlags finger_status = priv->finger_status;
|
||||
|
||||
finger_status |= added_status;
|
||||
finger_status &= ~removed_status;
|
||||
|
||||
return fpi_device_report_finger_status (device, finger_status);
|
||||
}
|
||||
|
||||
@@ -202,6 +202,7 @@ void fpi_device_get_delete_data (FpDevice *device,
|
||||
FpPrint **print);
|
||||
GCancellable *fpi_device_get_cancellable (FpDevice *device);
|
||||
|
||||
void fpi_device_remove (FpDevice *device);
|
||||
|
||||
GSource * fpi_device_add_timeout (FpDevice *device,
|
||||
gint interval,
|
||||
@@ -255,4 +256,10 @@ void fpi_device_identify_report (FpDevice *device,
|
||||
FpPrint *print,
|
||||
GError *error);
|
||||
|
||||
gboolean fpi_device_report_finger_status (FpDevice *device,
|
||||
FpFingerStatusFlags finger_status);
|
||||
gboolean fpi_device_report_finger_status_changes (FpDevice *device,
|
||||
FpFingerStatusFlags added_status,
|
||||
FpFingerStatusFlags removed_status);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -41,6 +41,9 @@ fp_image_device_get_instance_private (FpImageDevice *self)
|
||||
g_type_class_get_instance_private_offset (img_class));
|
||||
}
|
||||
|
||||
static void fp_image_device_change_state (FpImageDevice *self,
|
||||
FpiImageDeviceState state);
|
||||
|
||||
/* Private shared functions */
|
||||
|
||||
void
|
||||
@@ -51,62 +54,105 @@ fpi_image_device_activate (FpImageDevice *self)
|
||||
|
||||
g_assert (!priv->active);
|
||||
|
||||
/* We don't have a neutral ACTIVE state, but we always will
|
||||
* go into WAIT_FINGER_ON afterwards. */
|
||||
priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||
|
||||
/* We might have been waiting for deactivation to finish before
|
||||
* starting the next operation. */
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
|
||||
fp_dbg ("Activating image device\n");
|
||||
fp_dbg ("Activating image device");
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_ACTIVATING);
|
||||
cls->activate (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_image_device_deactivate (FpImageDevice *self)
|
||||
fpi_image_device_deactivate (FpImageDevice *self, gboolean cancelling)
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||
|
||||
if (!priv->active)
|
||||
if (!priv->active || priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
|
||||
{
|
||||
/* XXX: We currently deactivate both from minutiae scan result
|
||||
* and finger off report. */
|
||||
fp_dbg ("Already deactivated, ignoring request.");
|
||||
return;
|
||||
}
|
||||
if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
|
||||
if (!cancelling && priv->state != FPI_IMAGE_DEVICE_STATE_IDLE)
|
||||
g_warning ("Deactivating image device while it is not idle, this should not happen.");
|
||||
|
||||
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||
|
||||
fp_dbg ("Deactivating image device\n");
|
||||
fp_dbg ("Deactivating image device");
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
|
||||
cls->deactivate (self);
|
||||
}
|
||||
|
||||
/* Static helper functions */
|
||||
|
||||
/* This should not be called directly to activate/deactivate the device! */
|
||||
static void
|
||||
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
g_autofree char *prev_state_str = NULL;
|
||||
g_autofree char *state_str = NULL;
|
||||
gboolean transition_is_valid = FALSE;
|
||||
gint i;
|
||||
|
||||
/* Cannot change to inactive using this function. */
|
||||
g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
struct
|
||||
{
|
||||
FpiImageDeviceState from;
|
||||
FpiImageDeviceState to;
|
||||
} valid_transitions[] = {
|
||||
{ FPI_IMAGE_DEVICE_STATE_INACTIVE, FPI_IMAGE_DEVICE_STATE_ACTIVATING },
|
||||
|
||||
/* We might have been waiting for the finger to go OFF to start the
|
||||
* next operation. */
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_IDLE },
|
||||
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
|
||||
|
||||
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
|
||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON },
|
||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_CAPTURE }, /* raw mode -- currently not supported */
|
||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING },
|
||||
|
||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_CAPTURE },
|
||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
||||
|
||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF },
|
||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_IDLE }, /* raw mode -- currently not supported */
|
||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
||||
|
||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_IDLE },
|
||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
||||
|
||||
{ FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
|
||||
};
|
||||
|
||||
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
|
||||
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
|
||||
fp_dbg ("Image device internal state change from %s to %s",
|
||||
prev_state_str, state_str);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
|
||||
{
|
||||
if (valid_transitions[i].from == priv->state && valid_transitions[i].to == state)
|
||||
{
|
||||
transition_is_valid = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!transition_is_valid)
|
||||
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
|
||||
prev_state_str, state_str);
|
||||
|
||||
priv->state = state;
|
||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
|
||||
|
||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
{
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NEEDED,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
}
|
||||
else if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
{
|
||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_NEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -114,14 +160,75 @@ fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
|
||||
if (priv->enroll_await_on_pending)
|
||||
/* We wait for both the minutiae scan to complete and the finger to
|
||||
* be removed before we switch to AWAIT_FINGER_ON. */
|
||||
if (priv->minutiae_scan_active || priv->finger_present)
|
||||
return;
|
||||
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
FpiDeviceAction action;
|
||||
|
||||
if (error)
|
||||
{
|
||||
priv->enroll_await_on_pending = FALSE;
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||
/* Keep the first error we encountered, but not if it is of type retry */
|
||||
if (priv->action_error && !(priv->action_error->domain == FP_DEVICE_RETRY))
|
||||
{
|
||||
g_warning ("Will complete with first error, new error was: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error (&priv->action_error);
|
||||
priv->action_error = error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not complete if the device is still active or a minutiae scan is pending. */
|
||||
if (priv->active || priv->minutiae_scan_active)
|
||||
return;
|
||||
|
||||
if (!priv->action_error)
|
||||
g_cancellable_set_error_if_cancelled (fpi_device_get_cancellable (device), &priv->action_error);
|
||||
|
||||
if (priv->action_error)
|
||||
{
|
||||
fpi_device_action_error (device, g_steal_pointer (&priv->action_error));
|
||||
g_clear_object (&priv->capture_image);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We are done, report the result. */
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
if (action == FPI_DEVICE_ACTION_ENROLL)
|
||||
{
|
||||
FpPrint *enroll_print;
|
||||
fpi_device_get_enroll_data (device, &enroll_print);
|
||||
|
||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
fpi_device_capture_complete (device, g_steal_pointer (&priv->capture_image), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->enroll_await_on_pending = TRUE;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,14 +244,16 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
FpiDeviceAction action;
|
||||
|
||||
/* Note: We rely on the device to not disappear during an operation. */
|
||||
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
||||
priv->minutiae_scan_active = FALSE;
|
||||
|
||||
if (!fp_image_detect_minutiae_finish (image, res, &error))
|
||||
{
|
||||
/* Cancel operation . */
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
fpi_device_action_error (device, g_steal_pointer (&error));
|
||||
fpi_image_device_deactivate (self);
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,13 +264,12 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
|
||||
}
|
||||
|
||||
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
||||
action = fpi_device_get_current_action (device);
|
||||
|
||||
if (action == FPI_DEVICE_ACTION_CAPTURE)
|
||||
{
|
||||
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->capture_image = g_steal_pointer (&image);
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,8 +283,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
|
||||
if (error->domain != FP_DEVICE_RETRY)
|
||||
{
|
||||
fpi_device_action_error (device, error);
|
||||
fpi_image_device_deactivate (self);
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
/* We might not yet be deactivating, if we are enrolling. */
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -199,8 +308,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
/* Start another scan or deactivate. */
|
||||
if (priv->enroll_stage == IMG_ENROLL_STAGES)
|
||||
{
|
||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||
fpi_image_device_deactivate (self);
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
fpi_image_device_deactivate (self, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -220,8 +329,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
|
||||
if (!error || error->domain == FP_DEVICE_RETRY)
|
||||
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
||||
fpi_device_verify_complete (device, error);
|
||||
fpi_image_device_deactivate (self);
|
||||
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
@@ -243,8 +352,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
|
||||
if (!error || error->domain == FP_DEVICE_RETRY)
|
||||
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
||||
fpi_device_identify_complete (device, error);
|
||||
fpi_image_device_deactivate (self);
|
||||
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -299,6 +408,19 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpiDeviceAction action;
|
||||
|
||||
if (present)
|
||||
{
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_PRESENT,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_NONE,
|
||||
FP_FINGER_STATUS_PRESENT);
|
||||
}
|
||||
|
||||
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||
{
|
||||
/* Do we really want to always ignore such reports? We could
|
||||
@@ -317,27 +439,23 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||
|
||||
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
||||
|
||||
priv->finger_present = present;
|
||||
|
||||
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||
{
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
|
||||
}
|
||||
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||
{
|
||||
/* We need to deactivate or continue to await finger */
|
||||
|
||||
/* There are three possible situations:
|
||||
* 1. We are deactivating the device and the action is still in progress
|
||||
* (minutiae detection).
|
||||
* 2. We are still deactivating the device after an action completed
|
||||
* 3. We were waiting for finger removal to start the new action
|
||||
* Either way, we always end up deactivating except for the enroll case.
|
||||
/* If we are in the non-enroll case, we always deactivate.
|
||||
*
|
||||
* The enroll case is special as AWAIT_FINGER_ON should only happen after
|
||||
* minutiae detection to prevent deactivation (without cancellation)
|
||||
* from the AWAIT_FINGER_ON state.
|
||||
* In the enroll case, the decision can only be made after minutiae
|
||||
* detection has finished.
|
||||
*/
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
|
||||
|
||||
if (action != FPI_DEVICE_ACTION_ENROLL)
|
||||
fpi_image_device_deactivate (self);
|
||||
fpi_image_device_deactivate (self, FALSE);
|
||||
else
|
||||
fp_image_device_enroll_maybe_await_finger_on (self);
|
||||
}
|
||||
@@ -372,16 +490,19 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||
|
||||
g_debug ("Image device captured an image");
|
||||
|
||||
priv->minutiae_scan_active = TRUE;
|
||||
|
||||
/* XXX: We also detect minutiae in capture mode, we solely do this
|
||||
* to normalize the image which will happen as a by-product. */
|
||||
fp_image_detect_minutiae (image,
|
||||
fpi_device_get_cancellable (FP_DEVICE (self)),
|
||||
fpi_image_device_minutiae_detected,
|
||||
self);
|
||||
|
||||
/* XXX: This is wrong if we add support for raw capture mode. */
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,36 +538,27 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||
g_debug ("Reporting retry during enroll");
|
||||
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
||||
|
||||
/* Wait for finger removal and re-touch.
|
||||
* TODO: Do we need to check that the finger is already off? */
|
||||
priv->enroll_await_on_pending = TRUE;
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||
priv->cancelling = TRUE;
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->cancelling = FALSE;
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
fp_image_device_maybe_complete_action (self, NULL);
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
priv->cancelling = TRUE;
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->cancelling = FALSE;
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
fp_image_device_maybe_complete_action (self, NULL);
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We abort the operation and let the surrounding code retry in the
|
||||
* non-enroll case (this is identical to a session error). */
|
||||
g_debug ("Abort current operation due to retry (non-enroll case)");
|
||||
priv->cancelling = TRUE;
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->cancelling = FALSE;
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
/* The capture case where there is no early reporting. */
|
||||
g_debug ("Abort current operation due to retry (no early-reporting)");
|
||||
fp_image_device_maybe_complete_action (self, error);
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,10 +617,8 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error)
|
||||
if (error->domain == FP_DEVICE_RETRY)
|
||||
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
||||
|
||||
priv->cancelling = TRUE;
|
||||
fpi_image_device_deactivate (self);
|
||||
priv->cancelling = FALSE;
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
fp_image_device_maybe_complete_action (self, error);
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -527,6 +637,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (priv->active == FALSE);
|
||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
@@ -545,6 +656,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||
|
||||
/* We always want to capture at this point, move to AWAIT_FINGER
|
||||
* state. */
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||
}
|
||||
|
||||
@@ -559,36 +671,20 @@ void
|
||||
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
|
||||
{
|
||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_return_if_fail (priv->active == TRUE);
|
||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
|
||||
|
||||
g_debug ("Image device deactivation completed");
|
||||
|
||||
priv->active = FALSE;
|
||||
|
||||
/* Deactivation completed. As we deactivate in the background
|
||||
* there may already be a new task pending. Check whether we
|
||||
* need to do anything. */
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
/* Assume finger was removed. */
|
||||
priv->finger_present = FALSE;
|
||||
|
||||
/* Special case, if we should be closing, but didn't due to a running
|
||||
* deactivation, then do so now. */
|
||||
if (action == FPI_DEVICE_ACTION_CLOSE)
|
||||
{
|
||||
cls->img_close (self);
|
||||
return;
|
||||
}
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
|
||||
/* We might be waiting to be able to activate again. */
|
||||
if (priv->pending_activation_timeout_id)
|
||||
{
|
||||
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||
priv->pending_activation_timeout_id =
|
||||
g_idle_add ((GSourceFunc) fpi_image_device_activate, self);
|
||||
}
|
||||
fp_image_device_maybe_complete_action (self, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -614,6 +710,8 @@ fpi_image_device_open_complete (FpImageDevice *self, GError *error)
|
||||
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||
|
||||
fpi_device_report_finger_status (FP_DEVICE (self), FP_FINGER_STATUS_NONE);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
/**
|
||||
* FpiImageDeviceState:
|
||||
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
|
||||
* @FPI_IMAGE_DEVICE_STATE_ACTIVATING: State during activate callback
|
||||
* @FPI_IMAGE_DEVICE_STATE_IDLE: Activated but idle
|
||||
* @FPI_IMAGE_DEVICE_STATE_DEACTIVATING: State during deactivate callback
|
||||
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
|
||||
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||
@@ -35,9 +38,33 @@
|
||||
* The driver needs to call fpi_image_device_report_finger_status() to move
|
||||
* between the different states. Note that the capture state might be entered
|
||||
* unconditionally if the device supports raw capturing.
|
||||
*
|
||||
* A usual run would look like:
|
||||
* - inactive -> activating: activate vfunc is called
|
||||
* - activating -> idle: fpi_image_device_activate_complete()
|
||||
* - idle -> await-finger-on
|
||||
* - await-finger-on -> capture: fpi_image_device_report_finger_status()
|
||||
* - capture -> await-finger-off: fpi_image_device_image_captured()
|
||||
* - await-finger-off -> idle: fpi_image_device_report_finger_status()
|
||||
* - idle -> deactivating: deactivate vfunc is called
|
||||
* - deactivating -> inactive: fpi_image_device_deactivate_complete()
|
||||
*
|
||||
* Raw mode is currently not supported (not waiting for finger), but in that
|
||||
* case the following transitions are valid:
|
||||
* - idle -> capture
|
||||
* - capture -> idle
|
||||
*
|
||||
* Also valid are these transitions in case of errors or cancellations:
|
||||
* - activating -> inactive: fpi_image_device_activate_complete()
|
||||
* - await-finger-on -> deactivating: deactivate vfunc is called
|
||||
* - capture -> deactivating: deactivate vfunc is called
|
||||
* - await-finger-off -> deactivating: deactivate vfunc is called
|
||||
*/
|
||||
typedef enum {
|
||||
FPI_IMAGE_DEVICE_STATE_INACTIVE,
|
||||
FPI_IMAGE_DEVICE_STATE_ACTIVATING,
|
||||
FPI_IMAGE_DEVICE_STATE_DEACTIVATING,
|
||||
FPI_IMAGE_DEVICE_STATE_IDLE,
|
||||
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
|
||||
FPI_IMAGE_DEVICE_STATE_CAPTURE,
|
||||
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
|
||||
@@ -58,11 +85,6 @@ typedef enum {
|
||||
* finger or image capture). Implementing this is optional, it can e.g. be
|
||||
* used to flash an LED when waiting for a finger.
|
||||
*
|
||||
* These are the main entry points for image based drivers. For all but the
|
||||
* change_state vfunc, implementations *must* eventually call the corresponding
|
||||
* function to finish the operation. It is also acceptable to call the generic
|
||||
*
|
||||
*
|
||||
* These are the main entry points for drivers to implement. Drivers may not
|
||||
* implement all of these entry points if they do not support the operation
|
||||
* (or a default implementation is sufficient).
|
||||
@@ -72,9 +94,8 @@ typedef enum {
|
||||
* fpi_device_action_error() function but doing so is not recommended in most
|
||||
* usecases.
|
||||
*
|
||||
* Drivers *must* also handle cancellation properly for any long running
|
||||
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||
* Image drivers must expect a @deactivate call to happen at any point during
|
||||
* image capture.
|
||||
*
|
||||
* This API is solely intended for drivers. It is purely internal and neither
|
||||
* API nor ABI stable.
|
||||
|
||||
@@ -240,7 +240,7 @@ fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GErr
|
||||
gint score;
|
||||
gstruct = g_ptr_array_index (template->prints, i);
|
||||
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
|
||||
fp_dbg ("score %d", score);
|
||||
fp_dbg ("score %d/%d", score, bz3_threshold);
|
||||
|
||||
if (score >= bz3_threshold)
|
||||
return FPI_MATCH_SUCCESS;
|
||||
|
||||
@@ -11,11 +11,13 @@ G_BEGIN_DECLS
|
||||
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
|
||||
* @FPI_PRINT_RAW: A raw print where the data is directly compared
|
||||
* @FPI_PRINT_NBIS: NBIS minutiae comparison
|
||||
* @FPI_PRINT_SDCP: Print from an SDCP conforming device
|
||||
*/
|
||||
typedef enum {
|
||||
FPI_PRINT_UNDEFINED = 0,
|
||||
FPI_PRINT_RAW,
|
||||
FPI_PRINT_NBIS,
|
||||
FPI_PRINT_SDCP,
|
||||
} FpiPrintType;
|
||||
|
||||
/**
|
||||
|
||||
1469
libfprint/fpi-sdcp-device.c
Normal file
1469
libfprint/fpi-sdcp-device.c
Normal file
File diff suppressed because it is too large
Load Diff
142
libfprint/fpi-sdcp-device.h
Normal file
142
libfprint/fpi-sdcp-device.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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 <glib-2.0/glib.h>
|
||||
#include "fpi-device.h"
|
||||
#include "fp-sdcp-device.h"
|
||||
|
||||
/**
|
||||
* FpiSdcpClaim:
|
||||
* @cert_m: The per-model ECDSA certificate (x509 ASN.1 DER encoded)
|
||||
* @pk_d: The device public key (65 bytes)
|
||||
* @pk_f: The firmware public key (65 bytes)
|
||||
* @h_f: The firmware hash
|
||||
* @s_m: Signature over @pk_d using the per-model private key (64 bytes)
|
||||
* @s_d: Signature over h_f and pk_f using the device private key (64 bytes)
|
||||
*
|
||||
* Structure to hold the claim as produced by the device during a secure
|
||||
* connect. See the SDCP specification for more details.
|
||||
*
|
||||
* Note all of these may simply be memory views into a larger #GBytes created
|
||||
* using g_bytes_new_from_bytes().
|
||||
*/
|
||||
struct _FpiSdcpClaim
|
||||
{
|
||||
/*< public >*/
|
||||
GBytes *cert_m;
|
||||
GBytes *pk_d;
|
||||
GBytes *pk_f;
|
||||
GBytes *h_f;
|
||||
GBytes *s_m;
|
||||
GBytes *s_d;
|
||||
};
|
||||
typedef struct _FpiSdcpClaim FpiSdcpClaim;
|
||||
|
||||
GType fpi_sdcp_claim_get_type (void) G_GNUC_CONST;
|
||||
FpiSdcpClaim *fpi_sdcp_claim_new (void);
|
||||
FpiSdcpClaim *fpi_sdcp_claim_copy (FpiSdcpClaim *other);
|
||||
void fpi_sdcp_claim_free (FpiSdcpClaim *claim);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSdcpClaim, fpi_sdcp_claim_free)
|
||||
|
||||
|
||||
/**
|
||||
* FpSdcpDeviceClass:
|
||||
* @connect: Establish SDCP connection. Similar to open in #FpDeviceClass
|
||||
* but called connect to mirror the SDCP specification.
|
||||
* @reconnect: Perform a faster reconnect. Drivers do not need to provide this
|
||||
* function. If reconnect fails, then a normal connect will be tried.
|
||||
* @enroll_begin: Start the enrollment procedure. In the absence of an error,
|
||||
* the driver must call fpi_sdcp_device_enroll_set_nonce() at any point. It
|
||||
* also must report enrollment progress using fpi_device_enroll_progress().
|
||||
* It should also store available metadata about the print in device memory.
|
||||
* The operation is completed with fpi_sdcp_device_enroll_ready().
|
||||
* @enroll_commit: Complete the enrollment procedure. This commits the newly
|
||||
* enrolled print to the device memory. Will only be called if enroll_begin
|
||||
* succeeded. The passed id may be %NULL, in that case the driver must
|
||||
* abort the enrollment process. id is owned by the base class and remains
|
||||
* valid throughout the operation.
|
||||
* @identify: Start identification process. On completion, the driver must call
|
||||
* fpi_sdcp_device_identify_complete(). To request the user to retry the
|
||||
* fpi_sdcp_device_identify_retry() function is used.
|
||||
*
|
||||
*
|
||||
* These are the main entry points for drivers implementing SDCP.
|
||||
*
|
||||
* Drivers *must* eventually call the corresponding function to finish the
|
||||
* operation.
|
||||
*
|
||||
* XXX: Is the use of fpi_device_action_error() acceptable?
|
||||
*
|
||||
* Drivers *must* also handle cancellation properly for any long running
|
||||
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||
*
|
||||
* This API is solely intended for drivers. It is purely internal and neither
|
||||
* API nor ABI stable.
|
||||
*/
|
||||
struct _FpSdcpDeviceClass
|
||||
{
|
||||
FpDeviceClass parent_class;
|
||||
|
||||
void (*connect) (FpSdcpDevice *dev);
|
||||
void (*reconnect) (FpSdcpDevice *dev);
|
||||
void (*close) (FpSdcpDevice *dev);
|
||||
void (*enroll_begin) (FpSdcpDevice *dev);
|
||||
void (*enroll_commit) (FpSdcpDevice *dev,
|
||||
GBytes *id);
|
||||
void (*identify) (FpSdcpDevice *dev);
|
||||
};
|
||||
|
||||
void fpi_sdcp_device_set_intermediat_cas (FpSdcpDevice *self,
|
||||
GBytes *ca_1,
|
||||
GBytes *ca_2);
|
||||
|
||||
void fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
|
||||
GBytes **r_h,
|
||||
GBytes **pk_h);
|
||||
void fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
|
||||
GBytes *r_d,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
|
||||
GBytes **r_h);
|
||||
void fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_enroll_set_nonce (FpSdcpDevice *self,
|
||||
GBytes *nonce);
|
||||
void fpi_sdcp_device_enroll_ready (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_enroll_commit_complete (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_identify_data (FpSdcpDevice *self,
|
||||
GBytes **nonce);
|
||||
void fpi_sdcp_device_identify_retry (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
@@ -74,7 +74,7 @@
|
||||
* upon success (or fails).
|
||||
*
|
||||
* Your completion callback should examine the return value of
|
||||
* fpi_ssm_get_error() in ordater to determine whether the #FpiSsm completed or
|
||||
* fpi_ssm_get_error() in order to determine whether the #FpiSsm completed or
|
||||
* failed. An error code of zero indicates successful completion.
|
||||
*/
|
||||
|
||||
@@ -130,6 +130,7 @@ fpi_ssm_new_full (FpDevice *dev,
|
||||
{
|
||||
FpiSsm *machine;
|
||||
|
||||
BUG_ON (dev == NULL);
|
||||
BUG_ON (nr_states < 1);
|
||||
BUG_ON (handler == NULL);
|
||||
|
||||
@@ -155,6 +156,8 @@ fpi_ssm_set_data (FpiSsm *machine,
|
||||
gpointer ssm_data,
|
||||
GDestroyNotify ssm_data_destroy)
|
||||
{
|
||||
g_return_if_fail (machine);
|
||||
|
||||
if (machine->ssm_data_destroy && machine->ssm_data)
|
||||
machine->ssm_data_destroy (machine->ssm_data);
|
||||
|
||||
@@ -173,12 +176,16 @@ fpi_ssm_set_data (FpiSsm *machine,
|
||||
void *
|
||||
fpi_ssm_get_data (FpiSsm *machine)
|
||||
{
|
||||
g_return_val_if_fail (machine, NULL);
|
||||
|
||||
return machine->ssm_data;
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_ssm_clear_delayed_action (FpiSsm *machine)
|
||||
{
|
||||
g_return_if_fail (machine);
|
||||
|
||||
if (machine->cancellable_id)
|
||||
{
|
||||
g_cancellable_disconnect (machine->cancellable, machine->cancellable_id);
|
||||
@@ -235,6 +242,8 @@ fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
|
||||
gpointer user_data,
|
||||
GDestroyNotify destroy_func)
|
||||
{
|
||||
g_return_if_fail (machine);
|
||||
|
||||
BUG_ON (machine->completed);
|
||||
BUG_ON (machine->timeout != NULL);
|
||||
|
||||
@@ -302,6 +311,8 @@ __ssm_call_handler (FpiSsm *machine)
|
||||
void
|
||||
fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
|
||||
{
|
||||
g_return_if_fail (ssm != NULL);
|
||||
|
||||
BUG_ON (!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
@@ -336,6 +347,9 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
void
|
||||
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||
{
|
||||
g_return_if_fail (parent != NULL);
|
||||
g_return_if_fail (child != NULL);
|
||||
|
||||
BUG_ON (parent->timeout);
|
||||
child->parentsm = parent;
|
||||
|
||||
@@ -355,6 +369,8 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||
void
|
||||
fpi_ssm_mark_completed (FpiSsm *machine)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
BUG_ON (machine->completed);
|
||||
BUG_ON (machine->timeout != NULL);
|
||||
|
||||
@@ -427,6 +443,7 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
||||
void
|
||||
fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
g_assert (error);
|
||||
if (machine->error)
|
||||
{
|
||||
@@ -534,6 +551,8 @@ fpi_ssm_next_state_delayed (FpiSsm *machine,
|
||||
void
|
||||
fpi_ssm_jump_to_state (FpiSsm *machine, int state)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
BUG_ON (machine->completed);
|
||||
BUG_ON (state < 0 || state >= machine->nr_states);
|
||||
BUG_ON (machine->timeout != NULL);
|
||||
@@ -598,6 +617,20 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||
g_source_set_name (machine->timeout, source_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_device:
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Returns the device that the SSM has been associated with.
|
||||
*
|
||||
* Returns: (transfer none): the #FpDevice.
|
||||
*/
|
||||
FpDevice *
|
||||
fpi_ssm_get_device (FpiSsm *machine)
|
||||
{
|
||||
return machine->dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_cur_state:
|
||||
* @machine: an #FpiSsm state machine
|
||||
@@ -610,6 +643,8 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||
int
|
||||
fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||
{
|
||||
g_return_val_if_fail (machine != NULL, 0);
|
||||
|
||||
return machine->cur_state;
|
||||
}
|
||||
|
||||
@@ -624,6 +659,8 @@ fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||
GError *
|
||||
fpi_ssm_get_error (FpiSsm *machine)
|
||||
{
|
||||
g_return_val_if_fail (machine != NULL, NULL);
|
||||
|
||||
return machine->error;
|
||||
}
|
||||
|
||||
@@ -638,6 +675,8 @@ fpi_ssm_get_error (FpiSsm *machine)
|
||||
GError *
|
||||
fpi_ssm_dup_error (FpiSsm *machine)
|
||||
{
|
||||
g_return_val_if_fail (machine != NULL, NULL);
|
||||
|
||||
if (machine->error)
|
||||
return g_error_copy (machine->error);
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ void fpi_ssm_mark_failed (FpiSsm *machine,
|
||||
void fpi_ssm_set_data (FpiSsm *machine,
|
||||
gpointer ssm_data,
|
||||
GDestroyNotify ssm_data_destroy);
|
||||
|
||||
FpDevice * fpi_ssm_get_device (FpiSsm *machine);
|
||||
gpointer fpi_ssm_get_data (FpiSsm *machine);
|
||||
GError * fpi_ssm_get_error (FpiSsm *machine);
|
||||
GError * fpi_ssm_dup_error (FpiSsm *machine);
|
||||
|
||||
@@ -105,6 +105,7 @@ fpi_usb_transfer_new (FpDevice * device)
|
||||
|
||||
self = g_slice_new0 (FpiUsbTransfer);
|
||||
self->ref_count = 1;
|
||||
self->type = FP_TRANSFER_NONE;
|
||||
|
||||
self->device = device;
|
||||
|
||||
@@ -186,7 +187,7 @@ fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||
* fpi_usb_transfer_fill_bulk_full:
|
||||
* @transfer: The #FpiUsbTransfer
|
||||
* @endpoint: The endpoint to send the transfer to
|
||||
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL.
|
||||
* @buffer: The data to send.
|
||||
* @length: The size of @buffer
|
||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||
*
|
||||
@@ -274,7 +275,7 @@ fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||
* fpi_usb_transfer_fill_interrupt_full:
|
||||
* @transfer: The #FpiUsbTransfer
|
||||
* @endpoint: The endpoint to send the transfer to
|
||||
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL.
|
||||
* @buffer: The data to send.
|
||||
* @length: The size of @buffer
|
||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||
*
|
||||
@@ -353,6 +354,24 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
|
||||
fpi_usb_transfer_unref (transfer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
transfer_cancel_cb (FpiUsbTransfer *transfer)
|
||||
{
|
||||
GError *error;
|
||||
FpiUsbTransferCallback callback;
|
||||
|
||||
error = g_error_new_literal (G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED,
|
||||
"Transfer was cancelled before being started");
|
||||
callback = transfer->callback;
|
||||
transfer->callback = NULL;
|
||||
transfer->actual_length = -1;
|
||||
callback (transfer, transfer->device, transfer->user_data, error);
|
||||
|
||||
fpi_usb_transfer_unref (transfer);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_usb_transfer_submit:
|
||||
@@ -386,6 +405,18 @@ fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
|
||||
|
||||
log_transfer (transfer, TRUE, NULL);
|
||||
|
||||
/* Work around libgusb cancellation issue, see
|
||||
* https://github.com/hughsie/libgusb/pull/42
|
||||
* should be fixed with libgusb 0.3.7.
|
||||
* Note that this is not race free, we rely on libfprint and API users
|
||||
* not cancelling from a different thread here.
|
||||
*/
|
||||
if (cancellable && g_cancellable_is_cancelled (cancellable))
|
||||
{
|
||||
g_idle_add ((GSourceFunc) transfer_cancel_cb, transfer);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (transfer->type)
|
||||
{
|
||||
case FP_TRANSFER_BULK:
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gusb.h>
|
||||
#include "fpi-compat.h"
|
||||
#include "fpi-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -47,10 +48,10 @@ typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
|
||||
* Type of the transfer.
|
||||
*/
|
||||
typedef enum {
|
||||
FP_TRANSFER_NONE = 0,
|
||||
FP_TRANSFER_BULK,
|
||||
FP_TRANSFER_CONTROL,
|
||||
FP_TRANSFER_INTERRUPT,
|
||||
FP_TRANSFER_NONE = -1,
|
||||
FP_TRANSFER_CONTROL = 0,
|
||||
FP_TRANSFER_BULK = 2,
|
||||
FP_TRANSFER_INTERRUPT = 3,
|
||||
} FpiTransferType;
|
||||
|
||||
/**
|
||||
@@ -115,6 +116,7 @@ void fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||
guint8 endpoint,
|
||||
gsize length);
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
|
||||
guint8 endpoint,
|
||||
guint8 *buffer,
|
||||
@@ -134,6 +136,7 @@ void fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||
guint8 endpoint,
|
||||
gsize length);
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||
void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
|
||||
guint8 endpoint,
|
||||
guint8 *buffer,
|
||||
|
||||
@@ -83,6 +83,8 @@ main (int argc, char **argv)
|
||||
g_print ("\n");
|
||||
g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n");
|
||||
g_print ("\n");
|
||||
g_print ("The quality and functionality of drivers varies widely. libfprint maintainers may not be able to help with issues arising from their use.\n");
|
||||
g_print ("\n");
|
||||
g_print ("## USB devices\n");
|
||||
g_print ("\n");
|
||||
g_print ("USB ID | Driver\n");
|
||||
|
||||
208
libfprint/fprint-list-udev-hwdb.c
Normal file
208
libfprint/fprint-list-udev-hwdb.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
||||
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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 <config.h>
|
||||
|
||||
#include "fpi-context.h"
|
||||
#include "fpi-device.h"
|
||||
|
||||
static const FpIdEntry whitelist_id_table[] = {
|
||||
/* Currently known and unsupported devices.
|
||||
* 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 = 0x04f3, .pid = 0x036b },
|
||||
{ .vid = 0x04f3, .pid = 0x0c00 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c4b },
|
||||
{ .vid = 0x04f3, .pid = 0x0c4c },
|
||||
{ .vid = 0x04f3, .pid = 0x0c4f },
|
||||
{ .vid = 0x04f3, .pid = 0x0c57 },
|
||||
{ .vid = 0x04f3, .pid = 0x2706 },
|
||||
{ .vid = 0x06cb, .pid = 0x0081 },
|
||||
{ .vid = 0x06cb, .pid = 0x0088 },
|
||||
{ .vid = 0x06cb, .pid = 0x008a },
|
||||
{ .vid = 0x06cb, .pid = 0x009a },
|
||||
{ .vid = 0x06cb, .pid = 0x009b },
|
||||
{ .vid = 0x06cb, .pid = 0x00a2 },
|
||||
{ .vid = 0x06cb, .pid = 0x00b7 },
|
||||
{ .vid = 0x06cb, .pid = 0x00bb },
|
||||
{ .vid = 0x06cb, .pid = 0x00be },
|
||||
{ .vid = 0x06cb, .pid = 0x00cb },
|
||||
{ .vid = 0x06cb, .pid = 0x00d8 },
|
||||
{ .vid = 0x06cb, .pid = 0x00da },
|
||||
{ .vid = 0x0a5c, .pid = 0x5801 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5805 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5834 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5843 },
|
||||
{ .vid = 0x10a5, .pid = 0x0007 },
|
||||
{ .vid = 0x1188, .pid = 0x9545 },
|
||||
{ .vid = 0x138a, .pid = 0x0007 },
|
||||
{ .vid = 0x138a, .pid = 0x003a },
|
||||
{ .vid = 0x138a, .pid = 0x003c },
|
||||
{ .vid = 0x138a, .pid = 0x003d },
|
||||
{ .vid = 0x138a, .pid = 0x003f },
|
||||
{ .vid = 0x138a, .pid = 0x0090 },
|
||||
{ .vid = 0x138a, .pid = 0x0091 },
|
||||
{ .vid = 0x138a, .pid = 0x0092 },
|
||||
{ .vid = 0x138a, .pid = 0x0094 },
|
||||
{ .vid = 0x138a, .pid = 0x0097 },
|
||||
{ .vid = 0x138a, .pid = 0x009d },
|
||||
{ .vid = 0x138a, .pid = 0x00ab },
|
||||
{ .vid = 0x147e, .pid = 0x1002 },
|
||||
{ .vid = 0x1491, .pid = 0x0088 },
|
||||
{ .vid = 0x16d1, .pid = 0x1027 },
|
||||
{ .vid = 0x1c7a, .pid = 0x0300 },
|
||||
{ .vid = 0x1c7a, .pid = 0x0570 },
|
||||
{ .vid = 0x1c7a, .pid = 0x0575 },
|
||||
{ .vid = 0x27c6, .pid = 0x5042 },
|
||||
{ .vid = 0x27c6, .pid = 0x5110 },
|
||||
{ .vid = 0x27c6, .pid = 0x5117 },
|
||||
{ .vid = 0x27c6, .pid = 0x5201 },
|
||||
{ .vid = 0x27c6, .pid = 0x521d },
|
||||
{ .vid = 0x27c6, .pid = 0x5301 },
|
||||
{ .vid = 0x27c6, .pid = 0x530c },
|
||||
{ .vid = 0x27c6, .pid = 0x532d },
|
||||
{ .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 = 0x5584 },
|
||||
{ .vid = 0x27c6, .pid = 0x55a2 },
|
||||
{ .vid = 0x27c6, .pid = 0x55a4 },
|
||||
{ .vid = 0x27c6, .pid = 0x55b4 },
|
||||
{ .vid = 0x27c6, .pid = 0x5740 },
|
||||
{ .vid = 0x2808, .pid = 0x9338 },
|
||||
{ .vid = 0x298d, .pid = 0x2033 },
|
||||
{ .vid = 0x3538, .pid = 0x0930 },
|
||||
{ .vid = 0 },
|
||||
};
|
||||
|
||||
static const FpIdEntry blacklist_id_table[] = {
|
||||
{ .vid = 0x0483, .pid = 0x2016 },
|
||||
/* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */
|
||||
{ .vid = 0x045e, .pid = 0x00bb },
|
||||
{ .vid = 0 },
|
||||
};
|
||||
|
||||
static const FpDeviceClass whitelist = {
|
||||
.type = FP_DEVICE_TYPE_USB,
|
||||
.id_table = whitelist_id_table,
|
||||
.id = "whitelist",
|
||||
.full_name = "Hardcoded whitelist"
|
||||
};
|
||||
|
||||
GHashTable *printed = NULL;
|
||||
|
||||
static void
|
||||
print_driver (const FpDeviceClass *cls)
|
||||
{
|
||||
const FpIdEntry *entry;
|
||||
gint num_printed = 0;
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
return;
|
||||
|
||||
for (entry = cls->id_table; entry->vid != 0; entry++)
|
||||
{
|
||||
const FpIdEntry *bl_entry;
|
||||
char *key;
|
||||
|
||||
for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++)
|
||||
if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid)
|
||||
break;
|
||||
|
||||
if (bl_entry->vid != 0)
|
||||
continue;
|
||||
|
||||
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid);
|
||||
|
||||
if (g_hash_table_lookup (printed, key) != NULL)
|
||||
{
|
||||
if (cls == &whitelist)
|
||||
g_warning ("%s implemented by driver %s",
|
||||
key, (const char *) g_hash_table_lookup (printed, key));
|
||||
g_free (key);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_hash_table_insert (printed, key, (void *) cls->id);
|
||||
|
||||
if (num_printed == 0)
|
||||
{
|
||||
if (cls != &whitelist)
|
||||
g_print ("\n# Supported by libfprint driver %s\n", cls->id);
|
||||
else
|
||||
g_print ("\n# Known unsupported devices\n");
|
||||
}
|
||||
|
||||
g_print ("usb:v%04Xp%04X*\n",
|
||||
entry->vid, entry->pid);
|
||||
num_printed++;
|
||||
}
|
||||
|
||||
if (num_printed > 0)
|
||||
g_print (" ID_AUTOSUSPEND=1\n");
|
||||
}
|
||||
|
||||
static int
|
||||
driver_compare (gconstpointer p1, gconstpointer p2)
|
||||
{
|
||||
g_autoptr(FpDeviceClass) cls1 = g_type_class_ref (*(GType *) p1);
|
||||
g_autoptr(FpDeviceClass) cls2 = g_type_class_ref (*(GType *) p2);
|
||||
|
||||
return g_strcmp0 (cls1->id, cls2->id);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_autoptr(GArray) drivers = fpi_get_driver_types ();
|
||||
g_autofree char *program_name = NULL;
|
||||
guint i;
|
||||
|
||||
program_name = g_path_get_basename (argv[0]);
|
||||
|
||||
g_print ("# SPDX-License-Identifier: LGPL-2.1-or-later\n");
|
||||
g_print ("# This file has been generated using %s with all drivers enabled\n",
|
||||
program_name);
|
||||
|
||||
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
g_array_sort (drivers, driver_compare);
|
||||
|
||||
for (i = 0; i < drivers->len; i++)
|
||||
{
|
||||
GType driver = g_array_index (drivers, GType, i);
|
||||
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
continue;
|
||||
|
||||
print_driver (cls);
|
||||
}
|
||||
|
||||
print_driver (&whitelist);
|
||||
|
||||
g_hash_table_destroy (printed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
||||
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* 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 <config.h>
|
||||
|
||||
#include "fpi-context.h"
|
||||
#include "fpi-device.h"
|
||||
|
||||
static const FpIdEntry whitelist_id_table[] = {
|
||||
/* Unsupported (for now) Validity Sensors finger print readers */
|
||||
{ .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */
|
||||
{ .vid = 0x138a, .pid = 0x0091 },
|
||||
{ .vid = 0x138a, .pid = 0x0094 },
|
||||
{ .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */
|
||||
{ .vid = 0 },
|
||||
};
|
||||
|
||||
static const FpIdEntry blacklist_id_table[] = {
|
||||
{ .vid = 0x0483, .pid = 0x2016 },
|
||||
/* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */
|
||||
{ .vid = 0x045e, .pid = 0x00bb },
|
||||
{ .vid = 0 },
|
||||
};
|
||||
|
||||
static const FpDeviceClass whitelist = {
|
||||
.type = FP_DEVICE_TYPE_USB,
|
||||
.id_table = whitelist_id_table,
|
||||
.full_name = "Hardcoded whitelist"
|
||||
};
|
||||
|
||||
GHashTable *printed = NULL;
|
||||
|
||||
static void
|
||||
print_driver (const FpDeviceClass *cls)
|
||||
{
|
||||
const FpIdEntry *entry;
|
||||
gint num_printed = 0;
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
return;
|
||||
|
||||
for (entry = cls->id_table; entry->vid != 0; entry++)
|
||||
{
|
||||
const FpIdEntry *bl_entry;
|
||||
char *key;
|
||||
|
||||
for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++)
|
||||
if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid)
|
||||
break;
|
||||
|
||||
if (bl_entry->vid != 0)
|
||||
continue;
|
||||
|
||||
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid);
|
||||
|
||||
if (g_hash_table_lookup (printed, key) != NULL)
|
||||
{
|
||||
g_free (key);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
||||
|
||||
if (num_printed == 0)
|
||||
g_print ("# %s\n", cls->full_name);
|
||||
|
||||
g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n",
|
||||
entry->vid, entry->pid);
|
||||
g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n",
|
||||
entry->vid, entry->pid, cls->full_name);
|
||||
num_printed++;
|
||||
}
|
||||
|
||||
if (num_printed > 0)
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_autoptr(GArray) drivers = fpi_get_driver_types ();
|
||||
guint i;
|
||||
|
||||
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
for (i = 0; i < drivers->len; i++)
|
||||
{
|
||||
GType driver = g_array_index (drivers, GType, i);
|
||||
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||
continue;
|
||||
|
||||
print_driver (cls);
|
||||
}
|
||||
|
||||
print_driver (&whitelist);
|
||||
|
||||
g_hash_table_destroy (printed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -78,102 +78,146 @@ nbis_sources = [
|
||||
'nbis/mindtct/xytreps.c',
|
||||
]
|
||||
|
||||
aeslib = false
|
||||
aesx660 = false
|
||||
aes3k = false
|
||||
drivers_sources = []
|
||||
drivers_cflags = []
|
||||
foreach driver: drivers
|
||||
if driver == 'upekts'
|
||||
drivers_sources += [ 'drivers/upekts.c', 'drivers/upek_proto.c' ]
|
||||
endif
|
||||
if driver == 'upektc'
|
||||
drivers_sources += [ 'drivers/upektc.c' ]
|
||||
endif
|
||||
if driver == 'upeksonly'
|
||||
drivers_sources += [ 'drivers/upeksonly.c' ]
|
||||
endif
|
||||
if driver == 'uru4000'
|
||||
drivers_sources += [ 'drivers/uru4000.c' ]
|
||||
endif
|
||||
if driver == 'aes1610'
|
||||
drivers_sources += [ 'drivers/aes1610.c' ]
|
||||
aeslib = true
|
||||
endif
|
||||
if driver == 'aes1660'
|
||||
drivers_sources += [ 'drivers/aes1660.c' ]
|
||||
aeslib = true
|
||||
aesx660 = true
|
||||
endif
|
||||
if driver == 'aes2501'
|
||||
drivers_sources += [ 'drivers/aes2501.c' ]
|
||||
aeslib = true
|
||||
endif
|
||||
if driver == 'aes2550'
|
||||
drivers_sources += [ 'drivers/aes2550.c' ]
|
||||
aeslib = true
|
||||
endif
|
||||
if driver == 'aes2660'
|
||||
drivers_sources += [ 'drivers/aes2660.c' ]
|
||||
aeslib = true
|
||||
aesx660 = true
|
||||
endif
|
||||
if driver == 'aes3500'
|
||||
drivers_sources += [ 'drivers/aes3500.c' ]
|
||||
aeslib = true
|
||||
aes3k = true
|
||||
endif
|
||||
if driver == 'aes4000'
|
||||
drivers_sources += [ 'drivers/aes4000.c' ]
|
||||
aeslib = true
|
||||
aes3k = true
|
||||
endif
|
||||
if driver == 'vcom5s'
|
||||
drivers_sources += [ 'drivers/vcom5s.c' ]
|
||||
endif
|
||||
if driver == 'vfs101'
|
||||
drivers_sources += [ 'drivers/vfs101.c' ]
|
||||
endif
|
||||
if driver == 'vfs301'
|
||||
drivers_sources += [ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ]
|
||||
endif
|
||||
if driver == 'vfs5011'
|
||||
drivers_sources += [ 'drivers/vfs5011.c' ]
|
||||
endif
|
||||
if driver == 'upektc_img'
|
||||
drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ]
|
||||
endif
|
||||
if driver == 'etes603'
|
||||
drivers_sources += [ 'drivers/etes603.c' ]
|
||||
endif
|
||||
if driver == 'vfs0050'
|
||||
drivers_sources += [ 'drivers/vfs0050.c' ]
|
||||
endif
|
||||
if driver == 'elan'
|
||||
drivers_sources += [ 'drivers/elan.c' ]
|
||||
endif
|
||||
if driver == 'virtual_image'
|
||||
drivers_sources += [ 'drivers/virtual-image.c' ]
|
||||
endif
|
||||
if driver == 'synaptics'
|
||||
drivers_sources += [
|
||||
'drivers/synaptics/synaptics.c',
|
||||
'drivers/synaptics/bmkt_message.c',
|
||||
]
|
||||
driver_sources = {
|
||||
'upekts' :
|
||||
[ 'drivers/upekts.c', 'drivers/upek_proto.c' ],
|
||||
'upektc' :
|
||||
[ 'drivers/upektc.c' ],
|
||||
'upeksonly' :
|
||||
[ 'drivers/upeksonly.c' ],
|
||||
'uru4000' :
|
||||
[ 'drivers/uru4000.c' ],
|
||||
'aes1610' :
|
||||
[ 'drivers/aes1610.c' ],
|
||||
'aes1660' :
|
||||
[ 'drivers/aes1660.c' ],
|
||||
'aes2501' :
|
||||
[ 'drivers/aes2501.c' ],
|
||||
'aes2550' :
|
||||
[ 'drivers/aes2550.c' ],
|
||||
'aes2660' :
|
||||
[ 'drivers/aes2660.c' ],
|
||||
'aes3500' :
|
||||
[ 'drivers/aes3500.c' ],
|
||||
'aes4000' :
|
||||
[ 'drivers/aes4000.c' ],
|
||||
'vcom5s' :
|
||||
[ 'drivers/vcom5s.c' ],
|
||||
'vfs101' :
|
||||
[ 'drivers/vfs101.c' ],
|
||||
'vfs301' :
|
||||
[ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ],
|
||||
'vfs5011' :
|
||||
[ 'drivers/vfs5011.c' ],
|
||||
'upektc_img' :
|
||||
[ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ],
|
||||
'etes603' :
|
||||
[ 'drivers/etes603.c' ],
|
||||
'vfs0050' :
|
||||
[ 'drivers/vfs0050.c' ],
|
||||
'elan' :
|
||||
[ 'drivers/elan.c' ],
|
||||
'virtual_image' :
|
||||
[ 'drivers/virtual-image.c' ],
|
||||
'virtual_device' :
|
||||
[ 'drivers/virtual-device.c' ],
|
||||
'virtual_device_storage' :
|
||||
[ 'drivers/virtual-device-storage.c' ],
|
||||
'virtual_sdcp' :
|
||||
[ 'drivers/virtual-sdcp.c' ],
|
||||
'synaptics' :
|
||||
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
|
||||
'goodixmoc' :
|
||||
[ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ],
|
||||
}
|
||||
|
||||
helper_sources = {
|
||||
'sdcp' :
|
||||
[ 'fp-sdcp-device.c', 'fpi-sdcp-device.c' ],
|
||||
'aeslib' :
|
||||
[ 'drivers/aeslib.c' ],
|
||||
'aesx660' :
|
||||
[ 'drivers/aesx660.c' ],
|
||||
'aes3k' :
|
||||
[ 'drivers/aes3k.c' ],
|
||||
'virtual' :
|
||||
[ 'drivers/virtual-device-listener.c' ],
|
||||
}
|
||||
|
||||
driver_helpers = {
|
||||
'aes1610' : [ 'aeslib' ],
|
||||
'aes1660' : [ 'aeslib', 'aesx660' ],
|
||||
'aes2501' : [ 'aeslib' ],
|
||||
'aes2550' : [ 'aeslib' ],
|
||||
'aes2660' : [ 'aeslib', 'aesx660' ],
|
||||
'aes3500' : [ 'aeslib', 'aes3k' ],
|
||||
'aes4000' : [ 'aeslib', 'aes3k' ],
|
||||
'virtual_image' : [ 'virtual' ],
|
||||
'virtual_device' : [ 'virtual' ],
|
||||
'virtual_device_storage' : [ 'virtual' ],
|
||||
'virtual_sdcp' : [ 'sdcp' ],
|
||||
}
|
||||
|
||||
helpers = []
|
||||
foreach driver : drivers
|
||||
if driver in driver_helpers
|
||||
foreach helper : driver_helpers[driver]
|
||||
if helper not in helpers
|
||||
helpers += helper
|
||||
endif
|
||||
endforeach
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if aeslib
|
||||
drivers_sources += [ 'drivers/aeslib.c' ]
|
||||
endif
|
||||
if aesx660
|
||||
drivers_sources += ['drivers/aesx660.c' ]
|
||||
endif
|
||||
if aes3k
|
||||
drivers_sources += ['drivers/aes3k.c' ]
|
||||
endif
|
||||
drivers_sources = []
|
||||
drivers_cflags = []
|
||||
foreach driver: drivers
|
||||
drivers_sources += driver_sources[driver]
|
||||
endforeach
|
||||
foreach helper : helpers
|
||||
drivers_sources += helper_sources[helper]
|
||||
endforeach
|
||||
|
||||
other_sources = []
|
||||
optional_deps = []
|
||||
|
||||
# Resolve extra dependencies
|
||||
foreach i : helpers + drivers
|
||||
driver = i
|
||||
foreach d, helper : driver_helpers
|
||||
if i in helpers
|
||||
driver = d
|
||||
break
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if i == 'aes3k'
|
||||
imaging_dep = dependency('pixman-1', required: false)
|
||||
if not imaging_dep.found()
|
||||
error('pixman is required for @0@ and possibly others'.format(driver))
|
||||
endif
|
||||
|
||||
libfprint_conf.set10('HAVE_PIXMAN', true)
|
||||
optional_deps += imaging_dep
|
||||
elif i == 'uru4000'
|
||||
nss_dep = dependency('nss', required: false)
|
||||
if not nss_dep.found()
|
||||
error('nss is required for uru4000')
|
||||
endif
|
||||
|
||||
optional_deps += nss_dep
|
||||
elif i == 'sdcp'
|
||||
nss_dep = dependency('nss', version: '>=3.55', required: false)
|
||||
if not nss_dep.found()
|
||||
error('nss >=3.55 is required for SDCP support (@0@ and possibly others)'.format(driver))
|
||||
endif
|
||||
|
||||
optional_deps += nss_dep
|
||||
else
|
||||
deps = []
|
||||
continue
|
||||
endif
|
||||
|
||||
endforeach
|
||||
|
||||
fp_enums = gnome.mkenums_simple('fp-enums',
|
||||
sources: libfprint_public_headers,
|
||||
@@ -192,6 +236,28 @@ enums_dep = declare_dependency(
|
||||
sources: [ fp_enums_h, fpi_enums_h ]
|
||||
)
|
||||
|
||||
# Export the drivers' types to the core code
|
||||
drivers_type_list = []
|
||||
drivers_type_func = []
|
||||
drivers_type_list += '#include <glib-object.h>'
|
||||
drivers_type_list += '#include "fpi-context.h"'
|
||||
drivers_type_list += ''
|
||||
drivers_type_func += 'GArray *'
|
||||
drivers_type_func += 'fpi_get_driver_types (void)'
|
||||
drivers_type_func += '{'
|
||||
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
|
||||
drivers_type_func += ' GType t;'
|
||||
drivers_type_func += ''
|
||||
foreach driver: supported_drivers
|
||||
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
|
||||
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
|
||||
drivers_type_func += ' g_array_append_val (drivers, t);'
|
||||
drivers_type_func += ''
|
||||
endforeach
|
||||
drivers_type_list += ''
|
||||
drivers_type_func += ' return drivers;'
|
||||
drivers_type_func += '}'
|
||||
|
||||
drivers_sources += configure_file(input: 'empty_file',
|
||||
output: 'fpi-drivers.c',
|
||||
capture: true,
|
||||
@@ -206,10 +272,8 @@ deps = [
|
||||
glib_dep,
|
||||
gobject_dep,
|
||||
gusb_dep,
|
||||
imaging_dep,
|
||||
mathlib_dep,
|
||||
nss_dep,
|
||||
]
|
||||
] + optional_deps
|
||||
|
||||
# These are empty and only exist so that the include directories are created
|
||||
# in the build tree. This silences a build time warning.
|
||||
@@ -228,6 +292,8 @@ libnbis = static_library('nbis',
|
||||
'-Wno-error=redundant-decls',
|
||||
'-Wno-redundant-decls',
|
||||
'-Wno-discarded-qualifiers',
|
||||
'-Wno-array-bounds',
|
||||
'-Wno-array-parameter',
|
||||
]),
|
||||
install: false)
|
||||
|
||||
@@ -250,11 +316,10 @@ libfprint_drivers = static_library('fprint-drivers',
|
||||
mapfile = files('libfprint.ver')
|
||||
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
|
||||
|
||||
libfprint = library(versioned_libname.split('lib')[1],
|
||||
libfprint = shared_library(versioned_libname.split('lib')[1],
|
||||
sources: [
|
||||
fp_enums,
|
||||
libfprint_sources,
|
||||
other_sources,
|
||||
],
|
||||
soversion: soversion,
|
||||
version: libversion,
|
||||
@@ -287,20 +352,30 @@ libfprint_private_dep = declare_dependency(
|
||||
]
|
||||
)
|
||||
|
||||
udev_rules = executable('fprint-list-udev-rules',
|
||||
'fprint-list-udev-rules.c',
|
||||
udev_hwdb = executable('fprint-list-udev-hwdb',
|
||||
'fprint-list-udev-hwdb.c',
|
||||
dependencies: libfprint_private_dep,
|
||||
link_with: libfprint_drivers,
|
||||
install: false)
|
||||
|
||||
if get_option('udev_rules')
|
||||
custom_target('udev-rules',
|
||||
output: '60-@0@-autosuspend.rules'.format(versioned_libname),
|
||||
capture: true,
|
||||
command: [ udev_rules ],
|
||||
install: true,
|
||||
install_dir: udev_rules_dir)
|
||||
endif
|
||||
udev_hwdb_generator = custom_target('udev-hwdb',
|
||||
output: 'autosuspend.hwdb',
|
||||
depend_files: drivers_sources,
|
||||
capture: true,
|
||||
command: [ udev_hwdb ],
|
||||
install: false,
|
||||
)
|
||||
|
||||
custom_target('sync-udev-hwdb',
|
||||
depends: udev_hwdb_generator,
|
||||
output: 'sync-udev-hwdb',
|
||||
install: false,
|
||||
command: [
|
||||
'cp', '-v',
|
||||
udev_hwdb_generator.full_path(),
|
||||
meson.source_root() / 'data'
|
||||
]
|
||||
)
|
||||
|
||||
supported_devices = executable('fprint-list-supported-devices',
|
||||
'fprint-list-supported-devices.c',
|
||||
|
||||
89
meson.build
89
meson.build
@@ -1,5 +1,5 @@
|
||||
project('libfprint', [ 'c', 'cpp' ],
|
||||
version: '1.90.1',
|
||||
version: '1.90.7',
|
||||
license: 'LGPLv2.1+',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
@@ -88,7 +88,12 @@ cairo_dep = dependency('cairo', required: false)
|
||||
|
||||
# Drivers
|
||||
drivers = get_option('drivers').split(',')
|
||||
virtual_drivers = [ 'virtual_image' ]
|
||||
virtual_drivers = [
|
||||
'virtual_image',
|
||||
'virtual_device',
|
||||
'virtual_device_storage',
|
||||
'virtual_sdcp',
|
||||
]
|
||||
default_drivers = [
|
||||
'upektc_img',
|
||||
'vfs5011',
|
||||
@@ -110,6 +115,14 @@ default_drivers = [
|
||||
'upektc',
|
||||
'upeksonly',
|
||||
'upekts',
|
||||
'goodixmoc',
|
||||
]
|
||||
|
||||
# FIXME: All the drivers should be fixed by adjusting the byte order.
|
||||
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
|
||||
endian_independent_drivers = virtual_drivers + [
|
||||
'aes3500',
|
||||
'synaptics',
|
||||
]
|
||||
|
||||
all_drivers = default_drivers + virtual_drivers
|
||||
@@ -126,60 +139,43 @@ if drivers.length() == 0 or drivers[0] == ''
|
||||
error('Cannot build libfprint without drivers, please specify a valid value for the drivers option')
|
||||
endif
|
||||
|
||||
nss_dep = dependency('', required: false)
|
||||
imaging_dep = dependency('', required: false)
|
||||
libfprint_conf.set10('HAVE_PIXMAN', false)
|
||||
foreach driver: drivers
|
||||
if driver == 'uru4000'
|
||||
nss_dep = dependency('nss', required: false)
|
||||
if not nss_dep.found()
|
||||
error('NSS is required for the URU4000/URU4500 driver')
|
||||
endif
|
||||
endif
|
||||
if driver == 'aes3500' or driver == 'aes4000'
|
||||
imaging_dep = dependency('pixman-1', required: false)
|
||||
if not imaging_dep.found()
|
||||
error('pixman is required for imaging support')
|
||||
if drivers == all_drivers or drivers == default_drivers
|
||||
default_drivers_are_enabled = true
|
||||
else
|
||||
default_drivers_are_enabled = true
|
||||
foreach driver: default_drivers
|
||||
if driver not in drivers
|
||||
default_drivers_are_enabled = false
|
||||
break
|
||||
endif
|
||||
endforeach
|
||||
endif
|
||||
|
||||
libfprint_conf.set10('HAVE_PIXMAN', true)
|
||||
endif
|
||||
if not all_drivers.contains(driver)
|
||||
error('Invalid driver \'' + driver + '\'')
|
||||
supported_drivers = []
|
||||
foreach driver: drivers
|
||||
if build_machine.endian() == 'little' or driver in endian_independent_drivers
|
||||
supported_drivers += driver
|
||||
else
|
||||
warning('Driver @0@ is not supported by big endian cpu @1@. Please, fix it!'.format(
|
||||
driver, build_machine.cpu()))
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# Export the drivers' types to the core code
|
||||
drivers_type_list = []
|
||||
drivers_type_func = []
|
||||
drivers_type_list += '#include <glib-object.h>'
|
||||
drivers_type_list += '#include "fpi-context.h"'
|
||||
drivers_type_list += ''
|
||||
drivers_type_func += 'GArray *'
|
||||
drivers_type_func += 'fpi_get_driver_types (void)'
|
||||
drivers_type_func += '{'
|
||||
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
|
||||
drivers_type_func += ' GType t;'
|
||||
drivers_type_func += ''
|
||||
foreach driver: drivers
|
||||
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
|
||||
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
|
||||
drivers_type_func += ' g_array_append_val (drivers, t);'
|
||||
drivers_type_func += ''
|
||||
endforeach
|
||||
drivers_type_list += ''
|
||||
drivers_type_func += ' return drivers;'
|
||||
drivers_type_func += '}'
|
||||
if default_drivers_are_enabled and supported_drivers != drivers
|
||||
default_drivers_are_enabled = false
|
||||
endif
|
||||
|
||||
root_inc = include_directories('.')
|
||||
|
||||
if get_option('udev_rules')
|
||||
udev_rules_dir = get_option('udev_rules_dir')
|
||||
udev_hwdb_dir = get_option('udev_hwdb_dir')
|
||||
|
||||
if udev_rules_dir == 'auto'
|
||||
if udev_hwdb_dir == 'auto'
|
||||
udev_dep = dependency('udev')
|
||||
udev_rules_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/rules.d'
|
||||
udev_hwdb_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/hwdb.d'
|
||||
endif
|
||||
else
|
||||
udev_hwdb_dir = false
|
||||
endif
|
||||
|
||||
if get_option('gtk-examples')
|
||||
@@ -191,9 +187,11 @@ if get_option('gtk-examples')
|
||||
endif
|
||||
endif
|
||||
|
||||
# Some dependency resolving happens inside here
|
||||
subdir('libfprint')
|
||||
|
||||
configure_file(output: 'config.h', configuration: libfprint_conf)
|
||||
|
||||
subdir('libfprint')
|
||||
subdir('examples')
|
||||
if get_option('doc')
|
||||
gnome = import('gnome')
|
||||
@@ -203,6 +201,7 @@ if get_option('gtk-examples')
|
||||
subdir('demo')
|
||||
endif
|
||||
|
||||
subdir('data')
|
||||
subdir('tests')
|
||||
|
||||
pkgconfig = import('pkgconfig')
|
||||
|
||||
@@ -10,8 +10,8 @@ option('udev_rules',
|
||||
description: 'Whether to create a udev rules file',
|
||||
type: 'boolean',
|
||||
value: true)
|
||||
option('udev_rules_dir',
|
||||
description: 'Installation path for udev rules',
|
||||
option('udev_hwdb_dir',
|
||||
description: 'Installation path for udev hwdb',
|
||||
type: 'string',
|
||||
value: 'auto')
|
||||
option('gtk-examples',
|
||||
@@ -22,3 +22,8 @@ option('doc',
|
||||
description: 'Whether to build the API documentation',
|
||||
type: 'boolean',
|
||||
value: true)
|
||||
|
||||
option('sdcp_virt_binary',
|
||||
description: 'Path to virtual SDCP test binary, please refer to CI for more details.',
|
||||
type: 'string',
|
||||
value: '')
|
||||
|
||||
@@ -12,8 +12,11 @@ case "$1" in
|
||||
;;
|
||||
esac
|
||||
|
||||
ARGS=4
|
||||
JOBS=4
|
||||
|
||||
pushd "$SRCROOT"
|
||||
uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/`
|
||||
git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/ | xargs -n$ARGS -P $JOBS uncrustify -c "$CFG" $OPTS
|
||||
RES=$?
|
||||
popd
|
||||
exit $RES
|
||||
exit $RES
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
To create a new umockdev test, you should:
|
||||
|
||||
1. Decide on what to test, the easiest case is just using the existing
|
||||
capture test case.
|
||||
2. Find the USB device you are testing with lsusb, e.g.:
|
||||
Bus 001 Device 005: ID 138a:0090 Validity Sensors, Inc. VFS7500 Touch Fingerprint Sensor
|
||||
This means we need to record USB device /dev/bus/usb/001/005
|
||||
3. Run "umockdev-record /dev/bus/usb/001/005 >device"
|
||||
This records the information about device, it should be placed into test/DRIVER/device
|
||||
4. Run the test, for a capture test this would be:
|
||||
umockdev-record -i /dev/bus/usb/001/005=capture.ioctl -- ./capture.py capture.png
|
||||
This will create a capture.ioctl and capture.png file.
|
||||
Please set the FP_DEVICE_EMULATION=1 environment variable. You may need
|
||||
to adjust the driver to adapt to the emulated environment (mainly if it
|
||||
uses random numbers, see synaptics.c for an example).
|
||||
5. Place all files into the driver subdirectory test/DRIVER,
|
||||
i.e. device, capture.ioctl, capture.png
|
||||
6. Add glue to meson.build
|
||||
7. Test whether everything works as expected
|
||||
|
||||
Please note, there is no need to use a real finger print in this case. If
|
||||
you would like to avoid submitting your own fingerprint then please just
|
||||
use e.g. the side of your finger, arm, or anything else that will produce
|
||||
an image with the device.
|
||||
|
||||
|
||||
Note that umockdev-record groups URBs aggressively. In most cases, manual
|
||||
intervention is unfortunately required. In most cases, drivers do a chain
|
||||
of commands like e.g. A then B each with a different reply. Umockdev will
|
||||
create a file like:
|
||||
|
||||
A
|
||||
reply 1
|
||||
reply 2
|
||||
B
|
||||
reply 1
|
||||
reply 2
|
||||
|
||||
which then needs to be re-ordered to be:
|
||||
|
||||
A
|
||||
reply 1
|
||||
B
|
||||
reply 1
|
||||
A
|
||||
reply 2
|
||||
B
|
||||
reply 2
|
||||
|
||||
Other changes may be needed to get everything working. For example the elan
|
||||
driver relies on a timeout that is not reported correctly. In this case the
|
||||
driver works around it by interpreting the protocol error differently in
|
||||
the virtual environment.
|
||||
99
tests/README.md
Normal file
99
tests/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
`umockdev` Tests
|
||||
================
|
||||
`umockdev` tests use fingerprint devices mocked by [`umockdev`
|
||||
toolchain][umockdev].
|
||||
|
||||
This document describes how to create a 'capture' test: a test that
|
||||
captures a picture of a fingerprint from the device (mocked by
|
||||
`umockdev`) and compares it with the standard one.
|
||||
|
||||
Other kinds of `umockdev` tests could be created in a similar manner.
|
||||
|
||||
|
||||
'Capture' Test Creation
|
||||
-----------------------
|
||||
A new 'capture' test is created by means of `capture.py` script:
|
||||
|
||||
1. Create (if needed) a directory for the driver under `tests`
|
||||
directory:
|
||||
|
||||
`mkdir DRIVER`
|
||||
|
||||
2. Prepare your execution environment.
|
||||
|
||||
In the next step a working and up to date libfprint is needed. This can be
|
||||
achieved by installing it into your system. Alternatively, you can set
|
||||
the following environment variables to run a local build:
|
||||
- `export LD_PRELOAD=<meson-build-dir>/libfprint/libfprint-2.so`
|
||||
- `export GI_TYPELIB_PATH=<meson-build-dir>/libfprint`
|
||||
|
||||
Also, sometimes the driver must be adapted to the emulated environment
|
||||
(mainly if it uses random numbers, see `synaptics.c` for an example).
|
||||
Set the following environment variable to enable this adaptation:
|
||||
- `export FP_DEVICE_EMULATION=1`
|
||||
|
||||
Run the next steps in the same terminal.
|
||||
|
||||
3. Find the real USB fingerprint device with `lsusb`, e.g.:
|
||||
|
||||
`Bus 001 Device 005: ID 138a:0090 Validity Sensors, Inc. VFS7500 Touch Fingerprint Sensor`
|
||||
|
||||
The following USB device is used in the example above:
|
||||
`/dev/bus/usb/001/005`.
|
||||
|
||||
For the following commands, it is assumed that the user that's
|
||||
running the commands has full access to the device node, whether
|
||||
by running the commands as `root`, or changing the permissions for
|
||||
that device node.
|
||||
|
||||
4. Record information about this device:
|
||||
|
||||
`umockdev-record /dev/bus/usb/001/005 > DRIVER/device`
|
||||
|
||||
5. Record interaction of `capture.py` (or other test) with the device:
|
||||
|
||||
`umockdev-record -i /dev/bus/usb/001/005=DRIVER/capture.ioctl -- python3 ./capture.py DRIVER/capture.png`
|
||||
|
||||
Files `capture.ioctl` and `capture.png` will be created as the
|
||||
result of this command.
|
||||
|
||||
6. Add driver's name to `drivers_tests` in the `meson.build`.
|
||||
7. Check whether everything works as expected.
|
||||
|
||||
**Note.** To avoid submitting a real fingerprint, the side of finger,
|
||||
arm, or anything else producing an image with the device can be used.
|
||||
|
||||
|
||||
Possible Issues
|
||||
---------------
|
||||
`umockdev-record` aggressively groups URBs. In most cases, manual
|
||||
intervention is unfortunately required. Often, drivers do a chain of
|
||||
commands like: A then B each with a different reply. However,
|
||||
`umockdev-record` could create a file like this:
|
||||
|
||||
A
|
||||
reply 1
|
||||
reply 2
|
||||
B
|
||||
reply 1
|
||||
reply 2
|
||||
|
||||
In that case, records must be re-ordered:
|
||||
|
||||
A
|
||||
reply 1
|
||||
B
|
||||
reply 1
|
||||
A
|
||||
reply 2
|
||||
B
|
||||
reply 2
|
||||
|
||||
Other changes may be needed to get everything working. For example the
|
||||
`elan` driver relies on a timeout that is not reported correctly. In
|
||||
this case the driver works around it by interpreting the protocol
|
||||
error differently in the virtual environment (by means of
|
||||
`FP_DEVICE_EMULATION` environment variable).
|
||||
|
||||
|
||||
[umockdev]: https://github.com/martinpitt/umockdev
|
||||
13
tests/aes3500/capture.ioctl
Normal file
13
tests/aes3500/capture.ioctl
Normal file
File diff suppressed because one or more lines are too long
BIN
tests/aes3500/capture.png
Normal file
BIN
tests/aes3500/capture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
561
tests/aes3500/device
Normal file
561
tests/aes3500/device
Normal file
@@ -0,0 +1,561 @@
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1/3-1.1/3-1.1.3
|
||||
N: bus/usb/003/004=12011001FFFFFF08FF0831570000000100010902200001010080320904000002FFFFFF000705810240000007050202080000
|
||||
E: BUSNUM=003
|
||||
E: DEVNAME=/dev/bus/usb/003/004
|
||||
E: DEVNUM=004
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_BUS=usb
|
||||
E: ID_MODEL=Fingerprint_Sensor
|
||||
E: ID_MODEL_ENC=Fingerprint\x20Sensor
|
||||
E: ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor
|
||||
E: ID_MODEL_ID=5731
|
||||
E: ID_REVISION=0000
|
||||
E: ID_SERIAL=08ff_Fingerprint_Sensor
|
||||
E: ID_USB_INTERFACES=:ffffff:
|
||||
E: ID_VENDOR=08ff
|
||||
E: ID_VENDOR_ENC=08ff
|
||||
E: ID_VENDOR_FROM_DATABASE=AuthenTec, Inc.
|
||||
E: ID_VENDOR_ID=08ff
|
||||
E: LIBFPRINT_DRIVER=AuthenTec AES3500
|
||||
E: MAJOR=189
|
||||
E: MINOR=259
|
||||
E: PRODUCT=8ff/5731/0
|
||||
E: SUBSYSTEM=usb
|
||||
E: TYPE=255/255/255
|
||||
A: authorized=1
|
||||
A: avoid_reset_quirk=0
|
||||
A: bConfigurationValue=1
|
||||
A: bDeviceClass=ff
|
||||
A: bDeviceProtocol=ff
|
||||
A: bDeviceSubClass=ff
|
||||
A: bMaxPacketSize0=8
|
||||
A: bMaxPower=100mA
|
||||
A: bNumConfigurations=1
|
||||
A: bNumInterfaces= 1
|
||||
A: bcdDevice=0000
|
||||
A: bmAttributes=80
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12011001FFFFFF08FF0831570000000100010902200001010080320904000002FFFFFF000705810240000007050202080000
|
||||
A: dev=189:259
|
||||
A: devnum=4\n
|
||||
A: devpath=1.1.3
|
||||
L: driver=../../../../../../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=5731
|
||||
A: idVendor=08ff
|
||||
A: ltm_capable=no
|
||||
A: maxchild=0
|
||||
L: port=../3-1.1:1.0/3-1.1-port3
|
||||
A: power/active_duration=3601332
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=2
|
||||
A: power/autosuspend_delay_ms=2000
|
||||
A: power/connected_duration=3601332
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/persist=1
|
||||
A: power/runtime_active_kids=0
|
||||
A: power/runtime_active_time=3601128
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=0
|
||||
A: product=Fingerprint Sensor
|
||||
A: quirks=0x0
|
||||
A: removable=removable
|
||||
A: speed=12
|
||||
A: urbnum=82
|
||||
A: version= 1.10
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1/3-1.1
|
||||
N: bus/usb/003/003=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
|
||||
E: BUSNUM=003
|
||||
E: DEVNAME=/dev/bus/usb/003/003
|
||||
E: DEVNUM=003
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_39_00_0-usb-0_1_1
|
||||
E: ID_MODEL=USB2.0_Hub
|
||||
E: ID_MODEL_ENC=USB2.0\x20Hub\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
|
||||
E: ID_MODEL_ID=0006
|
||||
E: ID_PATH=pci-0000:39:00.0-usb-0:1.1
|
||||
E: ID_PATH_TAG=pci-0000_39_00_0-usb-0_1_1
|
||||
E: ID_REVISION=9100
|
||||
E: ID_SERIAL=VIA_Labs__Inc._USB2.0_Hub
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_VENDOR=VIA_Labs__Inc.
|
||||
E: ID_VENDOR_ENC=VIA\x20Labs\x2c\x20Inc.\x20\x20\x20\x20\x20\x20\x20\x20\x20
|
||||
E: ID_VENDOR_ID=2230
|
||||
E: MAJOR=189
|
||||
E: MINOR=258
|
||||
E: PRODUCT=2230/6/9100
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=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=9100
|
||||
A: bmAttributes=e0
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
|
||||
A: dev=189:258
|
||||
A: devnum=3\n
|
||||
A: devpath=1.1
|
||||
L: driver=../../../../../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0006
|
||||
A: idVendor=2230
|
||||
A: ltm_capable=no
|
||||
A: manufacturer=VIA Labs, Inc.
|
||||
A: maxchild=4
|
||||
L: port=../3-1:1.0/3-1-port1
|
||||
A: power/active_duration=3601776
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=0
|
||||
A: power/autosuspend_delay_ms=0
|
||||
A: power/connected_duration=3601776
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/runtime_active_kids=2
|
||||
A: power/runtime_active_time=3601572
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=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=USB2.0 Hub
|
||||
A: quirks=0x0
|
||||
A: removable=fixed
|
||||
A: speed=480
|
||||
A: urbnum=40
|
||||
A: version= 2.10
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1
|
||||
N: bus/usb/003/002=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
|
||||
E: BUSNUM=003
|
||||
E: DEVNAME=/dev/bus/usb/003/002
|
||||
E: DEVNUM=002
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_39_00_0-usb-0_1
|
||||
E: ID_MODEL=USB2.0_Hub
|
||||
E: ID_MODEL_ENC=USB2.0\x20Hub\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
|
||||
E: ID_MODEL_ID=0006
|
||||
E: ID_PATH=pci-0000:39:00.0-usb-0:1
|
||||
E: ID_PATH_TAG=pci-0000_39_00_0-usb-0_1
|
||||
E: ID_REVISION=9100
|
||||
E: ID_SERIAL=VIA_Labs__Inc._USB2.0_Hub
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_VENDOR=VIA_Labs__Inc.
|
||||
E: ID_VENDOR_ENC=VIA\x20Labs\x2c\x20Inc.\x20\x20\x20\x20\x20\x20\x20\x20\x20
|
||||
E: ID_VENDOR_ID=2230
|
||||
E: MAJOR=189
|
||||
E: MINOR=257
|
||||
E: PRODUCT=2230/6/9100
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=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=9100
|
||||
A: bmAttributes=e0
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12011002090001403022060000910102000109021900010100E0000904000001090000000705810301000C
|
||||
A: dev=189:257
|
||||
A: devnum=2\n
|
||||
A: devpath=1
|
||||
L: driver=../../../../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0006
|
||||
A: idVendor=2230
|
||||
A: ltm_capable=no
|
||||
A: manufacturer=VIA Labs, Inc.
|
||||
A: maxchild=4
|
||||
L: port=../3-0:1.0/usb3-port1
|
||||
A: power/active_duration=3602292
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=0
|
||||
A: power/autosuspend_delay_ms=0
|
||||
A: power/connected_duration=3602292
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/runtime_active_kids=1
|
||||
A: power/runtime_active_time=3602016
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=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=USB2.0 Hub
|
||||
A: quirks=0x0
|
||||
A: removable=removable
|
||||
A: speed=480
|
||||
A: urbnum=31
|
||||
A: version= 2.10
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3
|
||||
N: bus/usb/003/001=12010002090001406B1D020015040302010109021900010100E0000904000001090000000705810304000C
|
||||
E: BUSNUM=003
|
||||
E: DEVNAME=/dev/bus/usb/003/001
|
||||
E: DEVNUM=001
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_39_00_0
|
||||
E: ID_MODEL=xHCI_Host_Controller
|
||||
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_MODEL_FROM_DATABASE=2.0 root hub
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_PATH=pci-0000:39:00.0
|
||||
E: ID_PATH_TAG=pci-0000_39_00_0
|
||||
E: ID_REVISION=0415
|
||||
E: ID_SERIAL=Linux_4.15.0-117-generic_xhci-hcd_xHCI_Host_Controller_0000:39:00.0
|
||||
E: ID_SERIAL_SHORT=0000:39:00.0
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_VENDOR=Linux_4.15.0-117-generic_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x204.15.0-117-generic\x20xhci-hcd
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: MAJOR=189
|
||||
E: MINOR=256
|
||||
E: PRODUCT=1d6b/2/415
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=9/0/1
|
||||
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=0415
|
||||
A: bmAttributes=e0
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020015040302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:256
|
||||
A: devnum=1\n
|
||||
A: devpath=0
|
||||
L: driver=../../../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0002
|
||||
A: idVendor=1d6b
|
||||
A: interface_authorized_default=1
|
||||
A: ltm_capable=no
|
||||
A: manufacturer=Linux 4.15.0-117-generic xhci-hcd
|
||||
A: maxchild=2
|
||||
A: power/active_duration=3602700
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=0
|
||||
A: power/autosuspend_delay_ms=0
|
||||
A: power/connected_duration=3602700
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/runtime_active_kids=1
|
||||
A: power/runtime_active_time=3602700
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=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: serial=0000:39:00.0
|
||||
A: speed=480
|
||||
A: urbnum=24
|
||||
A: version= 2.00
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0
|
||||
E: DRIVER=xhci_hcd
|
||||
E: ID_MODEL_FROM_DATABASE=DSL6340 USB 3.1 Controller [Alpine Ridge]
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d000015B5sv00002222sd00001111bc0Csc03i30
|
||||
E: PCI_CLASS=C0330
|
||||
E: PCI_ID=8086:15B5
|
||||
E: PCI_SLOT_NAME=0000:39:00.0
|
||||
E: PCI_SUBSYS_ID=2222:1111
|
||||
E: SUBSYSTEM=pci
|
||||
A: broken_parity_status=0
|
||||
A: class=0x0c0330
|
||||
H: config=8680B515060410000030030C200000000000F0D9000000000000000000000000000000000000000000000000222211110000000080000000000000000B010000
|
||||
A: consistent_dma_mask_bits=64
|
||||
A: current_link_speed=2.5 GT/s
|
||||
A: current_link_width=4
|
||||
A: d3cold_allowed=1
|
||||
A: dbc=disabled
|
||||
A: device=0x15b5
|
||||
A: dma_mask_bits=64
|
||||
L: driver=../../../../../../bus/pci/drivers/xhci_hcd
|
||||
A: driver_override=(null)
|
||||
A: enable=1
|
||||
L: iommu=../../../../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../../../../kernel/iommu_groups/17
|
||||
A: irq=141
|
||||
A: local_cpulist=0-3
|
||||
A: local_cpus=f
|
||||
A: max_link_speed=2.5 GT/s
|
||||
A: max_link_width=4
|
||||
A: modalias=pci:v00008086d000015B5sv00002222sd00001111bc0Csc03i30
|
||||
A: msi_bus=1
|
||||
A: msi_irqs/141=msi
|
||||
A: numa_node=-1
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 3 6 2048 3\nbuffer-512 12 16 512 2\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 15 15 2112 15\nxHCI ring segments 44 46 4096 46\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 3 32 128 1\nbuffer-32 0 0 32 0
|
||||
A: power/async=enabled
|
||||
A: power/control=on
|
||||
A: power/runtime_active_kids=2
|
||||
A: power/runtime_active_time=3602712
|
||||
A: power/runtime_enabled=forbidden
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=1
|
||||
A: power/wakeup=enabled
|
||||
A: power/wakeup_abort_count=0
|
||||
A: power/wakeup_active=0
|
||||
A: power/wakeup_active_count=0
|
||||
A: power/wakeup_count=0
|
||||
A: power/wakeup_expire_count=0
|
||||
A: power/wakeup_last_time_ms=224549241
|
||||
A: power/wakeup_max_time_ms=0
|
||||
A: power/wakeup_total_time_ms=0
|
||||
A: resource=0x00000000d9f00000 0x00000000d9f0ffff 0x0000000000040200\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=0x00
|
||||
A: subsystem_device=0x1111
|
||||
A: subsystem_vendor=0x2222
|
||||
A: vendor=0x8086
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0
|
||||
E: DRIVER=pcieport
|
||||
E: ID_MODEL_FROM_DATABASE=DSL6340 Thunderbolt 3 Bridge [Alpine Ridge 2C 2015]
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Bridge
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=Normal decode
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00001576sv00002222sd00001111bc06sc04i00
|
||||
E: PCI_CLASS=60400
|
||||
E: PCI_ID=8086:1576
|
||||
E: PCI_SLOT_NAME=0000:02:02.0
|
||||
E: PCI_SUBSYS_ID=2222:1111
|
||||
E: SUBSYSTEM=pci
|
||||
A: broken_parity_status=0
|
||||
A: class=0x060400
|
||||
H: config=86807615060410000000040620000100000000000000000002393900F1010000F0D9F0D9F1FF010000000000000000000000000080000000000000000B011000
|
||||
A: consistent_dma_mask_bits=32
|
||||
A: current_link_speed=2.5 GT/s
|
||||
A: current_link_width=4
|
||||
A: d3cold_allowed=1
|
||||
A: device=0x1576
|
||||
A: dma_mask_bits=32
|
||||
L: driver=../../../../../bus/pci/drivers/pcieport
|
||||
A: driver_override=(null)
|
||||
A: enable=1
|
||||
L: iommu=../../../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../../../kernel/iommu_groups/17
|
||||
A: irq=140
|
||||
A: local_cpulist=0-3
|
||||
A: local_cpus=f
|
||||
A: max_link_speed=2.5 GT/s
|
||||
A: max_link_width=4
|
||||
A: modalias=pci:v00008086d00001576sv00002222sd00001111bc06sc04i00
|
||||
A: msi_bus=1
|
||||
A: msi_irqs/140=msi
|
||||
A: numa_node=-1
|
||||
A: power/async=enabled
|
||||
A: power/clk_ctl=0
|
||||
A: power/control=on
|
||||
A: power/link_state=0
|
||||
A: power/runtime_active_kids=1
|
||||
A: power/runtime_active_time=3602728
|
||||
A: power/runtime_enabled=forbidden
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=2
|
||||
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: resource=0x0000000000000000 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\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x00000000d9f00000 0x00000000d9ffffff 0x0000000000000200\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000
|
||||
A: revision=0x00
|
||||
A: secondary_bus_number=57
|
||||
A: subordinate_bus_number=57
|
||||
A: subsystem_device=0x1111
|
||||
A: subsystem_vendor=0x2222
|
||||
A: vendor=0x8086
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0/0000:01:00.0
|
||||
E: DRIVER=pcieport
|
||||
E: ID_MODEL_FROM_DATABASE=DSL6340 Thunderbolt 3 Bridge [Alpine Ridge 2C 2015]
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Bridge
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=Normal decode
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00001576sv00002222sd00001111bc06sc04i00
|
||||
E: PCI_CLASS=60400
|
||||
E: PCI_ID=8086:1576
|
||||
E: PCI_SLOT_NAME=0000:01:00.0
|
||||
E: PCI_SUBSYS_ID=2222:1111
|
||||
E: SUBSYSTEM=pci
|
||||
A: broken_parity_status=0
|
||||
A: class=0x060400
|
||||
H: config=86807615060410000000040620000100000000000000000001023900F101000000C400DA01A0F1C100000000000000000000000080000000000000000B011000
|
||||
A: consistent_dma_mask_bits=32
|
||||
A: current_link_speed=8 GT/s
|
||||
A: current_link_width=2
|
||||
A: d3cold_allowed=1
|
||||
A: device=0x1576
|
||||
A: dma_mask_bits=32
|
||||
L: driver=../../../../bus/pci/drivers/pcieport
|
||||
A: driver_override=(null)
|
||||
A: enable=1
|
||||
L: iommu=../../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../../kernel/iommu_groups/14
|
||||
A: irq=137
|
||||
A: local_cpulist=0-3
|
||||
A: local_cpus=f
|
||||
A: max_link_speed=8 GT/s
|
||||
A: max_link_width=4
|
||||
A: modalias=pci:v00008086d00001576sv00002222sd00001111bc06sc04i00
|
||||
A: msi_bus=1
|
||||
A: msi_irqs/137=msi
|
||||
A: numa_node=-1
|
||||
A: power/async=enabled
|
||||
A: power/control=on
|
||||
A: power/runtime_active_kids=2
|
||||
A: power/runtime_active_time=3602740
|
||||
A: power/runtime_enabled=forbidden
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=2
|
||||
A: power/wakeup=enabled
|
||||
A: power/wakeup_abort_count=0
|
||||
A: power/wakeup_active=0
|
||||
A: power/wakeup_active_count=0
|
||||
A: power/wakeup_count=0
|
||||
A: power/wakeup_expire_count=0
|
||||
A: power/wakeup_last_time_ms=224549237
|
||||
A: power/wakeup_max_time_ms=0
|
||||
A: power/wakeup_total_time_ms=0
|
||||
A: resource=0x0000000000000000 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\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x00000000c4000000 0x00000000da0fffff 0x0000000000000200\n0x00000000a0000000 0x00000000c1ffffff 0x0000000000102201\n0x0000000000000000 0x0000000000000000 0x0000000000000000
|
||||
A: revision=0x00
|
||||
A: secondary_bus_number=2
|
||||
A: subordinate_bus_number=57
|
||||
A: subsystem_device=0x1111
|
||||
A: subsystem_vendor=0x2222
|
||||
A: vendor=0x8086
|
||||
|
||||
P: /devices/pci0000:00/0000:00:1c.0
|
||||
E: DRIVER=pcieport
|
||||
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Bridge
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=Normal decode
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00009D10sv00001028sd0000075Bbc06sc04i00
|
||||
E: PCI_CLASS=60400
|
||||
E: PCI_ID=8086:9D10
|
||||
E: PCI_SLOT_NAME=0000:00:1c.0
|
||||
E: PCI_SUBSYS_ID=1028:075B
|
||||
E: SUBSYSTEM=pci
|
||||
A: broken_parity_status=0
|
||||
A: class=0x060400
|
||||
H: config=8680109D07041000F1000406000081000000000000000000000139002020002000C400DA01A0F1C100000000000000000000000040000000000000000B011000
|
||||
A: consistent_dma_mask_bits=32
|
||||
A: current_link_speed=8 GT/s
|
||||
A: current_link_width=2
|
||||
A: d3cold_allowed=1
|
||||
A: device=0x9d10
|
||||
A: dma_mask_bits=32
|
||||
L: driver=../../../bus/pci/drivers/pcieport
|
||||
A: driver_override=(null)
|
||||
A: enable=1
|
||||
L: iommu=../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../kernel/iommu_groups/6
|
||||
A: irq=123
|
||||
A: local_cpulist=0-3
|
||||
A: local_cpus=f
|
||||
A: max_link_speed=8 GT/s
|
||||
A: max_link_width=2
|
||||
A: modalias=pci:v00008086d00009D10sv00001028sd0000075Bbc06sc04i00
|
||||
A: msi_bus=1
|
||||
A: msi_irqs/123=msi
|
||||
A: numa_node=-1
|
||||
A: power/async=enabled
|
||||
A: power/control=on
|
||||
A: power/runtime_active_kids=1
|
||||
A: power/runtime_active_time=228151860
|
||||
A: power/runtime_enabled=forbidden
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=0
|
||||
A: power/runtime_usage=2
|
||||
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: resource=0x0000000000000000 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\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000002000 0x0000000000002fff 0x0000000000000100\n0x00000000c4000000 0x00000000da0fffff 0x0000000000000200\n0x00000000a0000000 0x00000000c1ffffff 0x0000000000102201\n0x0000000000000000 0x0000000000000000 0x0000000000000000
|
||||
A: revision=0xf1
|
||||
A: secondary_bus_number=1
|
||||
A: subordinate_bus_number=57
|
||||
A: subsystem_device=0x075b
|
||||
A: subsystem_vendor=0x1028
|
||||
A: vendor=0x8086
|
||||
|
||||
@@ -36,11 +36,11 @@ A: bNumConfigurations=1
|
||||
A: bNumInterfaces= 1
|
||||
A: bcdDevice=0140
|
||||
A: bmAttributes=80
|
||||
A: busnum=1
|
||||
A: busnum=1\n
|
||||
A: configuration=
|
||||
H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001
|
||||
A: dev=189:93
|
||||
A: devnum=94
|
||||
A: devnum=94\n
|
||||
A: devpath=4.4
|
||||
L: driver=../../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0c26
|
||||
@@ -107,11 +107,11 @@ A: bNumConfigurations=1
|
||||
A: bNumInterfaces= 1
|
||||
A: bcdDevice=5284
|
||||
A: bmAttributes=e0
|
||||
A: busnum=1
|
||||
A: busnum=1\n
|
||||
A: configuration=
|
||||
H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C
|
||||
A: dev=189:82
|
||||
A: devnum=83
|
||||
A: devnum=83\n
|
||||
A: devpath=4
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=1018
|
||||
@@ -189,11 +189,11 @@ A: bNumConfigurations=1
|
||||
A: bNumInterfaces= 1
|
||||
A: bcdDevice=0503
|
||||
A: bmAttributes=e0
|
||||
A: busnum=1
|
||||
A: busnum=1\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:0
|
||||
A: devnum=1
|
||||
A: devnum=1\n
|
||||
A: devpath=0
|
||||
L: driver=../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0002
|
||||
|
||||
217
tests/goodixmoc/custom.ioctl
Normal file
217
tests/goodixmoc/custom.ioctl
Normal file
@@ -0,0 +1,217 @@
|
||||
@DEV /dev/bus/usb/003/008
|
||||
USBDEVFS_GET_CAPABILITIES 0 FD010000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 D00000000500BA4500611A297F
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000008009D6200D00000239572F5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 D0000001850067980002FE4150500000000000303130303032343744454C4C00000000474D3138384230004746353238380000312E30342E30352E31302E3530000000000000000000000000000000000000005553420000000000564253000000000030303030303030330000000000000000000000000000000000000000000000000000000000003B5CB43C000000000000555342000000000056425300000000003030303030303033000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 140 140 0 C001000184008E71000064500F41080A1800002300000101000101010100010105050100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B737316F0558B152
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000208004BB400C001005F5A6B1C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 C00100030700D12E0014140342C8AE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00100020400BE41BBC7BACE
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000004080036C900E00101C26FC596000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E0010005080054AB00141441240D0ECF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A6000003050022DD00CA3B9C30
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000060800E01F00A60001BCF2ED17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A60000070600B64900007A6860130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000040700BA45000F41625785F3
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000080800CC3300A20001BA8679AC000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000090C00BC430054640027004D0084CD5EED0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A500000524009F60000000000000000000000000000000000000000000000000000000000000000048D9D8CB
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000A08001AE500A5000172CD1245000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A500000B050008F703C6DBFA26000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A100000605003DC200632D10DE
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000C0800679800A100014526FF87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A100000D25007F8000D7843025CC713EA1543DF81EBAAF6BE244543EB9F4BC6FA74E8F246A711CD8C3EA54665F00000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000007070007F8000F41630A457A
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00000E0800B14E00A2000151C59D69000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200000F0C00C13E003E620027005900101FD1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A0000008070012ED016450F8E6B5D9
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001008003FC000A0000187F37724000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000001107008A7500000002FCFB4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020009050009F6004270904E
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000120800E91600B00201386F43E6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002001345007788008A009C009400880008009A0099008B00080008009100850000000000000000008F00A4009B0090008F00A100A000940088009A0097008D000000000000000000BEDDBBB29400880008009A0099008B00080008009100850000000000000000008F00A4009B0090008F00A100A000940088009A0097008D
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000A07009669000F41D397DA08
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000140800946B00A200014F39330E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000150C00E41B004E640027004F00755632510000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000B0700AF50016450F9BB7550
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000016080042BD00A000016CB093E1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000170700F708000000BAA9831600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000C0500C93600FFA00844
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001808006E9100B0020144AD1E73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200194500F00F008C009C009600080086009D0097008E00810092009100850000000000000000008F00A4009A008F008E00A1009F00920087009A0096008C000000000000000000E3A1F2A19600080086009D0097008E00810092009100850000000000000000008F00A4009A008F008E00A1009F00920087009A0096008C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200000D0700807F000F41ABF4CD98
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001A0800B84700A2000195E5AEB2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200001B0C00C8370048640027005A00021B15CE0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000000E07006F9001645040B3CD87
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001C0800C53A00A000011072CE74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000001D0700708F003A000B89A2D100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002000F0500748B00E76F715E
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00001E080013EC00B00201AFEEFAB6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002001F45008D720008009900920086008800960097008D007F0091008D00850000000000000000008F00A4009B0090008F00A100A000930087009A0096008D00000000000000000069C4E77C920086008800960097008D007F0091008D00850000000000000000008F00A4009B0090008F00A100A000930087009A0096008D
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000100700B34C000F4148456C7B
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000200800DE2100A2000173C16EC1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000210C00AE510048640027005500DD002B870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001107008A750164506269C323
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000022080008F700A000015048CE2E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000230700BD420000008C0CEEF100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020012050047B8005B407F33
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000240800758A00B0020149CA3AC5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200254500EB14008D00A100900087000800980099008C00080008000800080000000000000000008F00A3009A008F008E00A0009F00930087009A0096008C0000000000000000000F8D1061900087000800980099008C00080008000800080000000000000000008F00A3009A008F008E00A0009F00930087009A0096008C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001307000EF1000F414918ACF2
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000260800A35C00A2000198828A04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000270C00D32C0057640027004E0017D2351D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001407004AB5016450DB617BF4
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002808008F7000A000012C8A93BB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002907003AC500000044F2661300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B0020015050051AE00F61A492A
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002A080059A600B002019316A779000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002002B4500C7380089009C00920008008A00990098008A007F0093008E00860000000000000000008F00A4009A008F008E00A100A000930087009A0096008D000000000000000000A0269EE8920008008A00990098008A007F0093008E00860000000000000000008F00A4009A008F008E00A100A000930087009A0096008D
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000160700CE31000F41F0101425
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002C080024DB00A20001E440D791000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200002D0C0054AB004A64002700590057B20D220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A00000170700F708016450DA3CBB7D
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00002E0800F20D00A00001C7C9777E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000002F070047B8004C4C4EAAB86E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B00200180500C03F00B4605C02
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003008007C8300B002018DEA091E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B00200314500E21D00080008000800080088009A0096008F00820092009000080000000000000000008F00A3009A008F008E00A000A000930087009A0096008C000000000000000000E0BA753D0800080088009A0096008F00820092009000080000000000000000008F00A3009A008F008E00A000A000930087009A0096008C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001907008976000F4181E62410
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000320800AA5500A200015CA2B9DF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000330C00DA25005464002700500088A694DC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001A070066990164506AA1240F
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000340800D72800A00001D935D919000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A00000350700629D0000006775A83E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 B002001B05007D8200ACAF2518
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000036080001FE00B0020166A9EDDB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 B002003745009F600008000800080008008600970095000800830090008D00880000000000000000008F00A3009A008F008E00A100A000930087009A0096008C000000000000000000F054EC42080008008600970095000800830090008D00880000000000000000008F00A3009A008F008E00A100A000930087009A0096008C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A200001C070049B6000F4138EE9CC7
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003808002DD200A200012060E44A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000390C005DA2004A640027004F005D569D1A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A000001D0700708F01645012C2339F
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003A0800FB0400A0000103E944A5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A000003B07004EB1000000D6B5F7C500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A300001E0700B649000F41F8F75650
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003C0800867900A30001B114E662000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A300003D0500629D009DDA98C4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 A400001F6A001EE1640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900E6F6BD05
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00003E080050AF00A40001795F8D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A400003F05006B940099962233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E0000020040049B6AEA0E8AB
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004008001BE400E00001D5F1C38E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000004108001BE400000000315A099D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 13 13 0 A60000210500B74800B39B168D
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000420800CD3200A60001EA5DF016000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 128 0 A60000436C00EC130001640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900FA60A49A000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00100220400FD0253E4FA3B
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000440800B04F00E0010132DE18BE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E00100450800D22D000000002B1189D3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A20000230700EF100100238AF5F029
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000460800669900A2000190EB3938000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A20000470C0016E9004C640027004D005C10F4310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A50000242400B7480000000000000000000000000000000000000000000000000000000000000000664B5D3F
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004808004AB500A50001CF21EB81000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A50000499200D22D004C642A00000000640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04D4A2B430F0D25BF63D97E631EC0F0F86A6A3DCDEF50C82BB7E8C2D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E000002504008976203A9633
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004A08009C6300E00001A9339E1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000004B08009C63004C642A9C8BFEAB000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E0010026040056A9D15D8DC2
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004C0800E11E00E00101034161C7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E001004D0800837C004C642ACB9D5A09000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 15 15 0 A2000027070044BB010023F3CB2730
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00004E080037C800A20001A1744041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A200004F0C0047B80052640027004D00E19CE96F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 44 44 0 A500002824004DB200000000000000000000000000000000000000000000000000000000000000003DB8032C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA0000500800B94600A500019C80610A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 192 0 A5000051920021DE0052642A00000000640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04D4A2B430F0D25BF63D97E631EC0F0F86A6A3DCDEF50CCC7D08E82D30303030303030302D302D30303030303030302D6E6F626F647900954F9F36EAEDD0364E04
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 12 12 0 E00000290400738C14C55D45
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA00005208006F9000E00001FA921490000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 E000005308006F900052642AB5A4CC36000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 114 114 0 A700002A6A0044BB640043010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E4650312D30303030303030302D302D30303030303030302D6E6F626F6479001CF66539
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 AA000054080012ED00A70001544A2520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 0 0
|
||||
USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2048 64 0 A7000055050052AD00C5D5FE86000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
74
tests/goodixmoc/custom.py
Executable file
74
tests/goodixmoc/custom.py
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import gi
|
||||
gi.require_version('FPrint', '2.0')
|
||||
from gi.repository import FPrint, GLib
|
||||
|
||||
ctx = GLib.main_context_default()
|
||||
|
||||
c = FPrint.Context()
|
||||
c.enumerate()
|
||||
devices = c.get_devices()
|
||||
|
||||
d = devices[0]
|
||||
del devices
|
||||
|
||||
assert d.get_driver() == "goodixmoc"
|
||||
|
||||
d.open_sync()
|
||||
|
||||
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
|
||||
174
tests/goodixmoc/device
Normal file
174
tests/goodixmoc/device
Normal file
@@ -0,0 +1,174 @@
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3/3-2
|
||||
N: bus/usb/003/008=12010002EF000040C627405800010102030109022000010103A0320904000002FF0000040705830240000007050102400000
|
||||
E: DEVNAME=/dev/bus/usb/003/008
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: PRODUCT=27c6/5840/100
|
||||
E: TYPE=239/0/0
|
||||
E: BUSNUM=003
|
||||
E: DEVNUM=008
|
||||
E: MAJOR=189
|
||||
E: MINOR=263
|
||||
E: SUBSYSTEM=usb
|
||||
E: ID_VENDOR=Goodix_Technology_Co.__Ltd.
|
||||
E: ID_VENDOR_ENC=Goodix\x20Technology\x20Co.\x2c\x20Ltd.
|
||||
E: ID_VENDOR_ID=27c6
|
||||
E: ID_MODEL=Goodix_USB2.0_MISC
|
||||
E: ID_MODEL_ENC=Goodix\x20USB2.0\x20MISC
|
||||
E: ID_MODEL_ID=5840
|
||||
E: ID_REVISION=0100
|
||||
E: ID_SERIAL=Goodix_Technology_Co.__Ltd._Goodix_USB2.0_MISC_UIDE1AD5CBA_XXXX_MOC_B0
|
||||
E: ID_SERIAL_SHORT=UIDE1AD5CBA_XXXX_MOC_B0
|
||||
E: ID_BUS=usb
|
||||
E: ID_USB_INTERFACES=:ff0000:
|
||||
E: ID_VENDOR_FROM_DATABASE=Shenzhen Goodix Technology Co.,Ltd.
|
||||
E: ID_PATH=pci-0000:00:14.0-usb-0:2
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2
|
||||
E: LIBFPRINT_DRIVER=Goodix MOC Fingerprint Sensor
|
||||
A: authorized=1
|
||||
A: avoid_reset_quirk=0
|
||||
A: bConfigurationValue=1
|
||||
A: bDeviceClass=ef
|
||||
A: bDeviceProtocol=00
|
||||
A: bDeviceSubClass=00
|
||||
A: bMaxPacketSize0=64
|
||||
A: bMaxPower=100mA
|
||||
A: bNumConfigurations=1
|
||||
A: bNumInterfaces= 1
|
||||
A: bcdDevice=0100
|
||||
A: bmAttributes=a0
|
||||
A: busnum=3\n
|
||||
A: configuration=UIDE1AD5CBA_XXXX_MOC_B0
|
||||
H: descriptors=12010002EF000040C627405800010102030109022000010103A0320904000002FF0000040705830240000007050102400000
|
||||
A: dev=189:263
|
||||
A: devnum=8\n
|
||||
A: devpath=2
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
A: idProduct=5840
|
||||
A: idVendor=27c6
|
||||
A: ltm_capable=no
|
||||
A: manufacturer=Goodix Technology Co., Ltd.
|
||||
A: maxchild=0
|
||||
L: port=../3-0:1.0/usb3-port2
|
||||
A: power/active_duration=2684
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=2
|
||||
A: power/autosuspend_delay_ms=2000
|
||||
A: power/connected_duration=54348
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/persist=1
|
||||
A: power/runtime_active_kids=0
|
||||
A: power/runtime_active_time=2518
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=51550
|
||||
A: power/runtime_usage=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=Goodix USB2.0 MISC
|
||||
A: quirks=0x0
|
||||
A: removable=removable
|
||||
A: rx_lanes=1
|
||||
A: serial=UIDE1AD5CBA_XXXX_MOC_B0
|
||||
A: speed=12
|
||||
A: tx_lanes=1
|
||||
A: urbnum=15
|
||||
A: version= 2.00
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3
|
||||
N: bus/usb/003/001=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
|
||||
E: DEVNAME=/dev/bus/usb/003/001
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: PRODUCT=1d6b/2/508
|
||||
E: TYPE=9/0/1
|
||||
E: BUSNUM=003
|
||||
E: DEVNUM=001
|
||||
E: MAJOR=189
|
||||
E: MINOR=256
|
||||
E: SUBSYSTEM=usb
|
||||
E: ID_VENDOR=Linux_5.8.0-38-generic_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x205.8.0-38-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=0508
|
||||
E: ID_SERIAL=Linux_5.8.0-38-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:
|
||||
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=0508
|
||||
A: bmAttributes=e0
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:256
|
||||
A: devnum=1\n
|
||||
A: devpath=0
|
||||
L: driver=../../../../bus/usb/drivers/usb
|
||||
A: idProduct=0002
|
||||
A: idVendor=1d6b
|
||||
A: interface_authorized_default=1
|
||||
A: ltm_capable=no
|
||||
A: manufacturer=Linux 5.8.0-38-generic xhci-hcd
|
||||
A: maxchild=4
|
||||
A: power/active_duration=2790916
|
||||
A: power/async=enabled
|
||||
A: power/autosuspend=0
|
||||
A: power/autosuspend_delay_ms=0
|
||||
A: power/connected_duration=15607832
|
||||
A: power/control=auto
|
||||
A: power/level=auto
|
||||
A: power/runtime_active_kids=1
|
||||
A: power/runtime_active_time=2790874
|
||||
A: power/runtime_enabled=enabled
|
||||
A: power/runtime_status=active
|
||||
A: power/runtime_suspended_time=12816956
|
||||
A: power/runtime_usage=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=584
|
||||
A: version= 2.00
|
||||
|
||||
|
||||
54
tests/hwdb-check-unsupported.py
Executable file
54
tests/hwdb-check-unsupported.py
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import urllib
|
||||
import urllib.request
|
||||
import re
|
||||
|
||||
error = False
|
||||
|
||||
try:
|
||||
response = urllib.request.urlopen('https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md')
|
||||
except:
|
||||
print("Could not download current list of unsupported devices, skipping test.")
|
||||
sys.exit(77)
|
||||
data = response.read().decode('utf-8')
|
||||
|
||||
devices = []
|
||||
devices_re = re.compile(r'^.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*$', re.MULTILINE)
|
||||
for m in devices_re.finditer(data):
|
||||
vid = m.group(1)
|
||||
pid = m.group(2)
|
||||
devices.append((vid, pid))
|
||||
|
||||
generator = open(os.path.join(os.path.dirname(__file__), '..', 'libfprint', 'fprint-list-udev-hwdb.c')).read()
|
||||
|
||||
id_re = re.compile(' { .vid = 0x([a-fA-F0-9]*), .pid = 0x([a-fA-F0-9]*) }')
|
||||
# Check everything is the same
|
||||
started = False
|
||||
for l in generator.split('\n'):
|
||||
m = id_re.match(l)
|
||||
if m is None:
|
||||
# Stop on the first line that does not match anymore
|
||||
if started:
|
||||
break
|
||||
continue
|
||||
else:
|
||||
started = True
|
||||
|
||||
vid_pid = (m.group(1), m.group(2))
|
||||
try:
|
||||
devices.remove(vid_pid)
|
||||
except ValueError:
|
||||
print("Generator has entry that is not on wiki: {}:{}".format(*vid_pid))
|
||||
error = True
|
||||
|
||||
for vid_pid in devices:
|
||||
print("New entry from wiki is missing: {}:{}".format(*vid_pid))
|
||||
error = True
|
||||
|
||||
if error:
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
@@ -5,41 +5,101 @@ envs.set('G_MESSAGES_DEBUG', 'all')
|
||||
|
||||
# Setup paths
|
||||
envs.set('MESON_SOURCE_ROOT', meson.source_root())
|
||||
envs.set('MESON_BUILD_ROOT', meson.build_root())
|
||||
envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint'))
|
||||
|
||||
# Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed
|
||||
# random numbers rather than proper ones)
|
||||
envs.set('FP_DEVICE_EMULATION', '1')
|
||||
|
||||
# Path to SDCP virtual device binary, only used for virtual-sdcp test
|
||||
envs.set('SDCP_VIRT_BINARY', get_option('sdcp_virt_binary'))
|
||||
|
||||
# Set a colon-separated list of native drivers we enable in tests
|
||||
envs.set('FP_DRIVERS_WHITELIST', 'virtual_image')
|
||||
envs.set('FP_DRIVERS_WHITELIST', ':'.join([
|
||||
'virtual_image',
|
||||
'virtual_device',
|
||||
'virtual_device_storage',
|
||||
]))
|
||||
|
||||
envs.set('NO_AT_BRIDGE', '1')
|
||||
|
||||
drivers_tests = [
|
||||
'aes3500',
|
||||
'elan',
|
||||
'vfs5011',
|
||||
'synaptics',
|
||||
'vfs0050',
|
||||
'vfs301',
|
||||
'vfs5011',
|
||||
'goodixmoc',
|
||||
]
|
||||
|
||||
if get_option('introspection')
|
||||
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
|
||||
virtual_devices_tests = [
|
||||
'virtual-image',
|
||||
'virtual-device',
|
||||
]
|
||||
|
||||
if 'virtual_image' in drivers
|
||||
unittest_inspector = find_program('unittest_inspector.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'))
|
||||
unit_tests = r.stdout().strip().split('\n')
|
||||
|
||||
if r.returncode() == 0 and unit_tests.length() > 0
|
||||
suite += vdtest
|
||||
else
|
||||
unit_tests = [vdtest]
|
||||
endif
|
||||
|
||||
foreach ut: unit_tests
|
||||
ut_suite = suite
|
||||
ut_args = base_args
|
||||
if unit_tests.length() > 1
|
||||
ut_args += ut
|
||||
ut_suite += ut.split('.')[0]
|
||||
endif
|
||||
test(ut,
|
||||
python3,
|
||||
args: ut_args,
|
||||
suite: ut_suite,
|
||||
depends: libfprint_typelib,
|
||||
env: envs,
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
endforeach
|
||||
else
|
||||
test(vdtest,
|
||||
find_program('sh'),
|
||||
args: ['-c', 'exit 77']
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if 'virtual_sdcp' in drivers and get_option('sdcp_virt_binary') != ''
|
||||
python3 = find_program('python3')
|
||||
unittest_inspector = find_program('unittest_inspector.py')
|
||||
base_args = files('virtual-image.py')
|
||||
base_args = files('virtual-sdcp.py')
|
||||
suite = []
|
||||
|
||||
r = run_command(unittest_inspector, files('virtual-image.py'))
|
||||
r = run_command(unittest_inspector, files('virtual-sdcp.py'))
|
||||
unit_tests = r.stdout().strip().split('\n')
|
||||
|
||||
if r.returncode() == 0 and unit_tests.length() > 0
|
||||
suite += 'virtual-image'
|
||||
suite += 'virtual-sdcp'
|
||||
else
|
||||
unit_tests = ['virtual-image']
|
||||
unit_tests = ['virtual-sdcp']
|
||||
endif
|
||||
|
||||
sdcp_envs = envs
|
||||
sdcp_envs.set('FP_DEVICE_EMULATION', '0')
|
||||
foreach ut: unit_tests
|
||||
ut_suite = suite
|
||||
ut_args = base_args
|
||||
@@ -52,11 +112,12 @@ if get_option('introspection')
|
||||
args: ut_args,
|
||||
suite: ut_suite,
|
||||
depends: libfprint_typelib,
|
||||
env: envs,
|
||||
env: sdcp_envs,
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
endforeach
|
||||
else
|
||||
test('virtual-image',
|
||||
test('virtual-sdcp',
|
||||
find_program('sh'),
|
||||
args: ['-c', 'exit 77']
|
||||
)
|
||||
@@ -66,11 +127,13 @@ if get_option('introspection')
|
||||
driver_envs = envs
|
||||
driver_envs.set('FP_DRIVERS_WHITELIST', driver_test)
|
||||
|
||||
if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0')
|
||||
if (driver_test 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),
|
||||
env: driver_envs,
|
||||
workdir: meson.current_source_dir(),
|
||||
suite: ['drivers'],
|
||||
timeout: 10,
|
||||
depends: libfprint_typelib,
|
||||
@@ -164,6 +227,13 @@ foreach test_name: unit_tests
|
||||
)
|
||||
endforeach
|
||||
|
||||
# Run udev rule generator with fatal warnings
|
||||
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'),
|
||||
env: envs)
|
||||
|
||||
gdb = find_program('gdb', required: false)
|
||||
if gdb.found()
|
||||
add_test_setup('gdb',
|
||||
@@ -184,6 +254,7 @@ if valgrind.found()
|
||||
timeout_multiplier: 10,
|
||||
env: [
|
||||
'G_SLICE=always-malloc',
|
||||
'UNDER_VALGRIND=1',
|
||||
('LIBFPRINT_TEST_WRAPPER=@0@ --tool=memcheck --leak-check=full ' +
|
||||
'--suppressions=@1@ --suppressions=@2@').format(
|
||||
valgrind.path(), glib_suppressions, python_suppressions)
|
||||
|
||||
BIN
tests/sdcp-key-db/cert9.db
Normal file
BIN
tests/sdcp-key-db/cert9.db
Normal file
Binary file not shown.
BIN
tests/sdcp-key-db/key4.db
Normal file
BIN
tests/sdcp-key-db/key4.db
Normal file
Binary file not shown.
@@ -4,14 +4,16 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 01
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 40 38 0 00009C37FE5C669C2D000A01014101C10000D11BB7134A090FA1000000000100000000000003
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE011100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE01130100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE025400
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE021100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02130100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE03512000014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE035400
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
@@ -20,13 +22,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255010C
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0355010C
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
@@ -35,19 +37,19 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550119
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550119
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550125
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -56,13 +58,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550125
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -71,13 +73,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550132
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550132
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -86,13 +88,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0355013E
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -101,13 +103,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0355013E
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -116,13 +118,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255014B
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0355014B
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
@@ -131,7 +133,7 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
@@ -140,13 +142,13 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550157
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550157
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE036000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
@@ -155,21 +157,21 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550164
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE03550164
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE02591F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE03591F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 41 0 0000FE03752301012007014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037200
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE037600
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE04651E4650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046600
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE047100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 41 0 0000FE04752301012007014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE047200
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE047600
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE05651E4650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE056600
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046000
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE056000
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101
|
||||
@@ -178,9 +180,9 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE04651E4650312D30303030303030302D302
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100
|
||||
USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 39 0 0000FE0468214F2B014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 36 36 0 A7FE05811F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE05831F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE06A100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE06A200
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 39 0 0000FE0568214F2B014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 36 36 0 A7FE06811F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE06831F014650312D30303030303030302D302D30303030303030302D6E6F626F6479
|
||||
USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE07A100
|
||||
USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE07A200
|
||||
|
||||
|
||||
@@ -20,11 +20,14 @@ d.open_sync()
|
||||
template = FPrint.Print.new(d)
|
||||
|
||||
def enroll_progress(*args):
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.NEEDED
|
||||
print('enroll progress: ' + str(args))
|
||||
|
||||
# List, enroll, list, verify, delete, list
|
||||
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")
|
||||
@@ -33,7 +36,9 @@ 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")
|
||||
assert verify_res == True
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user