Compare commits
598 commits
benzea/imp
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
f579a77bfd | ||
|
03deb3011b | ||
|
c7650b6ec9 | ||
|
128d809227 | ||
|
9356e895a2 | ||
|
3c2883b992 | ||
|
eb568a62aa | ||
|
d763f8f41a | ||
|
df41ed56f6 | ||
|
aff063c23c | ||
|
e2511095d1 | ||
|
9515cc2e59 | ||
|
b3cfc40dea | ||
|
c162b895c0 | ||
|
40b3923ca6 | ||
|
d7e7d8e036 | ||
|
ec53abfc3a | ||
|
83541a2ddc | ||
|
e22497d51b | ||
|
0dcb4be4d3 | ||
|
8f93aef122 | ||
|
8dfa12e41d | ||
|
88cb452e05 | ||
|
909865ed8d | ||
|
39333a0642 | ||
|
4340be728c | ||
|
dba5ca5535 | ||
|
2a70cd7e02 | ||
|
3108ac3144 | ||
|
c928d7bd8f | ||
|
ec42b2ade1 | ||
|
4edfa48608 | ||
|
1a5df96751 | ||
|
62448492af | ||
|
874513e79a | ||
|
5c89bda7f3 | ||
|
8147372bdd | ||
|
43336a204f | ||
|
968331c383 | ||
|
d547c000fc | ||
|
ff6caca2e3 | ||
|
77756e111d | ||
|
23a4f5b77a | ||
|
5b7c5e7c09 | ||
|
da28731adc | ||
|
6440a7d12f | ||
|
71e0c29f28 | ||
|
a2d950044d | ||
|
96e5888110 | ||
|
dd476c0ccf | ||
|
4cdca4da24 | ||
|
a68fce0f2c | ||
|
1f5e0821e0 | ||
|
d6b4adec73 | ||
|
9e7bfa05b3 | ||
|
9ecd6236ee | ||
|
a07011bac2 | ||
|
f7290255e0 | ||
|
29048c51db | ||
|
42676dd300 | ||
|
45c5d17f3b | ||
|
fc76db562e | ||
|
9f93f5ded7 | ||
|
74c4125827 | ||
|
4f6d908390 | ||
|
575bd369d5 | ||
|
304219b65c | ||
|
23bca2a8ac | ||
|
4bf064d873 | ||
|
d2c2410a6f | ||
|
e8f9cc1fce | ||
|
0ee274946d | ||
|
0c26205a1e | ||
|
d957bbd0f4 | ||
|
ec9e6f1947 | ||
|
24658fb351 | ||
|
d5fda36bc0 | ||
|
cdaa3497d7 | ||
|
8a5bec6619 | ||
|
145f7287fa | ||
|
dbd89929b9 | ||
|
01663c1fb5 | ||
|
4ef13d971d | ||
|
a267e30fc6 | ||
|
2ba60d0a52 | ||
|
947420d2ce | ||
|
793cad57f3 | ||
|
f37e20b8a0 | ||
|
e2f199bb6a | ||
|
059ab65081 | ||
|
7893278cc6 | ||
|
0697191387 | ||
|
8be666bb05 | ||
|
019a294ec4 | ||
|
f6e80456d9 | ||
|
51cab75b1e | ||
|
1ed2b23902 | ||
|
9dd72611bf | ||
|
4bcb55e412 | ||
|
5bda7aef38 | ||
|
b4f564cafc | ||
|
a3f568db3d | ||
|
ba920aa41b | ||
|
db1e88138b | ||
|
7ff95dc39a | ||
|
098ff97edd | ||
|
90cbcd7fb5 | ||
|
182367a079 | ||
|
daaafc80c3 | ||
|
c989cc4b95 | ||
|
0edae7b641 | ||
|
49e3963783 | ||
|
040d0d34fd | ||
|
82c406dace | ||
|
046607add6 | ||
|
9c0cd3fb23 | ||
|
439223cac3 | ||
|
992a207ede | ||
|
ae6be6837b | ||
|
261ba3a4a4 | ||
|
e9dddcc87a | ||
|
7e02f3faf9 | ||
|
b61303500e | ||
|
668b3517a9 | ||
|
657fe85c25 | ||
|
4d5e2775b2 | ||
|
8a04578847 | ||
|
77e95aa545 | ||
|
b9df7a4e70 | ||
|
1ca56adff5 | ||
|
d683b271d4 | ||
|
94e86875ae | ||
|
511d456006 | ||
|
11e379050f | ||
|
9416f91c75 | ||
|
c4ae89575a | ||
|
04f6cac7ec | ||
|
d2981fc6a4 | ||
|
8c9167d836 | ||
|
9aa3060d32 | ||
|
9a1dcaa801 | ||
|
683ac48e21 | ||
|
3b34fc9b5b | ||
|
41f8737b48 | ||
|
ef805f2341 | ||
|
bd99f865d8 | ||
|
3717468a8a | ||
|
8d545a0b95 | ||
|
355957919e | ||
|
07778f6bfa | ||
|
7fcce7891a | ||
|
b0d9d00762 | ||
|
e95056aa86 | ||
|
9321791d0e | ||
|
4031bb62d7 | ||
|
59767af552 | ||
|
3fb8860dc4 | ||
|
03e0efe7ea | ||
|
df9483e723 | ||
|
870468c741 | ||
|
47223e551f | ||
|
e0de8c67b6 | ||
|
4a700758a6 | ||
|
e8a7ff1033 | ||
|
8ae27b4672 | ||
|
b81c6857f2 | ||
|
dbd20ec669 | ||
|
e7eaecedc6 | ||
|
52d0409241 | ||
|
f2d0d0bc57 | ||
|
8fd1fcbe49 | ||
|
e4a297887b | ||
|
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 | ||
|
b137807420 | ||
|
0936fc3597 | ||
|
b7f436e8de | ||
|
4f0b0fa526 | ||
|
f0abefa9fa | ||
|
7f58556011 | ||
|
cecb01bcb9 | ||
|
b95402bc72 | ||
|
484743f652 | ||
|
a5cfc1644f | ||
|
b3565b83e1 | ||
|
8f46de0a60 | ||
|
b3c5fe4b82 | ||
|
4cf5f92a52 | ||
|
297236b51a | ||
|
8626c64831 | ||
|
e4f9935706 | ||
|
8ba29606bb | ||
|
1b74813adf | ||
|
07ff03970f | ||
|
25ab4849a4 | ||
|
840bcc77a5 | ||
|
a464f602ca | ||
|
ad17011e68 | ||
|
744a71ce08 | ||
|
422fc5facf | ||
|
6d542edf8a | ||
|
8d4d56b1f1 | ||
|
6e30a1ee45 | ||
|
87c3b9c5ba | ||
|
0a08a6a7c0 | ||
|
9db89e00d0 | ||
|
3ad65b9589 | ||
|
48aa6d0252 | ||
|
eefc954f91 | ||
|
5bcf9ac008 | ||
|
d2402309ee | ||
|
a651b65401 | ||
|
bc3f622b2a | ||
|
5de49b33e6 | ||
|
81e198c034 | ||
|
c0895a858d | ||
|
5d5995f201 | ||
|
f71045b743 | ||
|
0274d0783b | ||
|
5c5a4f6907 | ||
|
5b6f5c9aad | ||
|
41e05b1133 | ||
|
579e01359b | ||
|
cc887c1a37 | ||
|
fdd2d6abf8 | ||
|
6bf29108a1 | ||
|
d0751ae06b | ||
|
a218a5efdd | ||
|
c6ae8e58a4 | ||
|
87c7894c28 | ||
|
e7ff4f705c | ||
|
c26588942a | ||
|
3d68cddfe7 | ||
|
96fba323b9 | ||
|
bd4f118b5e | ||
|
9d4b5ad682 | ||
|
ca788b6de2 | ||
|
90ccf9a0af | ||
|
2581f1aa32 | ||
|
ebe5cb58ba | ||
|
bd500b2235 | ||
|
8fa50d667c | ||
|
2ae8b74e60 | ||
|
f4ec816a6b | ||
|
9e2a7235e3 | ||
|
66c9e4a829 | ||
|
0bb8ad1313 | ||
|
6eb06697e9 | ||
|
355cae1bbd | ||
|
15a90eb451 | ||
|
82ba69b1df | ||
|
ccd42bdece | ||
|
e19a1a6550 | ||
|
5ac770c614 | ||
|
5faf8498d9 | ||
|
cfbd5d27b7 | ||
|
169ca1ba77 | ||
|
bb08d2e3c2 | ||
|
ca5143ffa5 | ||
|
7eb10178b8 | ||
|
2c9e252ca4 | ||
|
23fab3a20a | ||
|
24e9363a46 | ||
|
a12d316aa4 | ||
|
88461d53ec | ||
|
3b47113122 | ||
|
7a7bec5a80 | ||
|
8be861b876 | ||
|
8893840ffa | ||
|
4d6a7ec09d | ||
|
b9e546f05b | ||
|
05df5e2822 | ||
|
58a9214610 | ||
|
cdcc476325 | ||
|
a87e9c546f | ||
|
ad514c3775 | ||
|
3c5b7f8ea6 | ||
|
b09df0e40a | ||
|
027ac8d843 | ||
|
b3a4c2cf9a | ||
|
9f3272f296 | ||
|
456522397a | ||
|
0889ec20a8 | ||
|
30c783cbeb | ||
|
078cea1709 | ||
|
bc8a5859e3 | ||
|
05bc2e1c80 | ||
|
29a13a9b4a | ||
|
54286c7603 | ||
|
db14995c31 | ||
|
7aaeec3d6a | ||
|
0b8e2d6074 | ||
|
0c582230f3 | ||
|
829fb9f873 | ||
|
4d5c34e11a | ||
|
8292c449f7 | ||
|
3f3d4559b4 | ||
|
fcdf1a1ff1 | ||
|
ba07c74006 | ||
|
6716359fe8 | ||
|
c27a4faeca | ||
|
8992e559f8 | ||
|
6c6df626c8 | ||
|
87dee93633 | ||
|
516c1593bb | ||
|
dcc7e6de90 | ||
|
3c6ba0b678 | ||
|
4db1b84c7a | ||
|
36108f9f82 | ||
|
19f239ce61 | ||
|
f91e5310bb | ||
|
0d604fa34e | ||
|
d9bcf9b9cc | ||
|
b8e558452a | ||
|
c9e1a7f283 | ||
|
c5aedc9970 | ||
|
5b17eda011 | ||
|
022b4a75b1 | ||
|
bfc75de778 | ||
|
f3f768e738 | ||
|
dbb26c5ade | ||
|
0566f82219 | ||
|
c8e1269f61 | ||
|
2158c5e2d1 | ||
|
10945f8546 | ||
|
806ad10673 | ||
|
4562f9dae3 | ||
|
c57defda92 | ||
|
c806993cb9 | ||
|
95cb62fd3b | ||
|
d255a91e97 | ||
|
9ebb3fd231 | ||
|
68b5c5d98f | ||
|
2af0531994 | ||
|
bfd68bbc01 | ||
|
9c806e60f4 | ||
|
113bef8f3f | ||
|
1d1c39c234 | ||
|
4948a85e97 | ||
|
7e2db8e988 | ||
|
24d388f923 | ||
|
af42b3e468 | ||
|
edb09463f4 | ||
|
42b1deaeea | ||
|
fe828d0bb2 | ||
|
cf5473a55c | ||
|
0471edbf10 | ||
|
299a797423 | ||
|
c594863639 | ||
|
3bb1840750 | ||
|
f31b8483d4 | ||
|
324258bc8c | ||
|
f578ebe82d | ||
|
98fa6efce3 | ||
|
c7b7f78273 | ||
|
b4c3756ab0 | ||
|
da46f53e82 | ||
|
eeddd8c7bc | ||
|
43a8c909bf | ||
|
09576e5209 | ||
|
8184e33dd6 | ||
|
6f2b1f97da | ||
|
c3bf6fe863 | ||
|
5bed81025e | ||
|
d7100e41df | ||
|
ae7021e529 | ||
|
d9de941a47 | ||
|
7114d97f25 | ||
|
92a5278a74 | ||
|
d01bb41b7c | ||
|
ad88a5a78f | ||
|
ff0107fc0a | ||
|
107fdfde32 | ||
|
bb0ef04b85 | ||
|
0a475196e0 | ||
|
1dee7985b9 | ||
|
a1a3933191 | ||
|
9c8360ad67 | ||
|
0c7d2d8ecd | ||
|
6209b22e3b |
215 changed files with 72185 additions and 4847 deletions
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
|
23
.gitignore
vendored
23
.gitignore
vendored
|
@ -1,24 +1,3 @@
|
||||||
ltmain.sh
|
|
||||||
missing
|
|
||||||
stamp-h1
|
|
||||||
libtool
|
|
||||||
*.la
|
|
||||||
*.lo
|
|
||||||
*.o
|
*.o
|
||||||
*.swp
|
*.swp
|
||||||
Makefile
|
_build
|
||||||
Makefile.in
|
|
||||||
config.h*
|
|
||||||
aclocal.m4
|
|
||||||
autom4te.cache
|
|
||||||
config.guess
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
config.sub
|
|
||||||
configure
|
|
||||||
depcomp
|
|
||||||
install-sh
|
|
||||||
.deps
|
|
||||||
.libs
|
|
||||||
compile
|
|
||||||
ChangeLog
|
|
||||||
|
|
169
.gitlab-ci.yml
169
.gitlab-ci.yml
|
@ -1,13 +1,26 @@
|
||||||
image: registry.freedesktop.org/libfprint/libfprint/master:v1
|
include:
|
||||||
|
- local: '.gitlab-ci/libfprint-templates.yaml'
|
||||||
|
- project: 'freedesktop/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
|
||||||
|
FDO_DISTRIBUTION_TAG: latest
|
||||||
|
FDO_DISTRIBUTION_VERSION: rawhide
|
||||||
|
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
|
||||||
|
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||||
|
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||||
|
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- check-source
|
- check-source
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- flatpack
|
- flatpak
|
||||||
|
|
||||||
variables:
|
image: $FEDORA_IMAGE
|
||||||
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
|
||||||
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
|
||||||
|
|
||||||
.build_one_driver_template: &build_one_driver
|
.build_one_driver_template: &build_one_driver
|
||||||
script:
|
script:
|
||||||
|
@ -29,75 +42,133 @@ variables:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
variables:
|
variables:
|
||||||
driver: virtual_image
|
driver: virtual_image
|
||||||
<<: *build_one_driver
|
<<: *build_one_driver
|
||||||
<<: *build
|
<<: *build
|
||||||
# <<: *check_abi
|
# <<: *check_abi
|
||||||
|
artifacts:
|
||||||
|
expose_as: "HTML Documentation"
|
||||||
|
paths:
|
||||||
|
- _build/doc/html
|
||||||
|
- _build/doc/html/index.html
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
test:
|
test:
|
||||||
stage: test
|
stage: test
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
script:
|
script:
|
||||||
- meson --werror -Ddrivers=all . _build
|
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- meson test -C _build --verbose --no-stdsplit
|
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
||||||
|
- ninja -C _build coverage
|
||||||
|
- cat _build/meson-logs/coverage.txt
|
||||||
|
artifacts:
|
||||||
|
expose_as: 'Coverage Report'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
- _build/meson-logs/coveragereport/index.html
|
||||||
|
expire_in: 1 week
|
||||||
|
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
||||||
|
|
||||||
test_valgrind:
|
test_valgrind:
|
||||||
stage: test
|
stage: test
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
script:
|
script:
|
||||||
- meson -Ddrivers=all . _build
|
- meson -Ddrivers=all . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
|
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
|
||||||
|
artifacts:
|
||||||
|
expose_as: 'Valgrind test logs'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
- _build/meson-logs/testlog-valgrind.txt
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
|
||||||
|
test_scan_build:
|
||||||
|
stage: test
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- meson -Ddrivers=all . _build
|
||||||
|
# Wrapper to add --status-bugs and disable malloc checker
|
||||||
|
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
test_indent:
|
test_indent:
|
||||||
stage: check-source
|
stage: check-source
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
script:
|
script:
|
||||||
- scripts/uncrustify.sh --check
|
- scripts/uncrustify.sh
|
||||||
|
- git diff
|
||||||
|
- "! git status -s | grep -q ."
|
||||||
|
|
||||||
.flatpak_script_template: &flatpak_script
|
test_unsupported_list:
|
||||||
|
stage: check-source
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
- tests/hwdb-check-unsupported.py
|
||||||
# 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
|
flatpak:
|
||||||
artifacts:
|
stage: flatpak
|
||||||
paths:
|
extends: .flatpak
|
||||||
- ${BUNDLE}
|
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36
|
||||||
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: flatpack
|
|
||||||
variables:
|
variables:
|
||||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
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"
|
FLATPAK_MODULE: "libfprint"
|
||||||
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
APP_ID: "org.freedesktop.libfprint.Demo"
|
||||||
<<: *flatpak
|
rules:
|
||||||
|
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
|
||||||
flatpak-auto master:
|
when: never
|
||||||
<<: *flatpak_master
|
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||||
|
when: never
|
||||||
|
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||||
when: always
|
when: always
|
||||||
only:
|
- if: '$CI_COMMIT_TAG'
|
||||||
- tags
|
when: always
|
||||||
- master
|
# For any other (commit), allow manual run.
|
||||||
|
# This excludes MRs which would create a duplicate pipeline
|
||||||
flatpak-manual master:
|
- if: '$CI_COMMIT_BRANCH'
|
||||||
<<: *flatpak_master
|
|
||||||
when: manual
|
when: manual
|
||||||
except:
|
allow_failure: true
|
||||||
- tags
|
|
||||||
- master
|
# CONTAINERS creation stage
|
||||||
|
container_fedora_build:
|
||||||
|
extends: .fdo.container-build@fedora
|
||||||
|
only:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||||
|
variables:
|
||||||
|
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
||||||
|
FDO_FORCE_REBUILD: 1
|
||||||
|
# a list of packages to install
|
||||||
|
FDO_DISTRIBUTION_PACKAGES:
|
||||||
|
$LIBFPRINT_DEPENDENCIES
|
||||||
|
vala
|
||||||
|
libpcap-devel
|
||||||
|
libudev-devel
|
||||||
|
FDO_DISTRIBUTION_EXEC: |
|
||||||
|
git clone https://github.com/martinpitt/umockdev.git && \
|
||||||
|
cd umockdev && \
|
||||||
|
meson _build --prefix=/usr && \
|
||||||
|
ninja -C _build && ninja -C _build install
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Rebuild and push with
|
|
||||||
#
|
|
||||||
# cd .gitlab-ci/
|
|
||||||
# docker build --no-cache -t registry.freedesktop.org/libfprint/libfprint/master:v1 .
|
|
||||||
# docker push registry.freedesktop.org/libfprint/libfprint/master:v1
|
|
||||||
#
|
|
||||||
|
|
||||||
FROM fedora:rawhide
|
|
||||||
|
|
||||||
RUN dnf -y update && dnf -y upgrade && \
|
|
||||||
dnf -y install \
|
|
||||||
doxygen \
|
|
||||||
flatpak-builder \
|
|
||||||
gcc \
|
|
||||||
gcc-c++ \
|
|
||||||
git \
|
|
||||||
glib2-devel \
|
|
||||||
glibc-devel \
|
|
||||||
gobject-introspection-devel \
|
|
||||||
gtk-doc \
|
|
||||||
gtk3-devel \
|
|
||||||
libabigail \
|
|
||||||
libgusb-devel \
|
|
||||||
libX11-devel \
|
|
||||||
libXv-devel \
|
|
||||||
meson \
|
|
||||||
nss-devel \
|
|
||||||
pixman-devel \
|
|
||||||
python3-cairo \
|
|
||||||
python3-gobject \
|
|
||||||
systemd \
|
|
||||||
umockdev \
|
|
||||||
uncrustify \
|
|
||||||
valgrind \
|
|
||||||
&& \
|
|
||||||
dnf clean all
|
|
29
.gitlab-ci/libfprint-templates.yaml
Normal file
29
.gitlab-ci/libfprint-templates.yaml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.libfprint_common_variables:
|
||||||
|
LIBFPRINT_DEPENDENCIES:
|
||||||
|
doxygen
|
||||||
|
flatpak-builder
|
||||||
|
gcc
|
||||||
|
gcc-c++
|
||||||
|
gcovr
|
||||||
|
git
|
||||||
|
glib2-devel
|
||||||
|
glibc-devel
|
||||||
|
gobject-introspection-devel
|
||||||
|
gtk-doc
|
||||||
|
gtk3-devel
|
||||||
|
libabigail
|
||||||
|
libgusb-devel
|
||||||
|
libgudev-devel
|
||||||
|
libX11-devel
|
||||||
|
libXv-devel
|
||||||
|
meson
|
||||||
|
nss-devel
|
||||||
|
pixman-devel
|
||||||
|
python3-cairo
|
||||||
|
python3-gobject
|
||||||
|
systemd
|
||||||
|
umockdev
|
||||||
|
uncrustify
|
||||||
|
valgrind
|
||||||
|
clang-analyzer
|
||||||
|
diffutils
|
4
.gitlab-ci/scan-build
Executable file
4
.gitlab-ci/scan-build
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This wrapper just disables the malloc checker
|
||||||
|
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc "$@"
|
13
MAINTAINERS
Normal file
13
MAINTAINERS
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Current maintainers of libfprint are:
|
||||||
|
|
||||||
|
* Benjamin Berg <bberg@redhat.com>
|
||||||
|
* Marco Trevisan (Treviño) <mail@3v1n0.net>
|
||||||
|
|
||||||
|
Many drivers are not actively maintained and may not be fully functional.
|
||||||
|
We are happy to receive contributions, but the support we can give is
|
||||||
|
limitted unfortunately. For many drivers we may not even have test devices.
|
||||||
|
|
||||||
|
Maintained drivers are:
|
||||||
|
* synaptics:
|
||||||
|
Contributed and maintained by Synaptics Inc.
|
||||||
|
Contact: Vincent Huang <vincent.huang@tw.synaptics.com>
|
188
NEWS
188
NEWS
|
@ -1,6 +1,194 @@
|
||||||
This file lists notable changes in each release. For the full history of all
|
This file lists notable changes in each release. For the full history of all
|
||||||
changes, see ChangeLog.
|
changes, see ChangeLog.
|
||||||
|
|
||||||
|
2021-06-30: v1.94.0 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Implement suspend/resume handling including USB wakeup configuration.
|
||||||
|
This requires writing the "persist" and "wakeup" sysfs attributes.
|
||||||
|
* Add simple temperature module to prevent devices from becoming too hot
|
||||||
|
* Add feature for continuous scanning
|
||||||
|
* New internal "critical section" API to simplify driver development
|
||||||
|
* elan: new PID 0x0c58
|
||||||
|
* elanmoc: Fixes for multi-user handling and FW changes
|
||||||
|
* virtual-device: Do not time out for SCAN command
|
||||||
|
|
||||||
|
2021-06-30: v1.92.1 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* elanmoc: New driver for ELAN match-on-chip devices
|
||||||
|
* egis0570: New driver for some Egis Technology devices
|
||||||
|
* synaptics: Fix empty identify causing enroll issues
|
||||||
|
* elan: Support more PIDs
|
||||||
|
* misc: Architecture related bugfixes
|
||||||
|
|
||||||
|
2021-06-30: v1.92.0 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Support for SPI devices was added together with the elanspi driver
|
||||||
|
* Generate hwdb for autosuspend (which is now pulled by systemd)
|
||||||
|
* An API was added to clear the device storage.
|
||||||
|
Note: Devices may not implement the "list" API anymore.
|
||||||
|
* Device features can now be queried using a common API
|
||||||
|
|
||||||
|
New drivers:
|
||||||
|
* vfs7552
|
||||||
|
* nb1010
|
||||||
|
* elanspi
|
||||||
|
|
||||||
|
Driver changes:
|
||||||
|
* uru4000: Fix deactivation when unplugged unexpectedly
|
||||||
|
* goodixmoc: Correctly complete verify/identify after retry condition
|
||||||
|
* goodixmoc: Support power shield feature
|
||||||
|
* goodixmoc: Support new PIDs
|
||||||
|
* synaptics: Fix driver lockup when sequence counter overflows (#358)
|
||||||
|
* synaptics: Remove unnecessary device reset
|
||||||
|
* synaptics: Support new PIDs
|
||||||
|
* synaptics: Add clear_storage and remove list support
|
||||||
|
* synaptics: Fix initialization if the device is still busy when opening
|
||||||
|
* upeksonly: Fix double free in USB transfer callbacks
|
||||||
|
* elan: Support new PIDs
|
||||||
|
* vfs301: Fix leak of USB transfer
|
||||||
|
* uru4000: Silence warning happening during startup
|
||||||
|
|
||||||
|
Internal API changes:
|
||||||
|
* ssm: Add getter for the device
|
||||||
|
* ssm: Add cleanup state feature
|
||||||
|
* image-device: Allow overriding number of enroll stages
|
||||||
|
* context: Support udev based device discovery
|
||||||
|
* spi-transfer: Add SPI transfer helper routines
|
||||||
|
|
||||||
|
Other:
|
||||||
|
* Use pcap based USB replay for CI
|
||||||
|
* New virtual drivers for more advanced testing
|
||||||
|
* Ensure async operations are run in the thread local main context
|
||||||
|
* Disable drivers on big-endian unless they are verified to work
|
||||||
|
* Add missing gobject-introspection dependency
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
that both the driver and external APIs have changed, as both the verify and
|
||||||
|
the identify functions now have early reporting mechanisms.
|
||||||
|
The soname for the library, as well as a number of file locations have also
|
||||||
|
changed. While this allows installation in parallel with the 1.0 version of
|
||||||
|
libfprint, we recommend installing only one, and migrating from version 1.0 to
|
||||||
|
version 2.0 alongside its main consumer (fprintd).
|
||||||
|
|
||||||
|
Only major changes are listed below. A lot of other cleanup work and small
|
||||||
|
fixes have also been merged.
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Add support to run tests in gdb/valgrind
|
||||||
|
- Allow testing on all architectures
|
||||||
|
- Avoid image device AWAIT_FINGER_ON to deactivate state transitions
|
||||||
|
- Fix verify/identify error propagation to library user
|
||||||
|
- Correctly read image device information from class data
|
||||||
|
- Continue enroll after an image driver reported a retry error
|
||||||
|
- Change external API to allow reporting match results early
|
||||||
|
- A lot of new unit tests and integration tests have been added
|
||||||
|
|
||||||
|
* Drivers API
|
||||||
|
- Support variadic arguments in error functions
|
||||||
|
- Various re-definitions of ownership handling
|
||||||
|
- Add convenience API to change state after a timeout
|
||||||
|
- Add unit tests for all the drivers API
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- elan: Ensure correct deactivation of device
|
||||||
|
- uru4000: Fix IRQ handler registration and internal state handling
|
||||||
|
- uru4000: Fix control transfer request type
|
||||||
|
- synaptics: Ensure errors are only reported after finger removal
|
||||||
|
|
||||||
2019-11-20: v1.90.0 release
|
2019-11-20: v1.90.0 release
|
||||||
|
|
||||||
This release updates the core of the library to use GLib routines and Gio
|
This release updates the core of the library to use GLib routines and Gio
|
||||||
|
|
328
data/autosuspend.hwdb
Normal file
328
data/autosuspend.hwdb
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
# 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
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# 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
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver aes2501
|
||||||
|
usb:v08FFp2500*
|
||||||
|
usb:v08FFp2580*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver aes2550
|
||||||
|
usb:v08FFp2550*
|
||||||
|
usb:v08FFp2810*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# 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
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver aes3500
|
||||||
|
usb:v08FFp5731*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver aes4000
|
||||||
|
usb:v5501p08FF*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver egis0570
|
||||||
|
usb:v1C7Ap0570*
|
||||||
|
usb:v1C7Ap0571*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# 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:v04F3p0C3D*
|
||||||
|
usb:v04F3p0C42*
|
||||||
|
usb:v04F3p0C4D*
|
||||||
|
usb:v04F3p0C4F*
|
||||||
|
usb:v04F3p0C63*
|
||||||
|
usb:v04F3p0C6E*
|
||||||
|
usb:v04F3p0C58*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver elanmoc
|
||||||
|
usb:v04F3p0C7E*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver etes603
|
||||||
|
usb:v1C7Ap0603*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver goodixmoc
|
||||||
|
usb:v27C6p5840*
|
||||||
|
usb:v27C6p609C*
|
||||||
|
usb:v27C6p60A2*
|
||||||
|
usb:v27C6p639C*
|
||||||
|
usb:v27C6p63AC*
|
||||||
|
usb:v27C6p63BC*
|
||||||
|
usb:v27C6p6496*
|
||||||
|
usb:v27C6p6584*
|
||||||
|
usb:v27C6p658C*
|
||||||
|
usb:v27C6p6592*
|
||||||
|
usb:v27C6p6594*
|
||||||
|
usb:v27C6p659C*
|
||||||
|
usb:v27C6p6A94*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver nb1010
|
||||||
|
usb:v298Dp1010*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver synaptics
|
||||||
|
usb:v06CBp00BD*
|
||||||
|
usb:v06CBp00DF*
|
||||||
|
usb:v06CBp00F9*
|
||||||
|
usb:v06CBp00FC*
|
||||||
|
usb:v06CBp00C2*
|
||||||
|
usb:v06CBp00C9*
|
||||||
|
usb:v06CBp0100*
|
||||||
|
usb:v06CBp00F0*
|
||||||
|
usb:v06CBp0103*
|
||||||
|
usb:v06CBp0123*
|
||||||
|
usb:v06CBp0126*
|
||||||
|
usb:v06CBp0129*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver upeksonly
|
||||||
|
usb:v147Ep2016*
|
||||||
|
usb:v147Ep1000*
|
||||||
|
usb:v147Ep1001*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver upektc
|
||||||
|
usb:v0483p2015*
|
||||||
|
usb:v147Ep3001*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver upektc_img
|
||||||
|
usb:v147Ep2020*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver uru4000
|
||||||
|
usb:v045Ep00BC*
|
||||||
|
usb:v045Ep00BD*
|
||||||
|
usb:v045Ep00CA*
|
||||||
|
usb:v05BAp0007*
|
||||||
|
usb:v05BAp0008*
|
||||||
|
usb:v05BAp000A*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vcom5s
|
||||||
|
usb:v061Ap0110*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vfs0050
|
||||||
|
usb:v138Ap0050*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vfs101
|
||||||
|
usb:v138Ap0001*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vfs301
|
||||||
|
usb:v138Ap0005*
|
||||||
|
usb:v138Ap0008*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vfs5011
|
||||||
|
usb:v138Ap0010*
|
||||||
|
usb:v138Ap0011*
|
||||||
|
usb:v138Ap0015*
|
||||||
|
usb:v138Ap0017*
|
||||||
|
usb:v138Ap0018*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver vfs7552
|
||||||
|
usb:v138Ap0091*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Known unsupported devices
|
||||||
|
usb:v04F3p036B*
|
||||||
|
usb:v04F3p0C00*
|
||||||
|
usb:v04F3p0C4B*
|
||||||
|
usb:v04F3p0C4C*
|
||||||
|
usb:v04F3p0C57*
|
||||||
|
usb:v04F3p0C5E*
|
||||||
|
usb:v04F3p2706*
|
||||||
|
usb:v06CBp0081*
|
||||||
|
usb:v06CBp0088*
|
||||||
|
usb:v06CBp008A*
|
||||||
|
usb:v06CBp009A*
|
||||||
|
usb:v06CBp009B*
|
||||||
|
usb:v06CBp00A2*
|
||||||
|
usb:v06CBp00B7*
|
||||||
|
usb:v06CBp00BB*
|
||||||
|
usb:v06CBp00BE*
|
||||||
|
usb:v06CBp00C4*
|
||||||
|
usb:v06CBp00CB*
|
||||||
|
usb:v06CBp00D8*
|
||||||
|
usb:v06CBp00DA*
|
||||||
|
usb:v06CBp00E7*
|
||||||
|
usb:v06CBp00E9*
|
||||||
|
usb:v0A5Cp5801*
|
||||||
|
usb:v0A5Cp5805*
|
||||||
|
usb:v0A5Cp5834*
|
||||||
|
usb:v0A5Cp5840*
|
||||||
|
usb:v0A5Cp5841*
|
||||||
|
usb:v0A5Cp5842*
|
||||||
|
usb:v0A5Cp5843*
|
||||||
|
usb:v0A5Cp5844*
|
||||||
|
usb:v0A5Cp5845*
|
||||||
|
usb:v10A5p0007*
|
||||||
|
usb:v1188p9545*
|
||||||
|
usb:v138Ap0007*
|
||||||
|
usb:v138Ap003A*
|
||||||
|
usb:v138Ap003C*
|
||||||
|
usb:v138Ap003D*
|
||||||
|
usb:v138Ap003F*
|
||||||
|
usb:v138Ap0090*
|
||||||
|
usb:v138Ap0092*
|
||||||
|
usb:v138Ap0094*
|
||||||
|
usb:v138Ap0097*
|
||||||
|
usb:v138Ap009D*
|
||||||
|
usb:v138Ap00AB*
|
||||||
|
usb:v147Ep1002*
|
||||||
|
usb:v1491p0088*
|
||||||
|
usb:v16D1p1027*
|
||||||
|
usb:v1C7Ap0300*
|
||||||
|
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
|
||||||
|
ID_PERSIST=0
|
11
data/meson.build
Normal file
11
data/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
if udev_hwdb_dir != ''
|
||||||
|
# This file has to be updated using
|
||||||
|
# ninja -C <builddir> libfprint/sync-udev-hwdb
|
||||||
|
# Note that the unsupported device list needs to be manually synced from
|
||||||
|
# the wiki. See comment in libfprint/fprint-list-uev-hwdb.c
|
||||||
|
|
||||||
|
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 ||
|
if (error->domain == FP_DEVICE_RETRY ||
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
libfprint_demo_set_mode (win, RETRY_MODE);
|
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
|
else
|
||||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
return;
|
return;
|
||||||
|
@ -524,7 +526,7 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp_device_supports_capture (g_ptr_array_index (devices, 0)))
|
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
|
||||||
{
|
{
|
||||||
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,9 +9,9 @@ datadir = join_paths(prefix, get_option('datadir'))
|
||||||
|
|
||||||
executable('gtk-libfprint-test',
|
executable('gtk-libfprint-test',
|
||||||
[ 'gtk-libfprint-test.c', gtk_test_resources ],
|
[ 'gtk-libfprint-test.c', gtk_test_resources ],
|
||||||
dependencies: [ libfprint_dep, gtk_dep ],
|
dependencies: [
|
||||||
include_directories: [
|
gtk_dep,
|
||||||
root_inc,
|
libfprint_dep,
|
||||||
],
|
],
|
||||||
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
|
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
|
||||||
install: true,
|
install: true,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"app-id": "org.freedesktop.libfprint.Demo",
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
"runtime": "org.gnome.Platform",
|
"runtime": "org.gnome.Platform",
|
||||||
"runtime-version": "3.32",
|
"runtime-version": "3.36",
|
||||||
"sdk": "org.gnome.Sdk",
|
"sdk": "org.gnome.Sdk",
|
||||||
"command": "gtk-libfprint-test",
|
"command": "gtk-libfprint-test",
|
||||||
"finish-args": [
|
"finish-args": [
|
||||||
|
@ -47,10 +47,22 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "gudev",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
|
||||||
|
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "libfprint",
|
"name": "libfprint",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
"config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -20,20 +20,27 @@ FP_TYPE_DEVICE
|
||||||
FP_DEVICE_RETRY
|
FP_DEVICE_RETRY
|
||||||
FP_DEVICE_ERROR
|
FP_DEVICE_ERROR
|
||||||
FpDeviceType
|
FpDeviceType
|
||||||
|
FpDeviceFeature
|
||||||
FpScanType
|
FpScanType
|
||||||
FpDeviceRetry
|
FpDeviceRetry
|
||||||
FpDeviceError
|
FpDeviceError
|
||||||
|
FpFingerStatusFlags
|
||||||
fp_device_retry_quark
|
fp_device_retry_quark
|
||||||
fp_device_error_quark
|
fp_device_error_quark
|
||||||
FpEnrollProgress
|
FpEnrollProgress
|
||||||
|
FpMatchCb
|
||||||
fp_device_get_driver
|
fp_device_get_driver
|
||||||
fp_device_get_device_id
|
fp_device_get_device_id
|
||||||
fp_device_get_name
|
fp_device_get_name
|
||||||
fp_device_get_scan_type
|
fp_device_get_scan_type
|
||||||
fp_device_get_nr_enroll_stages
|
fp_device_get_nr_enroll_stages
|
||||||
|
fp_device_get_finger_status
|
||||||
|
fp_device_get_features
|
||||||
|
fp_device_has_feature
|
||||||
fp_device_has_storage
|
fp_device_has_storage
|
||||||
fp_device_supports_identify
|
fp_device_supports_identify
|
||||||
fp_device_supports_capture
|
fp_device_supports_capture
|
||||||
|
fp_device_is_open
|
||||||
fp_device_open
|
fp_device_open
|
||||||
fp_device_close
|
fp_device_close
|
||||||
fp_device_enroll
|
fp_device_enroll
|
||||||
|
@ -42,6 +49,9 @@ fp_device_identify
|
||||||
fp_device_capture
|
fp_device_capture
|
||||||
fp_device_delete_print
|
fp_device_delete_print
|
||||||
fp_device_list_prints
|
fp_device_list_prints
|
||||||
|
fp_device_clear_storage
|
||||||
|
fp_device_suspend
|
||||||
|
fp_device_resume
|
||||||
fp_device_open_finish
|
fp_device_open_finish
|
||||||
fp_device_close_finish
|
fp_device_close_finish
|
||||||
fp_device_enroll_finish
|
fp_device_enroll_finish
|
||||||
|
@ -50,6 +60,9 @@ fp_device_identify_finish
|
||||||
fp_device_capture_finish
|
fp_device_capture_finish
|
||||||
fp_device_delete_print_finish
|
fp_device_delete_print_finish
|
||||||
fp_device_list_prints_finish
|
fp_device_list_prints_finish
|
||||||
|
fp_device_clear_storage_finish
|
||||||
|
fp_device_suspend_finish
|
||||||
|
fp_device_resume_finish
|
||||||
fp_device_open_sync
|
fp_device_open_sync
|
||||||
fp_device_close_sync
|
fp_device_close_sync
|
||||||
fp_device_enroll_sync
|
fp_device_enroll_sync
|
||||||
|
@ -58,6 +71,9 @@ fp_device_identify_sync
|
||||||
fp_device_capture_sync
|
fp_device_capture_sync
|
||||||
fp_device_delete_print_sync
|
fp_device_delete_print_sync
|
||||||
fp_device_list_prints_sync
|
fp_device_list_prints_sync
|
||||||
|
fp_device_clear_storage_sync
|
||||||
|
fp_device_suspend_sync
|
||||||
|
fp_device_resume_sync
|
||||||
FpDevice
|
FpDevice
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
@ -90,8 +106,6 @@ FP_TYPE_PRINT
|
||||||
FpFinger
|
FpFinger
|
||||||
FpPrint
|
FpPrint
|
||||||
fp_print_new
|
fp_print_new
|
||||||
fp_print_new_from_data
|
|
||||||
fp_print_to_data
|
|
||||||
fp_print_get_driver
|
fp_print_get_driver
|
||||||
fp_print_get_device_id
|
fp_print_get_device_id
|
||||||
fp_print_get_device_stored
|
fp_print_get_device_stored
|
||||||
|
@ -129,9 +143,11 @@ fpi_get_driver_types
|
||||||
<FILE>fpi-device</FILE>
|
<FILE>fpi-device</FILE>
|
||||||
FpDeviceClass
|
FpDeviceClass
|
||||||
FpTimeoutFunc
|
FpTimeoutFunc
|
||||||
FpDeviceAction
|
FpiDeviceAction
|
||||||
FpIdEntry
|
FpIdEntry
|
||||||
|
FpiDeviceUdevSubtypeFlags
|
||||||
fpi_device_get_usb_device
|
fpi_device_get_usb_device
|
||||||
|
fpi_device_get_udev_data
|
||||||
fpi_device_get_virtual_env
|
fpi_device_get_virtual_env
|
||||||
fpi_device_get_current_action
|
fpi_device_get_current_action
|
||||||
fpi_device_retry_new
|
fpi_device_retry_new
|
||||||
|
@ -149,6 +165,12 @@ fpi_device_action_is_cancelled
|
||||||
fpi_device_add_timeout
|
fpi_device_add_timeout
|
||||||
fpi_device_set_nr_enroll_stages
|
fpi_device_set_nr_enroll_stages
|
||||||
fpi_device_set_scan_type
|
fpi_device_set_scan_type
|
||||||
|
fpi_device_update_features
|
||||||
|
fpi_device_critical_enter
|
||||||
|
fpi_device_critical_leave
|
||||||
|
fpi_device_remove
|
||||||
|
fpi_device_report_finger_status
|
||||||
|
fpi_device_report_finger_status_changes
|
||||||
fpi_device_action_error
|
fpi_device_action_error
|
||||||
fpi_device_probe_complete
|
fpi_device_probe_complete
|
||||||
fpi_device_open_complete
|
fpi_device_open_complete
|
||||||
|
@ -158,7 +180,13 @@ fpi_device_verify_complete
|
||||||
fpi_device_identify_complete
|
fpi_device_identify_complete
|
||||||
fpi_device_capture_complete
|
fpi_device_capture_complete
|
||||||
fpi_device_delete_complete
|
fpi_device_delete_complete
|
||||||
|
fpi_device_list_complete
|
||||||
|
fpi_device_suspend_complete
|
||||||
|
fpi_device_resume_complete
|
||||||
fpi_device_enroll_progress
|
fpi_device_enroll_progress
|
||||||
|
fpi_device_verify_report
|
||||||
|
fpi_device_identify_report
|
||||||
|
fpi_device_class_auto_initialize_features
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -172,8 +200,8 @@ fpi_image_resize
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>fpi-image-device</FILE>
|
<FILE>fpi-image-device</FILE>
|
||||||
<TITLE>FpImageDevice</TITLE>
|
<TITLE>Internal FpImageDevice</TITLE>
|
||||||
FpImageDeviceState
|
FpiImageDeviceState
|
||||||
FpImageDeviceClass
|
FpImageDeviceClass
|
||||||
fpi_image_device_session_error
|
fpi_image_device_session_error
|
||||||
fpi_image_device_open_complete
|
fpi_image_device_open_complete
|
||||||
|
@ -183,6 +211,7 @@ fpi_image_device_deactivate_complete
|
||||||
fpi_image_device_report_finger_status
|
fpi_image_device_report_finger_status
|
||||||
fpi_image_device_image_captured
|
fpi_image_device_image_captured
|
||||||
fpi_image_device_retry_scan
|
fpi_image_device_retry_scan
|
||||||
|
fpi_image_device_set_bz3_threshold
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -197,13 +226,15 @@ BUG
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>fpi-print</FILE>
|
<FILE>fpi-print</FILE>
|
||||||
FpPrintType
|
FpiPrintType
|
||||||
FpiMatchResult
|
FpiMatchResult
|
||||||
fpi_print_add_print
|
fpi_print_add_print
|
||||||
fpi_print_set_type
|
fpi_print_set_type
|
||||||
fpi_print_set_device_stored
|
fpi_print_set_device_stored
|
||||||
fpi_print_add_from_image
|
fpi_print_add_from_image
|
||||||
fpi_print_bz3_match
|
fpi_print_bz3_match
|
||||||
|
fpi_print_generate_user_id
|
||||||
|
fpi_print_fill_from_user_id
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -224,10 +255,10 @@ fpi_ssm_mark_completed
|
||||||
fpi_ssm_mark_failed
|
fpi_ssm_mark_failed
|
||||||
fpi_ssm_set_data
|
fpi_ssm_set_data
|
||||||
fpi_ssm_get_data
|
fpi_ssm_get_data
|
||||||
|
fpi_ssm_get_device
|
||||||
fpi_ssm_get_error
|
fpi_ssm_get_error
|
||||||
fpi_ssm_dup_error
|
fpi_ssm_dup_error
|
||||||
fpi_ssm_get_cur_state
|
fpi_ssm_get_cur_state
|
||||||
fpi_ssm_next_state_timeout_cb
|
|
||||||
fpi_ssm_usb_transfer_cb
|
fpi_ssm_usb_transfer_cb
|
||||||
FpiSsm
|
FpiSsm
|
||||||
</SECTION>
|
</SECTION>
|
8
doc/libfprint-2.types
Normal file
8
doc/libfprint-2.types
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include <fprint.h>
|
||||||
|
#include <fp-image-device.h>
|
||||||
|
|
||||||
|
fp_context_get_type
|
||||||
|
fp_device_get_type
|
||||||
|
fp_image_device_get_type
|
||||||
|
fp_image_get_type
|
||||||
|
fp_print_get_type
|
|
@ -90,7 +90,7 @@ fp_image_get_width
|
||||||
<TITLE>Base class for image devices</TITLE>
|
<TITLE>Base class for image devices</TITLE>
|
||||||
FpImageDevice
|
FpImageDevice
|
||||||
FpImageDeviceClass
|
FpImageDeviceClass
|
||||||
FpImageDeviceState
|
FpiImageDeviceState
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -114,5 +114,3 @@ FpUsbTransferCallback
|
||||||
FP_USB_ENDPOINT_IN
|
FP_USB_ENDPOINT_IN
|
||||||
FP_USB_ENDPOINT_OUT
|
FP_USB_ENDPOINT_OUT
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ private_headers = [
|
||||||
'config.h',
|
'config.h',
|
||||||
'nbis-helpers.h',
|
'nbis-helpers.h',
|
||||||
'fprint.h',
|
'fprint.h',
|
||||||
'fp_internal.h',
|
|
||||||
|
|
||||||
# Subdirectories to ignore
|
# Subdirectories to ignore
|
||||||
'drivers',
|
'drivers',
|
||||||
|
@ -24,17 +23,15 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
|
||||||
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||||
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
|
|
||||||
gnome.gtkdoc('libfprint',
|
gnome.gtkdoc(versioned_libname,
|
||||||
main_xml: 'libfprint-docs.xml',
|
main_xml: 'libfprint-docs.xml',
|
||||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||||
|
include_directories: include_directories('../libfprint'),
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
content_files: content_files,
|
content_files: content_files,
|
||||||
expand_content_files: expand_content_files,
|
expand_content_files: expand_content_files,
|
||||||
scan_args: [
|
ignore_headers: private_headers,
|
||||||
#'--rebuild-sections',
|
gobject_typesfile: 'libfprint-2.types',
|
||||||
'--ignore-decorators=API_EXPORTED',
|
|
||||||
'--ignore-headers=' + ' '.join(private_headers),
|
|
||||||
],
|
|
||||||
fixxref_args: [
|
fixxref_args: [
|
||||||
'--html-dir=@0@'.format(docpath),
|
'--html-dir=@0@'.format(docpath),
|
||||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
ent_conf = configuration_data()
|
ent_conf = configuration_data()
|
||||||
ent_conf.set('PACKAGE', 'libfprint')
|
ent_conf.set('PACKAGE', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||||
ent_conf.set('PACKAGE_NAME', 'libfprint')
|
ent_conf.set('PACKAGE_NAME', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_STRING', 'libfprint')
|
ent_conf.set('PACKAGE_STRING', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||||
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||||
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Example fingerprint enrollment program
|
* Example fingerprint enrollment program
|
||||||
* Enrolls your choosen finger and saves the print to disk
|
* Enrolls your chosen finger and saves the print to disk
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
*
|
*
|
||||||
|
@ -19,8 +19,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-enroll"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
@ -28,6 +31,8 @@
|
||||||
typedef struct _EnrollData
|
typedef struct _EnrollData
|
||||||
{
|
{
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
unsigned int sigint_handler;
|
||||||
FpFinger finger;
|
FpFinger finger;
|
||||||
int ret_value;
|
int ret_value;
|
||||||
} EnrollData;
|
} EnrollData;
|
||||||
|
@ -35,6 +40,8 @@ typedef struct _EnrollData
|
||||||
static void
|
static void
|
||||||
enroll_data_free (EnrollData *enroll_data)
|
enroll_data_free (EnrollData *enroll_data)
|
||||||
{
|
{
|
||||||
|
g_clear_handle_id (&enroll_data->sigint_handler, g_source_remove);
|
||||||
|
g_clear_object (&enroll_data->cancellable);
|
||||||
g_main_loop_unref (enroll_data->loop);
|
g_main_loop_unref (enroll_data->loop);
|
||||||
g_free (enroll_data);
|
g_free (enroll_data);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +57,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (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);
|
g_main_loop_quit (enroll_data->loop);
|
||||||
}
|
}
|
||||||
|
@ -69,9 +76,14 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
{
|
{
|
||||||
enroll_data->ret_value = EXIT_SUCCESS;
|
enroll_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
if (!fp_device_has_storage (dev))
|
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
{
|
g_debug ("Device has storage, saving a print reference locally");
|
||||||
g_debug ("Device has not storage, saving 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);
|
int r = print_data_save (print, enroll_data->finger);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
|
@ -79,10 +91,9 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
enroll_data->ret_value = EXIT_FAILURE;
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
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,
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
@ -105,7 +116,7 @@ on_enroll_progress (FpDevice *device,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp_device_supports_capture (device) &&
|
if (print && fp_print_get_image (print) &&
|
||||||
print_image_save (print, "enrolled.pgm"))
|
print_image_save (print, "enrolled.pgm"))
|
||||||
printf ("Wrote scanned image to enrolled.pgm\n");
|
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||||
|
|
||||||
|
@ -135,11 +146,22 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
printf ("Scan your finger now.\n");
|
printf ("Scan your finger now.\n");
|
||||||
|
|
||||||
print_template = print_create_template (dev, enroll_data->finger);
|
print_template = print_create_template (dev, enroll_data->finger);
|
||||||
fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL,
|
fp_device_enroll (dev, print_template, enroll_data->cancellable,
|
||||||
NULL, (GAsyncReadyCallback) on_enroll_completed,
|
on_enroll_progress, NULL, NULL,
|
||||||
|
(GAsyncReadyCallback) on_enroll_completed,
|
||||||
enroll_data);
|
enroll_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
sigint_cb (void *user_data)
|
||||||
|
{
|
||||||
|
EnrollData *enroll_data = user_data;
|
||||||
|
|
||||||
|
g_cancellable_cancel (enroll_data->cancellable);
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
|
@ -186,8 +208,15 @@ main (void)
|
||||||
enroll_data->finger = finger;
|
enroll_data->finger = finger;
|
||||||
enroll_data->ret_value = EXIT_FAILURE;
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
enroll_data->loop = g_main_loop_new (NULL, FALSE);
|
enroll_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
enroll_data->cancellable = g_cancellable_new ();
|
||||||
|
enroll_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
||||||
|
SIGINT,
|
||||||
|
sigint_cb,
|
||||||
|
enroll_data,
|
||||||
|
NULL);
|
||||||
|
|
||||||
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
fp_device_open (dev, enroll_data->cancellable,
|
||||||
|
(GAsyncReadyCallback) on_device_opened,
|
||||||
enroll_data);
|
enroll_data);
|
||||||
|
|
||||||
g_main_loop_run (enroll_data->loop);
|
g_main_loop_run (enroll_data->loop);
|
||||||
|
|
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_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
|
{
|
||||||
|
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_has_feature (dev, FP_DEVICE_FEATURE_IDENTIFY))
|
||||||
|
{
|
||||||
|
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_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
|
@ -18,6 +18,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-mange-prints"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
@ -52,7 +54,7 @@ on_device_closed (FpDevice *dev,
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (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);
|
g_main_loop_quit (list_data->loop);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,7 @@ delete_next_print (FpDevice *dev,
|
||||||
g_assert_nonnull (list_data->to_delete);
|
g_assert_nonnull (list_data->to_delete);
|
||||||
print = list_data->to_delete->data;
|
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,
|
fp_device_delete_print (dev, print, NULL,
|
||||||
(GAsyncReadyCallback) on_print_deleted, list_data);
|
(GAsyncReadyCallback) on_print_deleted, list_data);
|
||||||
}
|
}
|
||||||
|
@ -197,9 +199,6 @@ on_list_completed (FpDevice *dev,
|
||||||
list_data->ret_value = EXIT_SUCCESS;
|
list_data->ret_value = EXIT_SUCCESS;
|
||||||
else
|
else
|
||||||
g_warning ("Invalid finger selected");
|
g_warning ("Invalid finger selected");
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
|
||||||
list_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +231,7 @@ on_device_opened (FpDevice *dev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp_device_has_storage (dev))
|
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
{
|
{
|
||||||
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
||||||
g_main_loop_quit (list_data->loop);
|
g_main_loop_quit (list_data->loop);
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
|
|
||||||
examples = [ 'enroll', 'verify', 'manage-prints' ]
|
examples = [
|
||||||
|
'enroll',
|
||||||
|
'identify',
|
||||||
|
'img-capture',
|
||||||
|
'manage-prints',
|
||||||
|
'verify',
|
||||||
|
]
|
||||||
|
|
||||||
foreach example: examples
|
foreach example: examples
|
||||||
executable(example,
|
executable(example,
|
||||||
[ example + '.c', 'storage.c', 'utilities.c' ],
|
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||||
dependencies: [ libfprint_dep, glib_dep ],
|
dependencies: [
|
||||||
include_directories: [
|
libfprint_dep,
|
||||||
root_inc,
|
glib_dep,
|
||||||
])
|
],
|
||||||
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
executable('cpp-test',
|
executable('cpp-test',
|
||||||
'cpp-test.cpp',
|
'cpp-test.cpp',
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
include_directories: [
|
)
|
||||||
root_inc,
|
|
||||||
])
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Trivial storage driver for example programs
|
* Trivial storage driver for example programs
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -19,7 +19,10 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-storage"
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
#include <libfprint/fpi-compat.h>
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -57,7 +60,7 @@ load_data (void)
|
||||||
{
|
{
|
||||||
GVariantDict *res;
|
GVariantDict *res;
|
||||||
GVariant *var;
|
GVariant *var;
|
||||||
g_autofree gchar *contents = NULL;
|
gchar *contents = NULL;
|
||||||
gsize length = 0;
|
gsize length = 0;
|
||||||
|
|
||||||
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
|
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
|
||||||
|
@ -66,7 +69,12 @@ load_data (void)
|
||||||
return g_variant_dict_new (NULL);
|
return g_variant_dict_new (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL);
|
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT,
|
||||||
|
contents,
|
||||||
|
length,
|
||||||
|
FALSE,
|
||||||
|
g_free,
|
||||||
|
contents);
|
||||||
|
|
||||||
res = g_variant_dict_new (var);
|
res = g_variant_dict_new (var);
|
||||||
g_variant_unref (var);
|
g_variant_unref (var);
|
||||||
|
@ -129,7 +137,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
|
||||||
|
|
||||||
g_autoptr(GVariant) val = NULL;
|
g_autoptr(GVariant) val = NULL;
|
||||||
g_autoptr(GVariantDict) dict = NULL;
|
g_autoptr(GVariantDict) dict = NULL;
|
||||||
g_autofree guchar *stored_data = NULL;
|
const guchar *stored_data = NULL;
|
||||||
gsize stored_len;
|
gsize stored_len;
|
||||||
|
|
||||||
dict = load_data ();
|
dict = load_data ();
|
||||||
|
@ -140,7 +148,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
|
||||||
FpPrint *print;
|
FpPrint *print;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
|
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
|
||||||
print = fp_print_deserialize (stored_data, stored_len, &error);
|
print = fp_print_deserialize (stored_data, stored_len, &error);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -152,12 +160,58 @@ print_data_load (FpDevice *dev, FpFinger finger)
|
||||||
return NULL;
|
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 *
|
FpPrint *
|
||||||
print_create_template (FpDevice *dev, FpFinger finger)
|
print_create_template (FpDevice *dev, FpFinger finger)
|
||||||
{
|
{
|
||||||
g_autoptr(GDateTime) datetime = NULL;
|
g_autoptr(GDateTime) datetime = NULL;
|
||||||
|
g_autoptr(GDate) date = NULL;
|
||||||
FpPrint *template = NULL;
|
FpPrint *template = NULL;
|
||||||
GDate *date = NULL;
|
|
||||||
gint year, month, day;
|
gint year, month, day;
|
||||||
|
|
||||||
template = fp_print_new (dev);
|
template = fp_print_new (dev);
|
||||||
|
@ -167,13 +221,12 @@ print_create_template (FpDevice *dev, FpFinger finger)
|
||||||
g_date_time_get_ymd (datetime, &year, &month, &day);
|
g_date_time_get_ymd (datetime, &year, &month, &day);
|
||||||
date = g_date_new_dmy (day, month, year);
|
date = g_date_new_dmy (day, month, year);
|
||||||
fp_print_set_enroll_date (template, date);
|
fp_print_set_enroll_date (template, date);
|
||||||
g_date_free (date);
|
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
gboolean
|
||||||
save_image_to_pgm (FpImage *img, const char *path)
|
save_image_to_pgm (FpImage *img, const char *path)
|
||||||
{
|
{
|
||||||
FILE *fd = fopen (path, "w");
|
FILE *fd = fopen (path, "w");
|
||||||
|
@ -213,7 +266,7 @@ save_image_to_pgm (FpImage *img, const char *path)
|
||||||
gboolean
|
gboolean
|
||||||
print_image_save (FpPrint *print, const char *path)
|
print_image_save (FpPrint *print, const char *path)
|
||||||
{
|
{
|
||||||
g_autoptr(FpImage) img = NULL;
|
FpImage *img = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
|
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
|
||||||
g_return_val_if_fail (path != NULL, FALSE);
|
g_return_val_if_fail (path != NULL, FALSE);
|
||||||
|
|
|
@ -18,17 +18,16 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __STORAGE_H
|
#pragma once
|
||||||
#define __STORAGE_H
|
|
||||||
|
|
||||||
|
|
||||||
int print_data_save (FpPrint *print,
|
int print_data_save (FpPrint *print,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
FpPrint * print_data_load (FpDevice *dev,
|
FpPrint * print_data_load (FpDevice *dev,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
|
GPtrArray * gallery_data_load (FpDevice *dev);
|
||||||
FpPrint * print_create_template (FpDevice *dev,
|
FpPrint * print_create_template (FpDevice *dev,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
gboolean print_image_save (FpPrint *print,
|
gboolean print_image_save (FpPrint *print,
|
||||||
const char *path);
|
const char *path);
|
||||||
|
gboolean save_image_to_pgm (FpImage *img,
|
||||||
#endif /* __STORAGE_H */
|
const char *path);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-utilities"
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -99,6 +101,7 @@ finger_to_string (FpFinger finger)
|
||||||
case FP_FINGER_RIGHT_LITTLE:
|
case FP_FINGER_RIGHT_LITTLE:
|
||||||
return "right little";
|
return "right little";
|
||||||
|
|
||||||
|
case FP_FINGER_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
@ -107,29 +110,19 @@ finger_to_string (FpFinger finger)
|
||||||
FpFinger
|
FpFinger
|
||||||
finger_chooser (void)
|
finger_chooser (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i = FP_FINGER_UNKNOWN;
|
||||||
const FpFinger all_fingers[] = {
|
|
||||||
FP_FINGER_LEFT_THUMB,
|
|
||||||
FP_FINGER_LEFT_INDEX,
|
|
||||||
FP_FINGER_LEFT_MIDDLE,
|
|
||||||
FP_FINGER_LEFT_RING,
|
|
||||||
FP_FINGER_LEFT_LITTLE,
|
|
||||||
FP_FINGER_RIGHT_THUMB,
|
|
||||||
FP_FINGER_RIGHT_INDEX,
|
|
||||||
FP_FINGER_RIGHT_MIDDLE,
|
|
||||||
FP_FINGER_RIGHT_RING,
|
|
||||||
FP_FINGER_RIGHT_LITTLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i)
|
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i)
|
||||||
g_print (" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i));
|
g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i));
|
||||||
|
|
||||||
g_print ("> ");
|
g_print ("> ");
|
||||||
if (!scanf ("%d%*c", &i))
|
if (!scanf ("%d%*c", &i))
|
||||||
return FP_FINGER_UNKNOWN;
|
return FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
if (i < 0 || i >= G_N_ELEMENTS (all_fingers))
|
i += FP_FINGER_FIRST;
|
||||||
|
|
||||||
|
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
|
||||||
return FP_FINGER_UNKNOWN;
|
return FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
return all_fingers[i];
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UTILITIES_H
|
#pragma once
|
||||||
#define __UTILITIES_H
|
|
||||||
|
|
||||||
FpDevice * discover_device (GPtrArray *devices);
|
FpDevice * discover_device (GPtrArray *devices);
|
||||||
FpFinger finger_chooser (void);
|
FpFinger finger_chooser (void);
|
||||||
const char * finger_to_string (FpFinger finger);
|
const char * finger_to_string (FpFinger finger);
|
||||||
|
|
||||||
#endif /* __UTILITIES_H */
|
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-verify"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
@ -28,6 +31,8 @@
|
||||||
typedef struct _VerifyData
|
typedef struct _VerifyData
|
||||||
{
|
{
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
unsigned int sigint_handler;
|
||||||
FpFinger finger;
|
FpFinger finger;
|
||||||
int ret_value;
|
int ret_value;
|
||||||
} VerifyData;
|
} VerifyData;
|
||||||
|
@ -35,6 +40,8 @@ typedef struct _VerifyData
|
||||||
static void
|
static void
|
||||||
verify_data_free (VerifyData *verify_data)
|
verify_data_free (VerifyData *verify_data)
|
||||||
{
|
{
|
||||||
|
g_clear_handle_id (&verify_data->sigint_handler, g_source_remove);
|
||||||
|
g_clear_object (&verify_data->cancellable);
|
||||||
g_main_loop_unref (verify_data->loop);
|
g_main_loop_unref (verify_data->loop);
|
||||||
g_free (verify_data);
|
g_free (verify_data);
|
||||||
}
|
}
|
||||||
|
@ -50,11 +57,24 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (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);
|
g_main_loop_quit (verify_data->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
verify_quit (FpDevice *dev,
|
||||||
|
VerifyData *verify_data)
|
||||||
|
{
|
||||||
|
if (!fp_device_is_open (dev))
|
||||||
|
{
|
||||||
|
g_main_loop_quit (verify_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
|
||||||
|
}
|
||||||
|
|
||||||
static void start_verification (FpDevice *dev,
|
static void start_verification (FpDevice *dev,
|
||||||
VerifyData *verify_data);
|
VerifyData *verify_data);
|
||||||
|
|
||||||
|
@ -71,35 +91,85 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
||||||
{
|
{
|
||||||
g_warning ("Failed to verify print: %s", error->message);
|
g_warning ("Failed to verify print: %s", error->message);
|
||||||
g_main_loop_quit (verify_data->loop);
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (error->domain != FP_DEVICE_RETRY)
|
||||||
|
{
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match)
|
|
||||||
{
|
|
||||||
g_print ("MATCH!\n");
|
|
||||||
if (fp_device_supports_capture (dev) &&
|
|
||||||
print_image_save (print, "verify.pgm"))
|
|
||||||
g_print ("Print image saved as verify.pgm");
|
|
||||||
|
|
||||||
verify_data->ret_value = EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_print ("NO MATCH!\n");
|
|
||||||
verify_data->ret_value = EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_print ("Verify again? [Y/n]? ");
|
g_print ("Verify again? [Y/n]? ");
|
||||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||||
(buffer[0] == 'Y' || buffer[0] == 'y'))
|
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
||||||
{
|
{
|
||||||
start_verification (dev, verify_data);
|
start_verification (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
verify_quit (dev, verify_data);
|
||||||
verify_data);
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
VerifyData *verify_data = user_data;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Match report: Finger not matched, retry error reported: %s",
|
||||||
|
error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print && fp_print_get_image (print) &&
|
||||||
|
print_image_save (print, "verify.pgm"))
|
||||||
|
g_print ("Print image saved as verify.pgm\n");
|
||||||
|
|
||||||
|
if (match)
|
||||||
|
{
|
||||||
|
char date_str[128];
|
||||||
|
|
||||||
|
verify_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
||||||
|
fp_print_get_enroll_date (match));
|
||||||
|
g_debug ("Match report: device %s matched finger %s successifully "
|
||||||
|
"with print %s, enrolled on date %s by user %s",
|
||||||
|
fp_device_get_name (dev),
|
||||||
|
finger_to_string (fp_print_get_finger (match)),
|
||||||
|
fp_print_get_description (match), date_str,
|
||||||
|
fp_print_get_username (match));
|
||||||
|
|
||||||
|
g_print ("MATCH!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Match report: Finger not matched");
|
||||||
|
g_print ("NO MATCH!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
|
@ -115,15 +185,27 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
if (!error)
|
if (!error)
|
||||||
{
|
{
|
||||||
FpPrint *verify_print = NULL;
|
FpPrint *verify_print = NULL;
|
||||||
|
g_autoptr(FpPrint) stored_print = NULL;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
if (!prints->len)
|
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)
|
for (i = 0; i < prints->len; ++i)
|
||||||
{
|
{
|
||||||
FpPrint *print = prints->pdata[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 &&
|
if (fp_print_get_finger (print) == verify_data->finger &&
|
||||||
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
||||||
{
|
{
|
||||||
|
@ -141,9 +223,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
|
|
||||||
if (!verify_print)
|
if (!verify_print)
|
||||||
{
|
{
|
||||||
g_warning ("Did you remember to enroll your %s finger first?",
|
verify_quit (dev, verify_data);
|
||||||
finger_to_string (verify_data->finger));
|
|
||||||
g_main_loop_quit (verify_data->loop);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,32 +231,36 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
fp_print_get_description (verify_print));
|
fp_print_get_description (verify_print));
|
||||||
|
|
||||||
g_print ("Print loaded. Time to verify!\n");
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
fp_device_verify (dev, verify_print, NULL,
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||||
|
on_match_cb, verify_data, NULL,
|
||||||
(GAsyncReadyCallback) on_verify_completed,
|
(GAsyncReadyCallback) on_verify_completed,
|
||||||
verify_data);
|
verify_data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_warning ("Loading prints failed with error %s", error->message);
|
g_warning ("Loading prints failed with error %s", error->message);
|
||||||
g_main_loop_quit (verify_data->loop);
|
verify_quit (dev, verify_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
start_verification (FpDevice *dev, VerifyData *verify_data)
|
start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||||
{
|
{
|
||||||
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
||||||
|
{
|
||||||
g_print ("Choose the finger to verify:\n");
|
g_print ("Choose the finger to verify:\n");
|
||||||
verify_data->finger = finger_chooser ();
|
verify_data->finger = finger_chooser ();
|
||||||
|
}
|
||||||
|
|
||||||
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
||||||
{
|
{
|
||||||
g_warning ("Unknown finger selected");
|
g_warning ("Unknown finger selected");
|
||||||
verify_data->ret_value = EXIT_FAILURE;
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
g_main_loop_quit (verify_data->loop);
|
verify_quit (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp_device_has_storage (dev))
|
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
{
|
{
|
||||||
g_print ("Creating finger template, using device storage...\n");
|
g_print ("Creating finger template, using device storage...\n");
|
||||||
fp_device_list_prints (dev, NULL,
|
fp_device_list_prints (dev, NULL,
|
||||||
|
@ -185,23 +269,17 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_print ("Loading previously enrolled %s finger data...\n",
|
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
|
||||||
finger_to_string (verify_data->finger));
|
|
||||||
g_autoptr(FpPrint) verify_print = NULL;
|
|
||||||
|
|
||||||
verify_print = print_data_load (dev, verify_data->finger);
|
|
||||||
|
|
||||||
if (!verify_print)
|
if (!verify_print)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to load fingerprint data");
|
verify_quit (dev, verify_data);
|
||||||
g_warning ("Did you remember to enroll your %s finger first?",
|
|
||||||
finger_to_string (verify_data->finger));
|
|
||||||
g_main_loop_quit (verify_data->loop);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_print ("Print loaded. Time to verify!\n");
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
fp_device_verify (dev, verify_print, NULL,
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||||
|
on_match_cb, verify_data, NULL,
|
||||||
(GAsyncReadyCallback) on_verify_completed,
|
(GAsyncReadyCallback) on_verify_completed,
|
||||||
verify_data);
|
verify_data);
|
||||||
}
|
}
|
||||||
|
@ -217,7 +295,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
if (!fp_device_open_finish (dev, res, &error))
|
||||||
{
|
{
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
g_warning ("Failed to open device: %s", error->message);
|
||||||
g_main_loop_quit (verify_data->loop);
|
verify_quit (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +304,16 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
start_verification (dev, verify_data);
|
start_verification (dev, verify_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
sigint_cb (void *user_data)
|
||||||
|
{
|
||||||
|
VerifyData *verify_data = user_data;
|
||||||
|
|
||||||
|
g_cancellable_cancel (verify_data->cancellable);
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
|
@ -256,8 +344,14 @@ main (void)
|
||||||
verify_data = g_new0 (VerifyData, 1);
|
verify_data = g_new0 (VerifyData, 1);
|
||||||
verify_data->ret_value = EXIT_FAILURE;
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
verify_data->cancellable = g_cancellable_new ();
|
||||||
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
verify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
||||||
|
SIGINT,
|
||||||
|
sigint_cb,
|
||||||
|
verify_data,
|
||||||
|
NULL);
|
||||||
|
fp_device_open (dev, verify_data->cancellable,
|
||||||
|
(GAsyncReadyCallback) on_device_opened,
|
||||||
verify_data);
|
verify_data);
|
||||||
|
|
||||||
g_main_loop_run (verify_data->loop);
|
g_main_loop_run (verify_data->loop);
|
||||||
|
|
|
@ -135,10 +135,8 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
||||||
size_t bytes)
|
size_t bytes)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
data = g_malloc (bytes);
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, NULL);
|
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
@ -614,6 +612,7 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
self->strips = g_slist_reverse (self->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
|
|
|
@ -18,11 +18,12 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES1660_H
|
#pragma once
|
||||||
#define __AES1660_H
|
|
||||||
|
|
||||||
#define AES1660_FRAME_SIZE 0x244
|
#define AES1660_FRAME_SIZE 0x244
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
@ -1986,5 +1987,3 @@ static const unsigned char aes1660_start_imaging_cmd[] = {
|
||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -458,6 +458,7 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx,
|
img = fpi_assemble_frames (&assembling_ctx,
|
||||||
self->strips);
|
self->strips);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
self->strips_len = 0;
|
self->strips_len = 0;
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2501_H
|
#pragma once
|
||||||
#define __AES2501_H
|
|
||||||
|
|
||||||
enum aes2501_regs {
|
enum aes2501_regs {
|
||||||
AES2501_REG_CTRL1 = 0x80,
|
AES2501_REG_CTRL1 = 0x80,
|
||||||
|
@ -172,5 +171,3 @@ enum aes2501_sensor_gain2 {
|
||||||
|
|
||||||
#define AES2501_SUM_HIGH_THRESH 1000
|
#define AES2501_SUM_HIGH_THRESH 1000
|
||||||
#define AES2501_SUM_LOW_THRESH 700
|
#define AES2501_SUM_LOW_THRESH 700
|
||||||
|
|
||||||
#endif /* __AES2501_H */
|
|
||||||
|
|
|
@ -197,12 +197,12 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC)
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
len = data[1] * 256 + data[2];
|
len = data[1] * 256 + data[2];
|
||||||
if (len != (AES2550_STRIP_SIZE - 3))
|
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 = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
||||||
stripe->delta_x = (int8_t) data[6];
|
stripe->delta_x = (int8_t) data[6];
|
||||||
stripe->delta_y = -(int8_t) data[7];
|
stripe->delta_y = -(int8_t) data[7];
|
||||||
|
@ -230,6 +230,7 @@ capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
self->strips_len = 0;
|
self->strips_len = 0;
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2550_H
|
#pragma once
|
||||||
#define __AES2550_H
|
|
||||||
|
|
||||||
/* Registers bits */
|
/* Registers bits */
|
||||||
|
|
||||||
|
@ -110,5 +109,3 @@ enum aes2550_cmds {
|
||||||
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
||||||
|
|
||||||
#define AES2550_EP_IN_BUF_SIZE 8192
|
#define AES2550_EP_IN_BUF_SIZE 8192
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -17,11 +17,12 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2660_H
|
#pragma once
|
||||||
#define __AES2660_H
|
|
||||||
|
|
||||||
#define AES2660_FRAME_SIZE 0x354
|
#define AES2660_FRAME_SIZE 0x354
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
@ -1960,5 +1961,3 @@ static const unsigned char aes2660_start_imaging_cmd[] = {
|
||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -106,7 +106,9 @@ static struct aes_regwrite init_reqs[] = {
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct aes_regwrite capture_reqs[] = {
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -155,4 +157,6 @@ fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aes_class->init_reqs = init_reqs;
|
aes_class->init_reqs = init_reqs;
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (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
|
typedef struct
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *img_trf;
|
/* This is used both as a flag that we are in a capture operation
|
||||||
gboolean deactivating;
|
* and for cancellation.
|
||||||
|
*/
|
||||||
|
GCancellable *img_capture_cancel;
|
||||||
} FpiDeviceAes3kPrivate;
|
} FpiDeviceAes3kPrivate;
|
||||||
|
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
|
@ -84,7 +86,8 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
FpImage *img;
|
FpImage *img;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
priv->img_trf = NULL;
|
/* Image capture operation is finished (error/completed) */
|
||||||
|
g_clear_object (&priv->img_capture_cancel);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -92,14 +95,14 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_CANCELLED))
|
G_IO_ERROR_CANCELLED))
|
||||||
{
|
{
|
||||||
/* Deactivation was completed. */
|
/* Cancellation implies we are deactivating. */
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
if (priv->deactivating)
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_image_device_session_error (dev, error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
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);
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
|
||||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
/* 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);
|
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
|
static void
|
||||||
do_capture (FpImageDevice *dev)
|
do_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
g_autoptr(FpiUsbTransfer) img_trf = NULL;
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
|
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
|
||||||
priv->img_trf->short_is_error = TRUE;
|
img_trf->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (priv->img_trf, 0,
|
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
priv->img_capture_cancel,
|
||||||
img_cb, NULL);
|
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
|
static void
|
||||||
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||||
{
|
{
|
||||||
fpi_image_device_activate_complete (dev, result);
|
fpi_image_device_activate_complete (dev, result);
|
||||||
if (!result)
|
|
||||||
do_capture (dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
aes3k_dev_activate (FpImageDevice *dev)
|
aes3k_dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (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);
|
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,12 +198,28 @@ aes3k_dev_deactivate (FpImageDevice *dev)
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
priv->deactivating = TRUE;
|
/* If a capture is running, then deactivation finishes from the cancellation handler */
|
||||||
if (priv->img_trf)
|
if (priv->img_capture_cancel)
|
||||||
return;
|
g_cancellable_cancel (priv->img_capture_cancel);
|
||||||
|
else
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
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
|
static void
|
||||||
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
||||||
{
|
{
|
||||||
|
@ -217,6 +262,7 @@ fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||||
img_class->img_open = aes3k_dev_init;
|
img_class->img_open = aes3k_dev_init;
|
||||||
img_class->img_close = aes3k_dev_deinit;
|
img_class->img_close = aes3k_dev_deinit;
|
||||||
img_class->activate = aes3k_dev_activate;
|
img_class->activate = aes3k_dev_activate;
|
||||||
|
img_class->change_state = aes3k_dev_change_state;
|
||||||
img_class->deactivate = aes3k_dev_deactivate;
|
img_class->deactivate = aes3k_dev_deactivate;
|
||||||
|
|
||||||
/* Extremely low due to low image quality. */
|
/* Extremely low due to low image quality. */
|
||||||
|
|
|
@ -57,4 +57,6 @@ struct _FpiDeviceAes3kClass
|
||||||
gsize data_buflen; /* buffer length of usb bulk transfer */
|
gsize data_buflen; /* buffer length of usb bulk transfer */
|
||||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||||
gsize init_reqs_len;
|
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 */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct aes_regwrite capture_reqs[] = {
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -152,4 +154,6 @@ fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aes_class->init_reqs = init_reqs;
|
aes_class->init_reqs = init_reqs;
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,11 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "aeslib"
|
#define FP_COMPONENT "aeslib"
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "drivers_api.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "fpi-usb-transfer.h"
|
|
||||||
#include "fpi-assembling.h"
|
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
#define MAX_REGWRITES_PER_REQUEST 16
|
#define MAX_REGWRITES_PER_REQUEST 16
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AESLIB_H__
|
#pragma once
|
||||||
#define __AESLIB_H__
|
|
||||||
|
|
||||||
#include <fprint.h>
|
#include <fprint.h>
|
||||||
|
|
||||||
|
@ -45,5 +44,3 @@ unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *frame,
|
struct fpi_frame *frame,
|
||||||
unsigned int x,
|
unsigned int x,
|
||||||
unsigned int y);
|
unsigned int y);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ static void complete_deactivation (FpImageDevice *dev);
|
||||||
#define CALIBRATE_DATA_LEN 4
|
#define CALIBRATE_DATA_LEN 4
|
||||||
#define FINGER_DET_DATA_LEN 4
|
#define FINGER_DET_DATA_LEN 4
|
||||||
|
|
||||||
|
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||||
static void
|
static void
|
||||||
aesX660_send_cmd_timeout (FpiSsm *ssm,
|
aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||||
FpDevice *_dev,
|
FpDevice *_dev,
|
||||||
|
@ -70,6 +71,7 @@ aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||||
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
|
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||||
static void
|
static void
|
||||||
aesX660_send_cmd (FpiSsm *ssm,
|
aesX660_send_cmd (FpiSsm *ssm,
|
||||||
FpDevice *dev,
|
FpDevice *dev,
|
||||||
|
@ -89,13 +91,12 @@ aesX660_read_response (FpiSsm *ssm,
|
||||||
FpiUsbTransferCallback callback)
|
FpiUsbTransferCallback callback)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||||
unsigned char *data;
|
|
||||||
GCancellable *cancel = NULL;
|
GCancellable *cancel = NULL;
|
||||||
|
|
||||||
if (cancellable)
|
if (cancellable)
|
||||||
cancel = fpi_device_get_cancellable (_dev);
|
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->ssm = ssm;
|
||||||
transfer->short_is_error = short_is_error;
|
transfer->short_is_error = short_is_error;
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
|
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? */
|
/* Calibrate response was read correctly? */
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
|
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_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus calibrate "
|
"Bogus calibrate "
|
||||||
|
@ -155,14 +156,14 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("Failed to read FD data\n");
|
fp_dbg ("Failed to read FD data");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
|
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_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus FD response %.2x",
|
"Bogus FD response %.2x",
|
||||||
|
@ -177,7 +178,7 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||||
}
|
}
|
||||||
else
|
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]);
|
data[AESX660_FINGER_PRESENT_OFFSET]);
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
|
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
|
||||||
}
|
}
|
||||||
|
@ -331,6 +332,7 @@ capture_set_idle_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
priv->strips = g_slist_reverse (priv->strips);
|
priv->strips = g_slist_reverse (priv->strips);
|
||||||
img = fpi_assemble_frames (cls->assembling_ctx, priv->strips);
|
img = fpi_assemble_frames (cls->assembling_ctx, priv->strips);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
g_slist_foreach (priv->strips, (GFunc) g_free, NULL);
|
g_slist_foreach (priv->strips, (GFunc) g_free, NULL);
|
||||||
g_slist_free (priv->strips);
|
g_slist_free (priv->strips);
|
||||||
priv->strips = NULL;
|
priv->strips = NULL;
|
||||||
|
@ -363,7 +365,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("Got %lu bytes of data", actual_length);
|
fp_dbg ("Got %" G_GSIZE_FORMAT " bytes of data", actual_length);
|
||||||
while (actual_length)
|
while (actual_length)
|
||||||
{
|
{
|
||||||
gssize payload_length;
|
gssize payload_length;
|
||||||
|
@ -384,7 +386,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
|
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
|
||||||
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
|
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
|
||||||
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
|
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
|
||||||
payload_length);
|
(long) payload_length);
|
||||||
|
|
||||||
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
|
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
|
||||||
copy_len = MIN (actual_length, still_needed_len);
|
copy_len = MIN (actual_length, still_needed_len);
|
||||||
|
@ -404,7 +406,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
g_byte_array_set_size (priv->stripe_packet, 0);
|
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)
|
if (finger_missing)
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
@ -439,7 +441,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_SET_IDLE:
|
case CAPTURE_SET_IDLE:
|
||||||
fp_dbg ("Got %lu frames\n", priv->strips_len);
|
fp_dbg ("Got %" G_GSIZE_FORMAT " frames", priv->strips_len);
|
||||||
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||||
capture_set_idle_cmd_cb);
|
capture_set_idle_cmd_cb);
|
||||||
break;
|
break;
|
||||||
|
@ -512,19 +514,19 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("read_id cmd failed\n");
|
fp_dbg ("read_id cmd failed");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
if (data[0] == 0x07)
|
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]);
|
data[4], data[3], data[5], data[6], data[7]);
|
||||||
}
|
}
|
||||||
else
|
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_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus read ID response %.2x",
|
"Bogus read ID response %.2x",
|
||||||
|
@ -552,7 +554,7 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Failed to init device %.2x",
|
"Failed to init device %.2x",
|
||||||
|
@ -569,11 +571,11 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
|
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
fp_dbg ("read_init_cb\n");
|
fp_dbg ("read_init_cb");
|
||||||
|
|
||||||
if (error)
|
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);
|
(gint) transfer->actual_length);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
|
@ -581,7 +583,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
if (data[0] != 0x42 || data[3] != 0x01)
|
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]);
|
data[3]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
|
@ -613,13 +615,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
case ACTIVATE_SET_IDLE:
|
case ACTIVATE_SET_IDLE:
|
||||||
priv->init_seq_idx = 0;
|
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),
|
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||||
fpi_ssm_usb_transfer_cb);
|
fpi_ssm_usb_transfer_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_SEND_READ_ID_CMD:
|
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),
|
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
|
||||||
fpi_ssm_usb_transfer_cb);
|
fpi_ssm_usb_transfer_cb);
|
||||||
break;
|
break;
|
||||||
|
@ -629,7 +631,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_SEND_INIT_CMD:
|
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_seq_idx,
|
||||||
priv->init_cmd_idx);
|
priv->init_cmd_idx);
|
||||||
aesX660_send_cmd (ssm, _dev,
|
aesX660_send_cmd (ssm, _dev,
|
||||||
|
@ -639,7 +641,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_READ_INIT_RESPONSE:
|
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);
|
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
444
libfprint/drivers/egis0570.c
Normal file
444
libfprint/drivers/egis0570.c
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
/*
|
||||||
|
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
|
||||||
|
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
|
||||||
|
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@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 "egis0570"
|
||||||
|
|
||||||
|
#include "egis0570.h"
|
||||||
|
#include "drivers_api.h"
|
||||||
|
|
||||||
|
/* Packet types */
|
||||||
|
#define PKT_TYPE_INIT 0
|
||||||
|
#define PKT_TYPE_REPEAT 1
|
||||||
|
|
||||||
|
/* Struct */
|
||||||
|
struct _FpDeviceEgis0570
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
|
gboolean running;
|
||||||
|
gboolean stop;
|
||||||
|
|
||||||
|
GSList *strips;
|
||||||
|
guint8 *background;
|
||||||
|
gsize strips_len;
|
||||||
|
|
||||||
|
int pkt_num;
|
||||||
|
int pkt_type;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
|
static unsigned char
|
||||||
|
egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
|
||||||
|
{
|
||||||
|
return frame->data[x + y * ctx->frame_width];
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = EGIS0570_IMGWIDTH,
|
||||||
|
.frame_height = EGIS0570_RFMGHEIGHT,
|
||||||
|
.image_width = EGIS0570_IMGWIDTH * 4 / 3,
|
||||||
|
.get_pixel = egis_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Service
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_last_pkt (FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
|
||||||
|
int type = self->pkt_type;
|
||||||
|
int num = self->pkt_num;
|
||||||
|
|
||||||
|
gboolean r;
|
||||||
|
|
||||||
|
r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
|
||||||
|
r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a bit for each frame on whether or not a finger has been detected.
|
||||||
|
* e.g. 00110 means that there is a finger in frame two and three.
|
||||||
|
*/
|
||||||
|
static char
|
||||||
|
postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
|
||||||
|
{
|
||||||
|
size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
if (!self->background)
|
||||||
|
{
|
||||||
|
self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
||||||
|
memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
||||||
|
|
||||||
|
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
||||||
|
{
|
||||||
|
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
||||||
|
self->background[i] = MIN (self->background[i], frame[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
||||||
|
{
|
||||||
|
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
||||||
|
{
|
||||||
|
if (frame[i] - EGIS0570_MARGIN > self->background[i])
|
||||||
|
frame[i] -= self->background[i];
|
||||||
|
else
|
||||||
|
frame[i] = 0;
|
||||||
|
|
||||||
|
mean[k] += frame[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char result = 0;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
||||||
|
{
|
||||||
|
fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
|
||||||
|
if (mean[k] > EGIS0570_MIN_MEAN)
|
||||||
|
result |= 1 << k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device communication
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
unsigned char *stripdata;
|
||||||
|
gboolean end = FALSE;
|
||||||
|
FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int where_finger_is = postprocess_frames (self, transfer->buffer);
|
||||||
|
|
||||||
|
if (where_finger_is > 0)
|
||||||
|
{
|
||||||
|
FpiImageDeviceState state;
|
||||||
|
|
||||||
|
fpi_image_device_report_finger_status (img_self, TRUE);
|
||||||
|
|
||||||
|
g_object_get (dev, "fpi-image-device-state", &state, NULL);
|
||||||
|
if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
|
||||||
|
{
|
||||||
|
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
||||||
|
{
|
||||||
|
if (where_finger_is & (1 << k))
|
||||||
|
{
|
||||||
|
struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
|
||||||
|
stripe->delta_x = 0;
|
||||||
|
stripe->delta_y = 0;
|
||||||
|
stripdata = stripe->data;
|
||||||
|
memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
||||||
|
self->strips = g_slist_prepend (self->strips, stripe);
|
||||||
|
self->strips_len += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
if (!self->stop && (self->strips_len > 0))
|
||||||
|
{
|
||||||
|
FpImage *img;
|
||||||
|
self->strips = g_slist_reverse (self->strips);
|
||||||
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
|
img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
|
||||||
|
g_slist_free_full (self->strips, g_free);
|
||||||
|
self->strips = NULL;
|
||||||
|
self->strips_len = 0;
|
||||||
|
FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
|
||||||
|
fpi_image_device_image_captured (img_self, resizeImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_image_device_report_finger_status (img_self, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recv_data_resp (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
|
||||||
|
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
|
||||||
|
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
|
||||||
|
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSM States
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum sm_states {
|
||||||
|
SM_INIT,
|
||||||
|
SM_START,
|
||||||
|
SM_REQ,
|
||||||
|
SM_RESP,
|
||||||
|
SM_REC_DATA,
|
||||||
|
SM_DONE,
|
||||||
|
SM_STATES_NUM
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ssm_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
|
case SM_INIT:
|
||||||
|
self->pkt_type = PKT_TYPE_INIT;
|
||||||
|
fpi_ssm_next_state (ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_START:
|
||||||
|
if (self->stop)
|
||||||
|
{
|
||||||
|
fp_dbg ("deactivating, marking completed");
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
fpi_image_device_deactivate_complete (img_dev, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->pkt_num = 0;
|
||||||
|
fpi_ssm_next_state (ssm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_REQ:
|
||||||
|
if (self->pkt_type == PKT_TYPE_INIT)
|
||||||
|
send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
|
||||||
|
else
|
||||||
|
send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RESP:
|
||||||
|
if (is_last_pkt (dev) == FALSE)
|
||||||
|
{
|
||||||
|
recv_cmd_resp (ssm, dev);
|
||||||
|
self->pkt_num += 1;
|
||||||
|
fpi_ssm_jump_to_state (ssm, SM_REQ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (self->pkt_type == PKT_TYPE_INIT)
|
||||||
|
self->pkt_type = PKT_TYPE_REPEAT;
|
||||||
|
|
||||||
|
fpi_ssm_next_state (ssm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_REC_DATA:
|
||||||
|
recv_data_resp (ssm, dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_DONE:
|
||||||
|
fpi_ssm_jump_to_state (ssm, SM_START);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Activation
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
|
||||||
|
self->running = FALSE;
|
||||||
|
g_clear_pointer (&self->background, g_free);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
fpi_image_device_session_error (img_dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
|
||||||
|
|
||||||
|
self->stop = FALSE;
|
||||||
|
|
||||||
|
fpi_ssm_start (ssm, loop_complete);
|
||||||
|
|
||||||
|
self->running = TRUE;
|
||||||
|
|
||||||
|
fpi_image_device_activate_complete (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Opening
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
|
|
||||||
|
fpi_image_device_open_complete (dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closing
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_deinit (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
|
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deactivation
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
||||||
|
|
||||||
|
if (self->running)
|
||||||
|
self->stop = TRUE;
|
||||||
|
else
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver data
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const FpIdEntry id_table[] = {
|
||||||
|
{ .vid = 0x1c7a, .pid = 0x0570, },
|
||||||
|
{ .vid = 0x1c7a, .pid = 0x0571, },
|
||||||
|
{ .vid = 0, .pid = 0, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_egis0570_init (FpDeviceEgis0570 *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = "egis0570";
|
||||||
|
dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
|
img_class->img_open = dev_init;
|
||||||
|
img_class->img_close = dev_deinit;
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
|
|
||||||
|
img_class->img_width = EGIS0570_IMGWIDTH;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
|
||||||
|
img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
|
||||||
|
}
|
177
libfprint/drivers/egis0570.h
Normal file
177
libfprint/drivers/egis0570.h
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
|
||||||
|
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
|
||||||
|
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __EGIS0570_H
|
||||||
|
|
||||||
|
#define __EGIS0570_H 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device data
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_CONF 1
|
||||||
|
#define EGIS0570_INTF 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device endpoints
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_EPOUT 0x04 /* ( 4 | FPI_USB_ENDPOINT_OUT ) */
|
||||||
|
#define EGIS0570_EPIN 0x83 /* ( 3 | FPI_USB_ENDPOINT_IN ) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialization packets (7 bytes each)
|
||||||
|
*
|
||||||
|
* First 4 bytes are equivalent to string "EGIS", which must be just a company identificator
|
||||||
|
* Other 3 bytes are not recognized yet and may be not important, as they are always the same
|
||||||
|
|
||||||
|
* Answers for each packet contain 7 bytes again
|
||||||
|
* First 4 bytes are reversed "EGIS", which is "SIGE", which is company ID again
|
||||||
|
* Other 3 bytes are not recognized yet
|
||||||
|
* But there is a pattern.
|
||||||
|
* Sending last packet makes sensor return image
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_TIMEOUT 10000
|
||||||
|
#define EGIS0570_PKTSIZE 7
|
||||||
|
|
||||||
|
#define EGIS0570_INIT_TOTAL (sizeof ((init_pkts)) / sizeof ((init_pkts[0])))
|
||||||
|
|
||||||
|
static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x09 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x09 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x03 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x03 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x01 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* There is another Packet !
|
||||||
|
* That just Work the same !!
|
||||||
|
* And the Size is different !!!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#define EGIS0570_INIT_TOTAL2 (sizeof((init_pkts2)) / sizeof((init_pkts2[0])))
|
||||||
|
|
||||||
|
static unsigned char init_pkts2[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x07},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x07},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x02},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x02},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x25, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3b},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe}
|
||||||
|
};
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After sending initial packets device returns image data (32512 bytes)
|
||||||
|
* To ask device to send image data again, host needs to send four additional packets
|
||||||
|
* Further work is to repeatedly send four repeat packets and read image data
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_INPSIZE 32512
|
||||||
|
|
||||||
|
/* 5 image with captured in different time of size 114 * 57 = 6498
|
||||||
|
* 5 * 6498 = 32490 plus 22 extra unrecognized char size data
|
||||||
|
* Two continuous image in this 5 images may have time delay of less than 20ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_IMGSIZE 6498
|
||||||
|
#define EGIS0570_IMGWIDTH 114
|
||||||
|
#define EGIS0570_IMGHEIGHT 57
|
||||||
|
|
||||||
|
/* size of middle area that is used from each frame */
|
||||||
|
#define EGIS0570_RFMGHEIGHT 17
|
||||||
|
/* rows to ignore from top and bottom of the image*/
|
||||||
|
#define EGIS0570_RFMDIS (EGIS0570_IMGHEIGHT - EGIS0570_RFMGHEIGHT) / 2
|
||||||
|
#define EGIS0570_IMGCOUNT 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image repeat request
|
||||||
|
* First 4 bytes are the same as in initialization packets
|
||||||
|
* Have no idea what the other 3 bytes mean
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_REPEAT_TOTAL (sizeof ((repeat_pkts)) / sizeof ((repeat_pkts[0])))
|
||||||
|
|
||||||
|
static unsigned char repeat_pkts[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This sensor is small so I decided to reduce bz3_threshold from
|
||||||
|
* 40 to 10 to have more success to fail ratio
|
||||||
|
* Bozorth3 Algorithm seems not fine at the end
|
||||||
|
* foreget about security :))
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EGIS0570_BZ3_THRESHOLD 25 /* and even less What a joke */
|
||||||
|
|
||||||
|
#define EGIS0570_MIN_MEAN 20
|
||||||
|
#define EGIS0570_MARGIN 3
|
||||||
|
|
||||||
|
#define EGIS0570_RESIZE 2
|
||||||
|
|
||||||
|
#endif
|
|
@ -73,9 +73,8 @@ struct _FpiDeviceElan
|
||||||
/* end commands */
|
/* end commands */
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
|
gboolean active;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
FpImageDeviceState dev_state;
|
|
||||||
FpImageDeviceState dev_state_next;
|
|
||||||
unsigned char *last_read;
|
unsigned char *last_read;
|
||||||
unsigned char calib_atts_left;
|
unsigned char calib_atts_left;
|
||||||
unsigned char calib_status;
|
unsigned char calib_status;
|
||||||
|
@ -87,8 +86,6 @@ struct _FpiDeviceElan
|
||||||
GSList *frames;
|
GSList *frames;
|
||||||
/* end state */
|
/* 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);
|
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -207,6 +204,7 @@ elan_save_img_frame (FpiDeviceElan *elandev)
|
||||||
|
|
||||||
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||||
unsigned short *frame = g_malloc (frame_size * sizeof (short));
|
unsigned short *frame = g_malloc (frame_size * sizeof (short));
|
||||||
|
|
||||||
elan_save_frame (elandev, frame);
|
elan_save_frame (elandev, frame);
|
||||||
unsigned int sum = 0;
|
unsigned int sum = 0;
|
||||||
|
|
||||||
|
@ -244,6 +242,7 @@ elan_process_frame_linear (unsigned short *raw_frame,
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
unsigned short min = 0xffff, max = 0;
|
unsigned short min = 0xffff, max = 0;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
if (raw_frame[i] < min)
|
if (raw_frame[i] < min)
|
||||||
|
@ -255,6 +254,7 @@ elan_process_frame_linear (unsigned short *raw_frame,
|
||||||
g_assert (max != min);
|
g_assert (max != min);
|
||||||
|
|
||||||
unsigned short px;
|
unsigned short px;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
px = raw_frame[i];
|
px = raw_frame[i];
|
||||||
|
@ -278,6 +278,7 @@ elan_process_frame_thirds (unsigned short *raw_frame,
|
||||||
|
|
||||||
unsigned short lvl0, lvl1, lvl2, lvl3;
|
unsigned short lvl0, lvl1, lvl2, lvl3;
|
||||||
unsigned short *sorted = g_malloc (frame_size * sizeof (short));
|
unsigned short *sorted = g_malloc (frame_size * sizeof (short));
|
||||||
|
|
||||||
memcpy (sorted, raw_frame, frame_size * sizeof (short));
|
memcpy (sorted, raw_frame, frame_size * sizeof (short));
|
||||||
qsort (sorted, frame_size, sizeof (short), cmp_short);
|
qsort (sorted, frame_size, sizeof (short), cmp_short);
|
||||||
lvl0 = sorted[0];
|
lvl0 = sorted[0];
|
||||||
|
@ -287,6 +288,7 @@ elan_process_frame_thirds (unsigned short *raw_frame,
|
||||||
g_free (sorted);
|
g_free (sorted);
|
||||||
|
|
||||||
unsigned short px;
|
unsigned short px;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
px = raw_frame[i];
|
px = raw_frame[i];
|
||||||
|
@ -320,6 +322,9 @@ elan_submit_image (FpImageDevice *dev)
|
||||||
g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
|
g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, frames);
|
fpi_do_movement_estimation (&assembling_ctx, frames);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, frames);
|
img = fpi_assemble_frames (&assembling_ctx, frames);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
|
|
||||||
|
g_slist_free_full (frames, g_free);
|
||||||
|
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
}
|
}
|
||||||
|
@ -479,7 +484,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
|
|
||||||
|
|
||||||
/* The device is inactive at this point. */
|
/* The device is inactive at this point. */
|
||||||
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
self->active = FALSE;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (self->deactivating)
|
||||||
{
|
{
|
||||||
|
@ -497,16 +502,15 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elan_stop_capture (FpDevice *dev)
|
elan_stop_capture (FpiDeviceElan *self)
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
|
|
||||||
FpiSsm *ssm =
|
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);
|
fpi_ssm_start (ssm, stop_capture_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,8 +540,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE;
|
|
||||||
|
|
||||||
/* 0x55 - finger present
|
/* 0x55 - finger present
|
||||||
* 0xff - device not calibrated (probably) */
|
* 0xff - device not calibrated (probably) */
|
||||||
if (self->last_read && self->last_read[0] == 0x55)
|
if (self->last_read && self->last_read[0] == 0x55)
|
||||||
|
@ -547,6 +549,10 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
|
||||||
|
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
else
|
||||||
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -579,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
/* XXX: cancellation was specially handled by doing nothing! */
|
|
||||||
|
|
||||||
/* either max frames captured or timed out waiting for the next frame */
|
/* either max frames captured or timed out waiting for the next frame */
|
||||||
if (!error ||
|
if (!error ||
|
||||||
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
|
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
|
||||||
|
@ -603,18 +607,22 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
fpi_image_device_session_error (dev, 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
|
static void
|
||||||
elan_capture (FpDevice *dev)
|
elan_capture (FpiDeviceElan *self)
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
FpiSsm *ssm =
|
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);
|
fpi_ssm_start (ssm, capture_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,7 +737,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
fp_dbg ("calibration failed");
|
fp_dbg ("calibration failed");
|
||||||
fpi_ssm_mark_failed (ssm,
|
fpi_ssm_mark_failed (ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||||
"Callibration failed!"));
|
"Calibration failed!"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -752,7 +760,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
if (self->calib_status == 0x00 &&
|
if (self->calib_status == 0x00 &&
|
||||||
self->last_read[0] == 0x01)
|
self->last_read[0] == 0x01)
|
||||||
self->calib_status = 0x01;
|
self->calib_status = 0x01;
|
||||||
fpi_ssm_next_state_delayed (ssm, 50, NULL);
|
fpi_ssm_next_state_delayed (ssm, 50);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -765,34 +773,33 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
static void
|
static void
|
||||||
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
|
||||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||||
|
elan_stop_capture (FPI_DEVICE_ELAN (dev));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elan_capture (dev);
|
elan_capture (FPI_DEVICE_ELAN (dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elan_calibrate (FpDevice *dev)
|
elan_calibrate (FpiDeviceElan *self)
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
|
|
||||||
|
g_return_if_fail (!self->active);
|
||||||
|
self->active = TRUE;
|
||||||
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
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);
|
CALIBRATE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, calibrate_complete);
|
fpi_ssm_start (ssm, calibrate_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,6 +895,7 @@ elan_activate (FpImageDevice *dev)
|
||||||
FpiSsm *ssm =
|
FpiSsm *ssm =
|
||||||
fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, activate_complete);
|
fpi_ssm_start (ssm, activate_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,94 +953,18 @@ dev_activate (FpImageDevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elan_change_state (FpImageDevice *idev)
|
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
{
|
|
||||||
FpDevice *dev = FP_DEVICE (idev);
|
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
|
||||||
FpImageDeviceState 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 FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
|
||||||
/* activation completed or another enroll stage started */
|
|
||||||
self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
|
||||||
elan_calibrate (dev);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FP_IMAGE_DEVICE_STATE_CAPTURE:
|
|
||||||
/* not used */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FP_IMAGE_DEVICE_STATE_INACTIVE:
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
|
||||||
elan_stop_capture (dev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
elan_change_state_async (FpDevice *dev,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
g_message ("state change dev: %p", dev);
|
|
||||||
elan_change_state (FP_IMAGE_DEVICE (dev));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
|
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
GSource *timeout;
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
/* Inactive and await finger off are equivalent for the elan driver. */
|
/* Note: We always calibrate even if that may not be needed always.
|
||||||
if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
* Doing this for each capture appears to make it at least less likely for
|
||||||
state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
* devices to end up in a bad state.
|
||||||
|
*/
|
||||||
if (self->dev_state_next == state)
|
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
fp_dbg ("change to state %d already queued", state);
|
elan_calibrate (self);
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case FP_IMAGE_DEVICE_STATE_INACTIVE:
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
|
||||||
case FP_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 FP_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 ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1042,19 +974,14 @@ dev_deactivate (FpImageDevice *dev)
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
if (!self->active)
|
||||||
{
|
|
||||||
/* The device is inactive already, complete the operation immediately. */
|
/* The device is inactive already, complete the operation immediately. */
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
/* The device is not yet inactive, flag that we are deactivating (and
|
/* The device is not yet inactive, flag that we are deactivating (and
|
||||||
* need to signal back deactivation) and then ensure we will change
|
* need to signal back deactivation).
|
||||||
* to the inactive state eventually. */
|
* Note that any running capture will be cancelled already if needed. */
|
||||||
self->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ELAN_H
|
#pragma once
|
||||||
#define __ELAN_H
|
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
@ -71,6 +70,9 @@
|
||||||
#define ELAN_CMD_TIMEOUT 10000
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
#define ELAN_FINGER_TIMEOUT 200
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
||||||
|
FpImageDevice);
|
||||||
|
|
||||||
struct elan_cmd
|
struct elan_cmd
|
||||||
{
|
{
|
||||||
unsigned char cmd[ELAN_CMD_LEN];
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
|
@ -211,7 +213,13 @@ static const FpIdEntry elan_id_table[] = {
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
{.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 = 0x0c33, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -219,10 +227,8 @@ static void elan_cmd_done (FpiSsm *ssm);
|
||||||
static void elan_cmd_read (FpiSsm *ssm,
|
static void elan_cmd_read (FpiSsm *ssm,
|
||||||
FpDevice *dev);
|
FpDevice *dev);
|
||||||
|
|
||||||
static void elan_calibrate (FpDevice *dev);
|
static void elan_calibrate (FpiDeviceElan *self);
|
||||||
static void elan_capture (FpDevice *dev);
|
static void elan_capture (FpiDeviceElan *self);
|
||||||
|
|
||||||
static void dev_change_state (FpImageDevice *dev,
|
static void dev_change_state (FpImageDevice *dev,
|
||||||
FpImageDeviceState state);
|
FpiImageDeviceState state);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
1139
libfprint/drivers/elanmoc/elanmoc.c
Normal file
1139
libfprint/drivers/elanmoc/elanmoc.c
Normal file
File diff suppressed because it is too large
Load diff
195
libfprint/drivers/elanmoc/elanmoc.h
Normal file
195
libfprint/drivers/elanmoc/elanmoc.h
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Elan Microelectronics
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-device.h"
|
||||||
|
#include "fpi-ssm.h"
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FPI, DEVICE_ELANMOC, FpDevice)
|
||||||
|
|
||||||
|
#define ELAN_MOC_DRIVER_FULLNAME "Elan MOC Sensors"
|
||||||
|
#define ELAN_M0C_CMD_LEN 0x3
|
||||||
|
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
||||||
|
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
||||||
|
#define ELAN_EP_MOC_CMD_IN (0x4 | LIBUSB_ENDPOINT_IN)
|
||||||
|
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
||||||
|
|
||||||
|
#define ELAN_MOC_CMD_TIMEOUT 5000
|
||||||
|
#define ELAN_MOC_CAL_RETRY 500
|
||||||
|
#define ELAN_MOC_ENROLL_TIMES 9
|
||||||
|
#define ELAN_MAX_USER_ID_LEN 92
|
||||||
|
#define ELAN_MAX_ENROLL_NUM 9
|
||||||
|
|
||||||
|
#define ELAN_MSG_VERIFY_ERR 0xfd
|
||||||
|
#define ELAN_MSG_DIRTY 0xfb
|
||||||
|
#define ELAN_MSG_AREA_NOT_ENOUGH 0xfe
|
||||||
|
#define ELAN_MSG_TOO_HIGH 0x41
|
||||||
|
#define ELAN_MSG_TOO_LEFT 0x42
|
||||||
|
#define ELAN_MSG_TOO_LOW 0x43
|
||||||
|
#define ELAN_MSG_TOO_RIGHT 0x44
|
||||||
|
#define ELAN_MSG_OK 0x00
|
||||||
|
|
||||||
|
#define ELAN_MAX_HDR_LEN 3
|
||||||
|
#define ELAN_USERDATE_SIZE (ELAN_MAX_USER_ID_LEN + 3)
|
||||||
|
|
||||||
|
#define ELAN_MSG_DRIVER_VERSION "1004"
|
||||||
|
|
||||||
|
struct elanmoc_cmd
|
||||||
|
{
|
||||||
|
unsigned char cmd_header[ELAN_MAX_HDR_LEN];
|
||||||
|
int cmd_len;
|
||||||
|
int resp_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd fw_ver_cmd = {
|
||||||
|
.cmd_header = {0x40, 0x19},
|
||||||
|
.cmd_len = 2,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd sensor_dim_cmd = {
|
||||||
|
.cmd_header = {0x00, 0x0c},
|
||||||
|
.cmd_len = 2,
|
||||||
|
.resp_len = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd cal_status_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x00},
|
||||||
|
.cmd_len = 3,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd enrolled_number_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x04},
|
||||||
|
.cmd_len = 3,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_verify_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x73},
|
||||||
|
.cmd_len = 5,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_above_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x02},
|
||||||
|
.cmd_len = 3,
|
||||||
|
.resp_len = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_enroll_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x01},
|
||||||
|
.cmd_len = 7,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_delete_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x13},
|
||||||
|
.cmd_len = 128,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_enroll_commit_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x11},
|
||||||
|
.cmd_len = 128,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_remove_all_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x98},
|
||||||
|
.cmd_len = 3,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_get_userid_cmd = {
|
||||||
|
.cmd_header = {0x43, 0x21, 0x00},
|
||||||
|
.cmd_len = 3,
|
||||||
|
.resp_len = 97,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_set_mod_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x14},
|
||||||
|
.cmd_len = 4,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanmoc_cmd elanmoc_check_reenroll_cmd = {
|
||||||
|
.cmd_header = {0x40, 0xff, 0x22},
|
||||||
|
.cmd_len = 3 + ELAN_USERDATE_SIZE,
|
||||||
|
.resp_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ElanCmdMsgCallback) (FpiDeviceElanmoc *self,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
enum moc_enroll_states {
|
||||||
|
MOC_ENROLL_GET_ENROLLED_NUM,
|
||||||
|
MOC_ENROLL_REENROLL_CHECK,
|
||||||
|
MOC_ENROLL_WAIT_FINGER,
|
||||||
|
MOC_ENROLL_COMMIT_RESULT,
|
||||||
|
MOC_ENROLL_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum moc_list_states {
|
||||||
|
MOC_LIST_GET_ENROLLED,
|
||||||
|
MOC_LIST_GET_FINGER,
|
||||||
|
MOC_LIST_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum delete_states {
|
||||||
|
DELETE_SEND_CMD,
|
||||||
|
DELETE_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dev_init_states {
|
||||||
|
DEV_WAIT_READY,
|
||||||
|
DEV_SET_MODE,
|
||||||
|
DEV_GET_VER,
|
||||||
|
DEV_GET_DIM,
|
||||||
|
DEV_GET_ENROLLED,
|
||||||
|
DEV_INIT_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dev_exit_states {
|
||||||
|
DEV_EXIT_ABOVE,
|
||||||
|
DEV_EXIT_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _FpiDeviceElanmoc
|
||||||
|
{
|
||||||
|
FpDevice parent;
|
||||||
|
FpiSsm *task_ssm;
|
||||||
|
FpiSsm *cmd_ssm;
|
||||||
|
FpiUsbTransfer *cmd_transfer;
|
||||||
|
gboolean cmd_cancelable;
|
||||||
|
gsize cmd_len_in;
|
||||||
|
unsigned short fw_ver;
|
||||||
|
unsigned char x_trace;
|
||||||
|
unsigned char y_trace;
|
||||||
|
int num_frames;
|
||||||
|
int curr_enrolled;
|
||||||
|
int cancel_result;
|
||||||
|
int cmd_retry_cnt;
|
||||||
|
int list_index;
|
||||||
|
GPtrArray *list_result;
|
||||||
|
};
|
1700
libfprint/drivers/elanspi.c
Normal file
1700
libfprint/drivers/elanspi.c
Normal file
File diff suppressed because it is too large
Load diff
351
libfprint/drivers/elanspi.h
Normal file
351
libfprint/drivers/elanspi.h
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
/*
|
||||||
|
* Elan SPI driver for libfprint
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
|
||||||
|
*
|
||||||
|
* 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 <config.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_UDEV
|
||||||
|
#error "elanspi requires udev"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fp-device.h>
|
||||||
|
#include <fpi-device.h>
|
||||||
|
|
||||||
|
#define ELANSPI_TP_PID 0x04f3
|
||||||
|
|
||||||
|
/* Sensor ID information copied from the windows driver */
|
||||||
|
|
||||||
|
struct elanspi_sensor_entry
|
||||||
|
{
|
||||||
|
unsigned char sensor_id, height, width, ic_version;
|
||||||
|
gboolean is_otp_model;
|
||||||
|
const gchar * name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_sensor_entry elanspi_sensor_table[] = {
|
||||||
|
{0x0, 0x78, 0x78, 0x0, 0x0, "eFSA120S"},
|
||||||
|
{0x1, 0x78, 0x78, 0x1, 0x1, "eFSA120SA"},
|
||||||
|
{0x2, 0xA0, 0xA0, 0x0, 0x0, "eFSA160S"},
|
||||||
|
{0x3, 0xd0, 0x50, 0x0, 0x0, "eFSA820R"},
|
||||||
|
{0x4, 0xC0, 0x38, 0x0, 0x0, "eFSA519R"},
|
||||||
|
{0x5, 0x60, 0x60, 0x0, 0x0, "eFSA96S"},
|
||||||
|
{0x6, 0x60, 0x60, 0x1, 0x1, "eFSA96SA"},
|
||||||
|
{0x7, 0x60, 0x60, 0x2, 0x1, "eFSA96SB"},
|
||||||
|
{0x8, 0xa0, 0x50, 0x1, 0x1, "eFSA816RA"},
|
||||||
|
{0x9, 0x90, 0x40, 0x1, 0x1, "eFSA614RA"},
|
||||||
|
{0xA, 0x90, 0x40, 0x2, 0x1, "eFSA614RB"},
|
||||||
|
{0xB, 0x40, 0x58, 0x1, 0x1, "eFSA688RA"},
|
||||||
|
{0xC, 0x50, 0x50, 0x1, 0x0, "eFSA80SA"},
|
||||||
|
{0xD, 0x47, 0x80, 0x1, 0x1, "eFSA712RA"},
|
||||||
|
{0xE, 0x50, 0x50, 0x2, 0x0, "eFSA80SC"},
|
||||||
|
{0, 0, 0, 0, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct elanspi_reg_entry
|
||||||
|
{
|
||||||
|
unsigned char addr, value;
|
||||||
|
/* terminates with 0xFF, 0xFF since register 0x0 is valid */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct elanspi_regtable
|
||||||
|
{
|
||||||
|
const struct elanspi_reg_entry *other;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char sid;
|
||||||
|
const struct elanspi_reg_entry *table;
|
||||||
|
} entries[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
|
||||||
|
{0x05, 0x60},
|
||||||
|
{0x06, 0xc0},
|
||||||
|
{0x07, 0x80},
|
||||||
|
{0x08, 0x04},
|
||||||
|
{0x0a, 0x97},
|
||||||
|
{0x0b, 0x72},
|
||||||
|
{0x0c, 0x69},
|
||||||
|
{0x0f, 0x2a},
|
||||||
|
{0x11, 0x2a},
|
||||||
|
{0x13, 0x27},
|
||||||
|
{0x15, 0x67},
|
||||||
|
{0x18, 0x04},
|
||||||
|
{0x21, 0x20},
|
||||||
|
{0x22, 0x36},
|
||||||
|
{0x2a, 0x5f},
|
||||||
|
{0x2b, 0xc0},
|
||||||
|
{0x2e, 0xff},
|
||||||
|
|
||||||
|
{0xff, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = {
|
||||||
|
{0x2A, 0x07},
|
||||||
|
{0x5, 0x60},
|
||||||
|
{0x6, 0xC0},
|
||||||
|
{0x7, 0x80},
|
||||||
|
{0x8, 0x04},
|
||||||
|
{0xA, 0x97},
|
||||||
|
{0xB, 0x72},
|
||||||
|
{0xC, 0x69},
|
||||||
|
{0xF, 0x2A},
|
||||||
|
{0x11, 0x2A},
|
||||||
|
{0x13, 0x27},
|
||||||
|
{0x15, 0x67},
|
||||||
|
{0x18, 0x04},
|
||||||
|
{0x21, 0x20},
|
||||||
|
{0x22, 0x36},
|
||||||
|
{0x2A, 0x5F},
|
||||||
|
{0x2B, 0xC0},
|
||||||
|
{0x2E, 0xFF},
|
||||||
|
|
||||||
|
{0xff, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_reg_entry elanspi_calibration_table_id0[] = {
|
||||||
|
{0x5, 0x60},
|
||||||
|
{0x6, 0xC0},
|
||||||
|
{0x8, 0x04},
|
||||||
|
{0xA, 0x97},
|
||||||
|
{0xB, 0x72},
|
||||||
|
{0xC, 0x69},
|
||||||
|
{0xF, 0x2B},
|
||||||
|
{0x11, 0x2B},
|
||||||
|
{0x13, 0x28},
|
||||||
|
{0x15, 0x28},
|
||||||
|
{0x18, 0x04},
|
||||||
|
{0x21, 0x20},
|
||||||
|
{0x2A, 0x4B},
|
||||||
|
|
||||||
|
{0xff, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
// old style sensor calibration, with only one page of registers
|
||||||
|
static const struct elanspi_regtable elanspi_calibration_table_old = {
|
||||||
|
.other = elanspi_calibration_table_default,
|
||||||
|
.entries = {
|
||||||
|
{ .sid = 0x0, .table = elanspi_calibration_table_id0 },
|
||||||
|
{ .sid = 0x5, .table = elanspi_calibration_table_id567 },
|
||||||
|
{ .sid = 0x6, .table = elanspi_calibration_table_id567 },
|
||||||
|
{ .sid = 0x7, .table = elanspi_calibration_table_id567 },
|
||||||
|
{ .sid = 0x0, .table = NULL }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// new style sensor calibration, with two pages of registers
|
||||||
|
static const struct elanspi_reg_entry elanspi_calibration_table_page0_id14[] = {
|
||||||
|
{0x00, 0x5a},
|
||||||
|
{0x01, 0x00},
|
||||||
|
{0x02, 0x4f},
|
||||||
|
{0x03, 0x00},
|
||||||
|
{0x04, 0x4f},
|
||||||
|
{0x05, 0xa0},
|
||||||
|
{0x06, 0x00},
|
||||||
|
{0x07, 0x00},
|
||||||
|
{0x08, 0x00},
|
||||||
|
{0x09, 0x04},
|
||||||
|
{0x0a, 0x74},
|
||||||
|
{0x0b, 0x05},
|
||||||
|
{0x0c, 0x08},
|
||||||
|
{0x0d, 0x00},
|
||||||
|
{0x0e, 0x00},
|
||||||
|
{0x0f, 0x14},
|
||||||
|
{0x10, 0x3c},
|
||||||
|
{0x11, 0x41},
|
||||||
|
{0x12, 0x0c},
|
||||||
|
{0x13, 0x00},
|
||||||
|
{0x14, 0x00},
|
||||||
|
{0x15, 0x04},
|
||||||
|
{0x16, 0x02},
|
||||||
|
{0x17, 0x00},
|
||||||
|
{0x18, 0x01},
|
||||||
|
{0x19, 0xf4},
|
||||||
|
{0x1a, 0x00},
|
||||||
|
{0x1b, 0x00},
|
||||||
|
{0x1c, 0x00},
|
||||||
|
{0x1d, 0x00},
|
||||||
|
{0x1e, 0x00},
|
||||||
|
{0x1f, 0x00},
|
||||||
|
{0x20, 0x00},
|
||||||
|
{0x21, 0x80},
|
||||||
|
{0x22, 0x06},
|
||||||
|
{0x23, 0x00},
|
||||||
|
{0x24, 0x00},
|
||||||
|
{0x25, 0x00},
|
||||||
|
{0x26, 0x00},
|
||||||
|
{0x27, 0x00},
|
||||||
|
{0x28, 0x00},
|
||||||
|
{0x29, 0x04},
|
||||||
|
{0x2a, 0x5f},
|
||||||
|
{0x2b, 0xe2},
|
||||||
|
{0x2c, 0xa0},
|
||||||
|
{0x2d, 0x00},
|
||||||
|
{0x2e, 0xff},
|
||||||
|
{0x2f, 0x40},
|
||||||
|
{0x30, 0x01},
|
||||||
|
{0x31, 0x38},
|
||||||
|
{0x32, 0x00},
|
||||||
|
{0x33, 0x00},
|
||||||
|
{0x34, 0x00},
|
||||||
|
{0x35, 0x1f},
|
||||||
|
{0x36, 0xff},
|
||||||
|
{0x37, 0x00},
|
||||||
|
{0x38, 0x00},
|
||||||
|
{0x39, 0x00},
|
||||||
|
{0x3a, 0x00},
|
||||||
|
{0xff, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_reg_entry elanspi_calibration_table_page1_id14[] = {
|
||||||
|
{0x00, 0x7b},
|
||||||
|
{0x01, 0x7f},
|
||||||
|
{0x02, 0x77},
|
||||||
|
{0x03, 0xd4},
|
||||||
|
{0x04, 0x7d},
|
||||||
|
{0x05, 0x19},
|
||||||
|
{0x06, 0x80},
|
||||||
|
{0x07, 0x40},
|
||||||
|
{0x08, 0x11},
|
||||||
|
{0x09, 0x00},
|
||||||
|
{0x0a, 0x00},
|
||||||
|
{0x0b, 0x14},
|
||||||
|
{0x0c, 0x00},
|
||||||
|
{0x0d, 0x00},
|
||||||
|
{0x0e, 0x32},
|
||||||
|
{0x0f, 0x02},
|
||||||
|
{0x10, 0x08},
|
||||||
|
{0x11, 0x6c},
|
||||||
|
{0x12, 0x00},
|
||||||
|
{0x13, 0x00},
|
||||||
|
{0x14, 0x32},
|
||||||
|
{0x15, 0x01},
|
||||||
|
{0x16, 0x16},
|
||||||
|
{0x17, 0x01},
|
||||||
|
{0x18, 0x14},
|
||||||
|
{0x19, 0x01},
|
||||||
|
{0x1a, 0x16},
|
||||||
|
{0x1b, 0x01},
|
||||||
|
{0x1c, 0x17},
|
||||||
|
{0x1d, 0x01},
|
||||||
|
{0x1e, 0x0a},
|
||||||
|
{0x1f, 0x01},
|
||||||
|
{0x20, 0x0a},
|
||||||
|
{0x21, 0x02},
|
||||||
|
{0x22, 0x08},
|
||||||
|
{0x23, 0x29},
|
||||||
|
{0x24, 0x00},
|
||||||
|
{0x25, 0x0c},
|
||||||
|
{0x26, 0x1a},
|
||||||
|
{0x27, 0x30},
|
||||||
|
{0x28, 0x1a},
|
||||||
|
{0x29, 0x30},
|
||||||
|
{0x2a, 0x00},
|
||||||
|
{0x2b, 0x00},
|
||||||
|
{0x2c, 0x01},
|
||||||
|
{0x2d, 0x16},
|
||||||
|
{0x2e, 0x01},
|
||||||
|
{0x2f, 0x17},
|
||||||
|
{0x30, 0x03},
|
||||||
|
{0x31, 0x2d},
|
||||||
|
{0x32, 0x03},
|
||||||
|
{0x33, 0x2d},
|
||||||
|
{0x34, 0x14},
|
||||||
|
{0x35, 0x00},
|
||||||
|
{0x36, 0x00},
|
||||||
|
{0x37, 0x00},
|
||||||
|
{0x38, 0x00},
|
||||||
|
{0x39, 0x03},
|
||||||
|
{0x3a, 0xfe},
|
||||||
|
{0x3b, 0x00},
|
||||||
|
{0x3c, 0x00},
|
||||||
|
{0x3d, 0x02},
|
||||||
|
{0x3e, 0x00},
|
||||||
|
{0x3f, 0x00},
|
||||||
|
{0xff, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_regtable elanspi_calibration_table_new_page0 = {
|
||||||
|
.other = NULL,
|
||||||
|
.entries = {
|
||||||
|
{ .sid = 0xe, .table = elanspi_calibration_table_page0_id14 },
|
||||||
|
{ .sid = 0x0, .table = NULL }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {
|
||||||
|
.other = NULL,
|
||||||
|
.entries = {
|
||||||
|
{ .sid = 0xe, .table = elanspi_calibration_table_page1_id14 },
|
||||||
|
{ .sid = 0x0, .table = NULL }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ELANSPI_NO_ROTATE 0
|
||||||
|
#define ELANSPI_90LEFT_ROTATE 1
|
||||||
|
#define ELANSPI_180_ROTATE 2
|
||||||
|
#define ELANSPI_90RIGHT_ROTATE 3
|
||||||
|
|
||||||
|
#define ELANSPI_HV_FLIPPED 1
|
||||||
|
|
||||||
|
#define ELANSPI_UDEV_TYPES FPI_DEVICE_UDEV_SUBTYPE_SPIDEV | FPI_DEVICE_UDEV_SUBTYPE_HIDRAW
|
||||||
|
#define ELANSPI_TP_VID 0x04f3
|
||||||
|
|
||||||
|
// using checkargs ACPI:HIDPID
|
||||||
|
static const FpIdEntry elanspi_id_table[] = {
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3134}, .driver_data = ELANSPI_90LEFT_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3148}, .driver_data = ELANSPI_180_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
||||||
|
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE},
|
||||||
|
{.udev_types = 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN 1000
|
||||||
|
|
||||||
|
#define ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN 3000
|
||||||
|
#define ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN 8000
|
||||||
|
|
||||||
|
#define ELANSPI_HV_CALIBRATION_TARGET_MEAN 3000
|
||||||
|
|
||||||
|
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
|
||||||
|
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3
|
||||||
|
|
||||||
|
#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
|
||||||
|
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
|
||||||
|
|
||||||
|
#define ELANSPI_MIN_FRAMES_DEBOUNCE 2
|
||||||
|
|
||||||
|
#define ELANSPI_SWIPE_FRAMES_DISCARD 1
|
||||||
|
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
||||||
|
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
||||||
|
|
||||||
|
#define ELANSPI_MAX_FRAME_HEIGHT 43
|
||||||
|
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
|
||||||
|
|
||||||
|
#define ELANSPI_HV_SENSOR_FRAME_DELAY 23
|
||||||
|
|
||||||
|
#define ELANSPI_OTP_TIMEOUT_USEC (12 * 1000)
|
||||||
|
|
||||||
|
#define ELANSPI_OLD_CAPTURE_TIMEOUT_USEC (100 * 1000)
|
||||||
|
#define ELANSPI_HV_CAPTURE_TIMEOUT_USEC (50 * 1000)
|
|
@ -36,7 +36,6 @@
|
||||||
#define FP_COMPONENT "etes603"
|
#define FP_COMPONENT "etes603"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
/* libusb defines */
|
/* libusb defines */
|
||||||
#define EP_IN 0x81
|
#define EP_IN 0x81
|
||||||
|
@ -860,13 +859,15 @@ m_capture_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FpImage *img;
|
|
||||||
unsigned int img_size;
|
|
||||||
/* Remove empty parts 2 times for the 2 frames */
|
/* Remove empty parts 2 times for the 2 frames */
|
||||||
process_removefpi_end (self);
|
process_removefpi_end (self);
|
||||||
process_removefpi_end (self);
|
process_removefpi_end (self);
|
||||||
img_size = self->fp_height * FE_WIDTH;
|
|
||||||
img = fp_image_new (FE_WIDTH, self->fp_height);
|
if (self->fp_height >= FE_WIDTH)
|
||||||
|
{
|
||||||
|
FpImage *img = fp_image_new (FE_WIDTH, self->fp_height);
|
||||||
|
unsigned int img_size = self->fp_height * FE_WIDTH;
|
||||||
|
|
||||||
/* Images received are white on black, so invert it. */
|
/* Images received are white on black, so invert it. */
|
||||||
/* TODO detect sweep direction */
|
/* TODO detect sweep direction */
|
||||||
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
|
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
|
||||||
|
@ -875,6 +876,12 @@ m_capture_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
fp_dbg ("Sending the raw fingerprint image (%dx%d)",
|
fp_dbg ("Sending the raw fingerprint image (%dx%d)",
|
||||||
img->width, img->height);
|
img->width, img->height);
|
||||||
fpi_image_device_image_captured (idev, img);
|
fpi_image_device_image_captured (idev, img);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fpi_image_device_retry_scan (idev, FP_DEVICE_RETRY_TOO_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (idev, FALSE);
|
fpi_image_device_report_finger_status (idev, FALSE);
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
}
|
}
|
||||||
|
|
1583
libfprint/drivers/goodixmoc/goodix.c
Normal file
1583
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);
|
445
libfprint/drivers/nb1010.c
Normal file
445
libfprint/drivers/nb1010.c
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
/*
|
||||||
|
* Next Biometrics driver for libfprint
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Huan Wang <fredwanghuan@gmail.com>
|
||||||
|
* Copyright (C) 2011-2012 Andrej Krutak <dev@andree.sk>
|
||||||
|
*
|
||||||
|
* 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 "nb1010"
|
||||||
|
#include "fpi-log.h"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
|
||||||
|
#define FRAME_HEIGHT 180
|
||||||
|
#define FRAME_WIDTH 256
|
||||||
|
|
||||||
|
#define NB1010_EP_OUT 0x02 | FPI_USB_ENDPOINT_OUT
|
||||||
|
#define NB1010_EP_IN 0x03 | FPI_USB_ENDPOINT_IN
|
||||||
|
|
||||||
|
#define NB1010_SENSITIVITY_BIT 12
|
||||||
|
|
||||||
|
#define NB1010_CMD_RECV_LEN 16
|
||||||
|
#define NB1010_CAPTURE_RECV_LEN 540
|
||||||
|
#define NB1010_CAPTURE_HEADER_LEN 25
|
||||||
|
|
||||||
|
#define NB1010_LINE_PER_PARTIAL 2
|
||||||
|
#define NB1010_N_PARTIAL (FRAME_HEIGHT / NB1010_LINE_PER_PARTIAL)
|
||||||
|
|
||||||
|
#define NB1010_DEFAULT_TIMEOUT 500
|
||||||
|
#define NB1010_TRANSITION_DELAY 50
|
||||||
|
|
||||||
|
/* Loop ssm states */
|
||||||
|
enum {
|
||||||
|
M_WAIT_PRINT,
|
||||||
|
M_REQUEST_PRINT,
|
||||||
|
M_CHECK_PRINT,
|
||||||
|
M_READ_PRINT_PRESTART,
|
||||||
|
M_READ_PRINT_START,
|
||||||
|
M_READ_PRINT_POLL,
|
||||||
|
M_SUBMIT_PRINT,
|
||||||
|
|
||||||
|
/* Number of states */
|
||||||
|
M_LOOP_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Follow Commands are obtained by decoding the usbcap, so it does not expose all the command available to the device.
|
||||||
|
* Known:
|
||||||
|
* 1. every command starts with 0x80
|
||||||
|
* 2. second byte is the comand, third byte is the seqence nubmer, init with rand, gets incremented
|
||||||
|
* everytime a new instruction is sent to the device. However device does not care or check the sequence, just echo back
|
||||||
|
* whatever chosen by the host.
|
||||||
|
* 3. cmd: 0x07 check, expect [0x80, 0x29...] as response
|
||||||
|
* 4. cmd: 0x16 ???, expect [0x80, 0x20...] as response. Happens during device init.
|
||||||
|
* 5. cmd: 0x13 print device, expect [0x80, 0x23...] as response. Response contains the device string
|
||||||
|
* 6. cmd: 0x38 check finger, expect [0x80, 0x37...] as response. The 14th byte indicate whether finger present [0-255]
|
||||||
|
* 7. cmd: 0x0d ???, expect [0x80, 0x20...] as response. Happens before capture.
|
||||||
|
* 8. cmd: 0x12 capture, expect [0x80, 0x20...] as response. After capture read 90 times in sequence to get all the frame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static guint8 nb1010_cmd_check_finger[] = {
|
||||||
|
0x80, 0x38, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pre capture, dont know what does it do, but appears everytime a capture begins */
|
||||||
|
static guint8 nb1010_cmd_precapture[] = {
|
||||||
|
0x80, 0x0d, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 nb1010_cmd_capture[] = {
|
||||||
|
0x80, 0x12, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _FpiDeviceNb1010
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
FpiSsm *ssm;
|
||||||
|
guint8 *scanline_buf;
|
||||||
|
gboolean deactivating;
|
||||||
|
int partial_received;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FPI, DEVICE_NB1010, FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_init (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
|
|
||||||
|
self->scanline_buf = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT);
|
||||||
|
|
||||||
|
fpi_image_device_open_complete (dev, error);
|
||||||
|
fp_dbg ("nb1010 Initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_deinit (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_clear_pointer (&self->scanline_buf, g_free);
|
||||||
|
|
||||||
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
|
fp_dbg ("nb1010 Deinitialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_activate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
|
||||||
|
self->deactivating = FALSE;
|
||||||
|
|
||||||
|
fpi_image_device_activate_complete (dev, NULL);
|
||||||
|
fp_dbg ("nb1010 Activated");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_deactivated (FpImageDevice *dev, GError * err)
|
||||||
|
{
|
||||||
|
fpi_image_device_deactivate_complete (dev, err);
|
||||||
|
fp_dbg ("nb1010 Deactivated");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_deactivate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
|
||||||
|
self->deactivating = TRUE;
|
||||||
|
if (self->ssm == NULL)
|
||||||
|
nb1010_dev_deactivated (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_request_fingerprint (FpiDeviceNb1010 *dev)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = NULL;
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
transfer->ssm = dev->ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT,
|
||||||
|
nb1010_cmd_check_finger, G_N_ELEMENTS (nb1010_cmd_check_finger),
|
||||||
|
NULL);
|
||||||
|
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_check_fingerprint_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
|
gpointer unused_data, GError *error)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer->buffer[NB1010_SENSITIVITY_BIT] > 0x30)
|
||||||
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
else
|
||||||
|
fpi_ssm_jump_to_state (transfer->ssm, M_WAIT_PRINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_cmd_check_fingerprint (FpiDeviceNb1010 *dev)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = NULL;
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
transfer->ssm = dev->ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
|
||||||
|
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
nb1010_check_fingerprint_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_read_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
|
gpointer unused_data, GError *error)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
FpiUsbTransfer *new_transfer = NULL;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_transfer = fpi_usb_transfer_new ( dev );
|
||||||
|
new_transfer->short_is_error = TRUE;
|
||||||
|
new_transfer->ssm = transfer->ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (new_transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
|
||||||
|
fpi_usb_transfer_submit (new_transfer, NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_write_ignore_read (FpiDeviceNb1010 *dev, guint8 *buf, gsize len)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = NULL;
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
transfer->ssm = dev->ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT, buf, len, NULL);
|
||||||
|
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
nb1010_read_ignore_data_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_read_capture_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
|
gpointer unused_data, GError *error)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (transfer->actual_length == NB1010_CAPTURE_RECV_LEN);
|
||||||
|
|
||||||
|
size_t offset = self->partial_received * NB1010_LINE_PER_PARTIAL * FRAME_WIDTH;
|
||||||
|
|
||||||
|
memcpy (self->scanline_buf + offset,
|
||||||
|
transfer->buffer + NB1010_CAPTURE_HEADER_LEN, NB1010_LINE_PER_PARTIAL * FRAME_WIDTH);
|
||||||
|
|
||||||
|
self->partial_received++;
|
||||||
|
if (self->partial_received == NB1010_N_PARTIAL)
|
||||||
|
{
|
||||||
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
nb1010_read_capture_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_read_capture (FpiDeviceNb1010 *dev)
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *transfer = NULL;
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new ( FP_DEVICE ( dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
transfer->ssm = dev->ssm;
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CAPTURE_RECV_LEN);
|
||||||
|
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
nb1010_read_capture_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
submit_image (FpiSsm *ssm,
|
||||||
|
FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
FpImage *img;
|
||||||
|
|
||||||
|
img = fp_image_new (FRAME_WIDTH, FRAME_HEIGHT);
|
||||||
|
if (img == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy (img->data, self->scanline_buf, FRAME_WIDTH * FRAME_HEIGHT);
|
||||||
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
|
{
|
||||||
|
fp_dbg ("nb1010 ssm complete cb");
|
||||||
|
|
||||||
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
|
||||||
|
|
||||||
|
self->ssm = NULL;
|
||||||
|
|
||||||
|
if (self->deactivating)
|
||||||
|
nb1010_dev_deactivated (dev, error);
|
||||||
|
else if (error != NULL)
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
{
|
||||||
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
|
||||||
|
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fp_dbg ("deactivating, marking completed");
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
|
case M_WAIT_PRINT:
|
||||||
|
/* Wait fingerprint scanning */
|
||||||
|
fpi_ssm_next_state_delayed (ssm, NB1010_TRANSITION_DELAY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_REQUEST_PRINT:
|
||||||
|
nb1010_request_fingerprint (self);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_CHECK_PRINT:
|
||||||
|
nb1010_cmd_check_fingerprint (self);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_READ_PRINT_PRESTART:
|
||||||
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
|
nb1010_write_ignore_read (self, nb1010_cmd_precapture, G_N_ELEMENTS (nb1010_cmd_precapture));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_READ_PRINT_START:
|
||||||
|
self->partial_received = 0;
|
||||||
|
nb1010_write_ignore_read (self, nb1010_cmd_capture, G_N_ELEMENTS (nb1010_cmd_capture));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_READ_PRINT_POLL:
|
||||||
|
nb1010_read_capture (self);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_SUBMIT_PRINT:
|
||||||
|
if (submit_image (ssm, dev))
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
|
{
|
||||||
|
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
||||||
|
FpiSsm *ssm_loop;
|
||||||
|
|
||||||
|
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
|
{
|
||||||
|
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
|
||||||
|
self->ssm = ssm_loop;
|
||||||
|
fpi_ssm_start (ssm_loop, m_loop_complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const FpIdEntry id_table[] = {
|
||||||
|
{ .vid = 0x298d, .pid = 0x1010, },
|
||||||
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_nb1010_init (FpiDeviceNb1010 *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = FP_COMPONENT;
|
||||||
|
dev_class->full_name = "NextBiometrics NB-1010-U";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||||
|
|
||||||
|
img_class->img_height = FRAME_HEIGHT;
|
||||||
|
img_class->img_width = FRAME_WIDTH;
|
||||||
|
|
||||||
|
img_class->bz3_threshold = 24;
|
||||||
|
|
||||||
|
img_class->img_open = nb1010_dev_init;
|
||||||
|
img_class->img_close = nb1010_dev_deinit;
|
||||||
|
img_class->activate = nb1010_dev_activate;
|
||||||
|
img_class->deactivate = nb1010_dev_deactivate;
|
||||||
|
img_class->change_state = nb1010_dev_change_state;
|
||||||
|
}
|
|
@ -17,8 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _BMKT_H_
|
#pragma once
|
||||||
#define _BMKT_H_
|
|
||||||
|
|
||||||
/**< User ID maximum length allowed */
|
/**< User ID maximum length allowed */
|
||||||
#define BMKT_MAX_USER_ID_LEN 100
|
#define BMKT_MAX_USER_ID_LEN 100
|
||||||
|
@ -228,5 +227,3 @@ typedef struct bmkt_user_id
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _BMKT_H_ */
|
|
||||||
|
|
|
@ -206,6 +206,7 @@ parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *res
|
||||||
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
||||||
{
|
{
|
||||||
if (offset >= msg_resp->payload_len)
|
if (offset >= msg_resp->payload_len)
|
||||||
|
|
|
@ -16,10 +16,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef BMKT_MESSAGE_H_
|
|
||||||
#define BMKT_MESSAGE_H_
|
|
||||||
|
|
||||||
|
|
||||||
#define BMKT_MESSAGE_HEADER_ID 0xFE
|
#define BMKT_MESSAGE_HEADER_ID 0xFE
|
||||||
#define BMKT_MESSAGE_HEADER_LEN (4)
|
#define BMKT_MESSAGE_HEADER_LEN (4)
|
||||||
|
@ -90,4 +87,3 @@ int bmkt_parse_message_header (uint8_t *resp_buf,
|
||||||
bmkt_msg_resp_t *msg_resp);
|
bmkt_msg_resp_t *msg_resp);
|
||||||
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
|
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
|
||||||
bmkt_response_t *resp);
|
bmkt_response_t *resp);
|
||||||
#endif /* BMKT_MESSAGE_H_ */
|
|
||||||
|
|
|
@ -17,9 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef _BMKT_RESPONSE_H_
|
|
||||||
#define _BMKT_RESPONSE_H_
|
|
||||||
|
|
||||||
#include "bmkt.h"
|
#include "bmkt.h"
|
||||||
|
|
||||||
|
@ -318,7 +316,7 @@ typedef struct bmkt_init_resp
|
||||||
*/
|
*/
|
||||||
typedef struct bmkt_enroll_resp
|
typedef struct bmkt_enroll_resp
|
||||||
{
|
{
|
||||||
int progress; /**< Shows current progress stutus [0-100] */
|
int progress; /**< Shows current progress status [0-100] */
|
||||||
uint8_t finger_id; /**< User's finger id [1-10] */
|
uint8_t finger_id; /**< User's finger id [1-10] */
|
||||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
|
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
|
||||||
} bmkt_enroll_resp_t;
|
} bmkt_enroll_resp_t;
|
||||||
|
@ -470,6 +468,7 @@ typedef union
|
||||||
bmkt_del_all_users_resp_t del_all_users_resp;
|
bmkt_del_all_users_resp_t del_all_users_resp;
|
||||||
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
||||||
bmkt_del_user_resp_t del_user_resp;
|
bmkt_del_user_resp_t del_user_resp;
|
||||||
|
bmkt_del_all_users_resp_t del_all_user_resp;
|
||||||
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
|
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
|
||||||
} bmkt_response_data_t;
|
} bmkt_response_data_t;
|
||||||
|
|
||||||
|
@ -485,5 +484,3 @@ typedef struct bmkt_response
|
||||||
int complete; /**< Operation completion status 1: complete / 0: not completed */
|
int complete; /**< Operation completion status 1: complete / 0: not completed */
|
||||||
bmkt_response_data_t response; /**< Operation specific response union */
|
bmkt_response_data_t response; /**< Operation specific response union */
|
||||||
} bmkt_response_t;
|
} bmkt_response_t;
|
||||||
|
|
||||||
#endif /* _BMKT_RESPONSE_H_ */
|
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SENSOR_H_
|
#pragma once
|
||||||
#define _SENSOR_H_
|
|
||||||
|
|
||||||
#include "usb_transport.h"
|
#include "usb_transport.h"
|
||||||
#define BMKT_MAX_PENDING_SESSIONS 2
|
#define BMKT_MAX_PENDING_SESSIONS 2
|
||||||
|
@ -84,4 +83,3 @@ int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
|
||||||
bmkt_msg_resp_t *msg_resp);
|
bmkt_msg_resp_t *msg_resp);
|
||||||
|
|
||||||
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
|
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
|
||||||
#endif /* _SENSOR_H_ */
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,8 +16,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __synaptics_h__
|
#pragma once
|
||||||
#define __synaptics_h__
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
#include "fpi-device.h"
|
||||||
#include "fpi-ssm.h"
|
#include "fpi-ssm.h"
|
||||||
|
@ -94,6 +93,8 @@ typedef enum {
|
||||||
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
||||||
SYNAPTICS_CMD_SEND_ASYNC,
|
SYNAPTICS_CMD_SEND_ASYNC,
|
||||||
SYNAPTICS_CMD_RESTART,
|
SYNAPTICS_CMD_RESTART,
|
||||||
|
SYNAPTICS_CMD_SUSPENDED,
|
||||||
|
SYNAPTICS_CMD_RESUME,
|
||||||
SYNAPTICS_CMD_NUM_STATES,
|
SYNAPTICS_CMD_NUM_STATES,
|
||||||
} SynapticsCmdState;
|
} SynapticsCmdState;
|
||||||
|
|
||||||
|
@ -111,11 +112,12 @@ struct _FpiDeviceSynaptics
|
||||||
FpiSsm *cmd_ssm;
|
FpiSsm *cmd_ssm;
|
||||||
FpiUsbTransfer *cmd_pending_transfer;
|
FpiUsbTransfer *cmd_pending_transfer;
|
||||||
gboolean cmd_complete_on_removal;
|
gboolean cmd_complete_on_removal;
|
||||||
GError *cmd_complete_error;
|
gboolean cmd_suspended;
|
||||||
void *cmd_complete_data;
|
guint8 id_idx;
|
||||||
|
|
||||||
bmkt_sensor_version_t mis_version;
|
bmkt_sensor_version_t mis_version;
|
||||||
|
|
||||||
|
gboolean action_starting;
|
||||||
GCancellable *interrupt_cancellable;
|
GCancellable *interrupt_cancellable;
|
||||||
|
|
||||||
gint enroll_stage;
|
gint enroll_stage;
|
||||||
|
@ -126,5 +128,3 @@ struct _FpiDeviceSynaptics
|
||||||
struct syna_enroll_resp_data enroll_resp_data;
|
struct syna_enroll_resp_data enroll_resp_data;
|
||||||
syna_state_t state;
|
syna_state_t state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__synaptics_h__
|
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
/*
|
/*
|
||||||
* LGPL CRC code copied from GStreamer-0.10.10:
|
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
|
||||||
|
*
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular 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; version
|
|
||||||
* 2.1 of the License.
|
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* 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
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "upek_proto.h"
|
#include "upek_proto.h"
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
/*
|
/*
|
||||||
* LGPL CRC code copied from GStreamer-0.10.10:
|
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
|
||||||
|
*
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular 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; version
|
|
||||||
* 2.1 of the License.
|
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* 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
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -47,17 +47,11 @@ enum {
|
||||||
enum sonly_kill_transfers_action {
|
enum sonly_kill_transfers_action {
|
||||||
NOT_KILLING = 0,
|
NOT_KILLING = 0,
|
||||||
|
|
||||||
/* abort a SSM with an error code */
|
|
||||||
ABORT_SSM,
|
|
||||||
|
|
||||||
/* report an image session error */
|
/* report an image session error */
|
||||||
IMG_SESSION_ERROR,
|
IMG_SESSION_ERROR,
|
||||||
|
|
||||||
/* iterate a SSM to the next state */
|
/* iterate a SSM to the next state */
|
||||||
ITERATE_SSM,
|
ITERATE_SSM,
|
||||||
|
|
||||||
/* call a callback */
|
|
||||||
EXEC_CALLBACK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sonly_fs {
|
enum sonly_fs {
|
||||||
|
@ -85,7 +79,7 @@ struct _FpiDeviceUpeksonly
|
||||||
int num_flying;
|
int num_flying;
|
||||||
|
|
||||||
GSList *rows;
|
GSList *rows;
|
||||||
size_t num_rows;
|
unsigned num_rows;
|
||||||
unsigned char *rowbuf;
|
unsigned char *rowbuf;
|
||||||
int rowbuf_offset;
|
int rowbuf_offset;
|
||||||
|
|
||||||
|
@ -97,11 +91,7 @@ struct _FpiDeviceUpeksonly
|
||||||
|
|
||||||
enum sonly_kill_transfers_action killing_transfers;
|
enum sonly_kill_transfers_action killing_transfers;
|
||||||
GError *kill_error;
|
GError *kill_error;
|
||||||
union
|
|
||||||
{
|
|
||||||
FpiSsm *kill_ssm;
|
FpiSsm *kill_ssm;
|
||||||
void (*kill_cb)(FpImageDevice *dev);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fpi_line_asmbl_ctx assembling_ctx;
|
struct fpi_line_asmbl_ctx assembling_ctx;
|
||||||
};
|
};
|
||||||
|
@ -176,11 +166,6 @@ last_transfer_killed (FpImageDevice *dev)
|
||||||
|
|
||||||
switch (self->killing_transfers)
|
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:
|
case ITERATE_SSM:
|
||||||
fp_dbg ("iterate ssm");
|
fp_dbg ("iterate ssm");
|
||||||
fpi_ssm_next_state (self->kill_ssm);
|
fpi_ssm_next_state (self->kill_ssm);
|
||||||
|
@ -191,6 +176,7 @@ last_transfer_killed (FpImageDevice *dev)
|
||||||
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
|
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case NOT_KILLING:
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +215,7 @@ handoff_img (FpImageDevice *dev)
|
||||||
|
|
||||||
self->rows = g_slist_reverse (self->rows);
|
self->rows = g_slist_reverse (self->rows);
|
||||||
|
|
||||||
fp_dbg ("%lu rows", self->num_rows);
|
fp_dbg ("%u rows", self->num_rows);
|
||||||
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
||||||
|
|
||||||
g_slist_free_full (self->rows, g_free);
|
g_slist_free_full (self->rows, g_free);
|
||||||
|
@ -309,7 +295,7 @@ row_complete (FpImageDevice *dev)
|
||||||
if (self->num_blank > FINGER_REMOVED_THRESHOLD)
|
if (self->num_blank > FINGER_REMOVED_THRESHOLD)
|
||||||
{
|
{
|
||||||
self->finger_state = FINGER_REMOVED;
|
self->finger_state = FINGER_REMOVED;
|
||||||
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %lu",
|
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %u",
|
||||||
self->num_blank, self->num_rows);
|
self->num_blank, self->num_rows);
|
||||||
handoff_img (dev);
|
handoff_img (dev);
|
||||||
return;
|
return;
|
||||||
|
@ -531,6 +517,14 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
return;
|
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)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_warn ("bad status %s, terminating session", error->message);
|
fp_warn ("bad status %s, terminating session", error->message);
|
||||||
|
@ -551,7 +545,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
* the first 2 bytes are a sequence number
|
* the first 2 bytes are a sequence number
|
||||||
* then there are 62 bytes for image data
|
* 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))
|
if (!is_capturing (self))
|
||||||
return;
|
return;
|
||||||
|
@ -560,7 +554,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (is_capturing (self))
|
if (is_capturing (self))
|
||||||
{
|
{
|
||||||
fpi_usb_transfer_submit (transfer,
|
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
||||||
0,
|
0,
|
||||||
self->img_cancellable,
|
self->img_cancellable,
|
||||||
img_data_cb,
|
img_data_cb,
|
||||||
|
@ -588,6 +582,8 @@ write_regs_finished (struct write_regs_data *wrdata, GError *error)
|
||||||
fpi_ssm_next_state (wrdata->ssm);
|
fpi_ssm_next_state (wrdata->ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_failed (wrdata->ssm, error);
|
fpi_ssm_mark_failed (wrdata->ssm, error);
|
||||||
|
|
||||||
|
g_free (wrdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_regs_iterate (struct write_regs_data *wrdata);
|
static void write_regs_iterate (struct write_regs_data *wrdata);
|
||||||
|
@ -634,9 +630,9 @@ write_regs_iterate (struct write_regs_data *wrdata)
|
||||||
1);
|
1);
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
transfer->ssm = wrdata->ssm;
|
transfer->ssm = wrdata->ssm;
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL);
|
|
||||||
|
|
||||||
transfer->buffer[0] = regwrite->value;
|
transfer->buffer[0] = regwrite->value;
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, wrdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -675,10 +671,10 @@ sm_write_reg (FpiSsm *ssm,
|
||||||
1);
|
1);
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
|
transfer->buffer[0] = value;
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
|
||||||
transfer->buffer[0] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -698,8 +694,6 @@ sm_read_reg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_dbg ("read reg result = %02x", self->read_reg_result);
|
fp_dbg ("read reg result = %02x", self->read_reg_result);
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (transfer->buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -736,7 +730,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
g_free (transfer->buffer);
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -744,7 +737,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_dbg ("interrupt received: %02x %02x %02x %02x",
|
fp_dbg ("interrupt received: %02x %02x %02x %02x",
|
||||||
transfer->buffer[0], transfer->buffer[1],
|
transfer->buffer[0], transfer->buffer[1],
|
||||||
transfer->buffer[2], transfer->buffer[3]);
|
transfer->buffer[2], transfer->buffer[3]);
|
||||||
g_free (transfer->buffer);
|
|
||||||
|
|
||||||
self->finger_state = FINGER_DETECTED;
|
self->finger_state = FINGER_DETECTED;
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
|
@ -908,7 +900,7 @@ capsm_fire_bulk (FpiSsm *ssm,
|
||||||
self->img_cancellable = g_cancellable_new ();
|
self->img_cancellable = g_cancellable_new ();
|
||||||
for (i = 0; i < self->img_transfers->len; i++)
|
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,
|
0,
|
||||||
self->img_cancellable,
|
self->img_cancellable,
|
||||||
img_data_cb,
|
img_data_cb,
|
||||||
|
@ -1406,8 +1398,12 @@ dev_activate (FpImageDevice *dev)
|
||||||
self->capturing = FALSE;
|
self->capturing = FALSE;
|
||||||
|
|
||||||
self->num_flying = 0;
|
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;
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ finger_present (unsigned char *img, size_t len, int sum_threshold)
|
||||||
if (img[i] < 160)
|
if (img[i] < 160)
|
||||||
sum++;
|
sum++;
|
||||||
|
|
||||||
fp_dbg ("finger_present: sum is %d\n", sum);
|
fp_dbg ("finger_present: sum is %d", sum);
|
||||||
return sum < sum_threshold ? 0 : 1;
|
return sum < sum_threshold ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
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);
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
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);
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Device variant %lu is not known\n", driver_data);
|
fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UPEKTC_H
|
/* *INDENT-OFF* */
|
||||||
#define __UPEKTC_H
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#define UPEKTC_CMD_LEN 0x40
|
#define UPEKTC_CMD_LEN 0x40
|
||||||
#define IMAGE_WIDTH 208
|
#define IMAGE_WIDTH 208
|
||||||
|
@ -1936,5 +1937,3 @@ static const unsigned char scan_cmd[0x40] = {
|
||||||
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
||||||
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
|
||||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||||
static void
|
static void
|
||||||
upektc_img_submit_req (FpiSsm *ssm,
|
upektc_img_submit_req (FpiSsm *ssm,
|
||||||
FpImageDevice *dev,
|
FpImageDevice *dev,
|
||||||
|
@ -193,7 +194,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (self->deactivating)
|
if (self->deactivating)
|
||||||
{
|
{
|
||||||
fp_dbg ("Deactivate requested\n");
|
fp_dbg ("Deactivate requested");
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
return;
|
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)
|
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);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -219,8 +220,8 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||||
if (response_size > transfer->actual_length)
|
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);
|
(gulong) response_size, (gint) transfer->actual_length);
|
||||||
fp_dbg ("Waiting for rest of transfer");
|
fp_dbg ("Waiting for rest of transfer");
|
||||||
BUG_ON (self->response_rest);
|
BUG_ON (self->response_rest);
|
||||||
self->response_rest = response_size - transfer->actual_length;
|
self->response_rest = response_size - transfer->actual_length;
|
||||||
|
@ -237,7 +238,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
{
|
{
|
||||||
/* No finger */
|
/* No finger */
|
||||||
case 0x28:
|
case 0x28:
|
||||||
fp_dbg ("18th byte is %.2x\n", data[18]);
|
fp_dbg ("18th byte is %.2x", data[18]);
|
||||||
switch (data[18])
|
switch (data[18])
|
||||||
{
|
{
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
|
@ -254,7 +255,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
case 0x1e:
|
case 0x1e:
|
||||||
/* short scan */
|
/* short scan */
|
||||||
fp_err ("short scan, aborting\n");
|
fp_err ("short scan, aborting");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY_TOO_SHORT);
|
FP_DEVICE_RETRY_TOO_SHORT);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -265,7 +266,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
/* too much horisontal movement */
|
/* 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,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY_CENTER_FINGER);
|
FP_DEVICE_RETRY_CENTER_FINGER);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -276,7 +277,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* some error happened, cancel scan */
|
/* 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,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY);
|
FP_DEVICE_RETRY);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -307,9 +308,10 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
||||||
data);
|
data);
|
||||||
BUG_ON (self->image_size != IMAGE_SIZE);
|
BUG_ON (self->image_size != IMAGE_SIZE);
|
||||||
fp_dbg ("Image size is %lu\n",
|
fp_dbg ("Image size is %lu",
|
||||||
self->image_size);
|
(gulong) self->image_size);
|
||||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
||||||
|
img->flags |= FPI_IMAGE_PARTIAL;
|
||||||
memcpy (img->data, self->image_bits,
|
memcpy (img->data, self->image_bits,
|
||||||
IMAGE_SIZE);
|
IMAGE_SIZE);
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
@ -319,7 +321,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Unknown response!\n");
|
fp_err ("Unknown response!");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -330,7 +332,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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));
|
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UPEKTC_IMG_H
|
#pragma once
|
||||||
#define __UPEKTC_IMG_H
|
|
||||||
|
|
||||||
static const unsigned char upek2020_init_1[] = {
|
static const unsigned char upek2020_init_1[] = {
|
||||||
'C', 'i', 'a', 'o',
|
'C', 'i', 'a', 'o',
|
||||||
|
@ -140,5 +139,3 @@ static const unsigned char upek2020_ack_frame[] = {
|
||||||
0x30,
|
0x30,
|
||||||
0xac, 0x5b /* CRC */
|
0xac, 0x5b /* CRC */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,19 +10,20 @@
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
* License as published by the Free Software Foundation; version
|
* published by the Free Software Foundation; either version 2.1 of the
|
||||||
* 2.1 of the License.
|
* License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful, but
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "upekts"
|
#define FP_COMPONENT "upekts"
|
||||||
|
@ -35,7 +36,6 @@
|
||||||
#define TIMEOUT 5000
|
#define TIMEOUT 5000
|
||||||
|
|
||||||
#define MSG_READ_BUF_SIZE 0x40
|
#define MSG_READ_BUF_SIZE 0x40
|
||||||
#define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)
|
|
||||||
|
|
||||||
struct _FpiDeviceUpekts
|
struct _FpiDeviceUpekts
|
||||||
{
|
{
|
||||||
|
@ -236,12 +236,18 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
guint8 *buf = udata->buffer;
|
guint8 *buf = udata->buffer;
|
||||||
guint16 len = ((buf[5] & 0xf) << 8) | buf[6];
|
guint16 len;
|
||||||
guint16 computed_crc = udf_crc (buf + 4, len + 3);
|
guint16 computed_crc;
|
||||||
guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7];
|
guint16 msg_crc;
|
||||||
unsigned char *retdata = NULL;
|
|
||||||
unsigned char code_a, code_b;
|
unsigned char code_a, code_b;
|
||||||
|
|
||||||
|
g_assert (udata->buflen >= 6);
|
||||||
|
len = ((buf[5] & 0xf) << 8) | buf[6];
|
||||||
|
|
||||||
|
g_assert (udata->buflen >= len + 9);
|
||||||
|
computed_crc = udf_crc (buf + 4, len + 3);
|
||||||
|
msg_crc = (buf[len + 8] << 8) | buf[len + 7];
|
||||||
|
|
||||||
if (computed_crc != msg_crc)
|
if (computed_crc != msg_crc)
|
||||||
{
|
{
|
||||||
fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
|
fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
|
||||||
|
@ -267,12 +273,7 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > 0)
|
udata->callback (device, READ_MSG_CMD, code_a, 0, buf + 7, len,
|
||||||
{
|
|
||||||
retdata = g_malloc (len);
|
|
||||||
memcpy (retdata, buf + 7, len);
|
|
||||||
}
|
|
||||||
udata->callback (device, READ_MSG_CMD, code_a, 0, retdata, len,
|
|
||||||
udata->user_data, NULL);
|
udata->user_data, NULL);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -309,14 +310,8 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
innerlen = innerlen - 3;
|
innerlen = innerlen - 3;
|
||||||
_subcmd = innerbuf[5];
|
_subcmd = innerbuf[5];
|
||||||
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
|
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
|
||||||
if (innerlen > 0)
|
|
||||||
{
|
|
||||||
retdata = g_malloc (innerlen);
|
|
||||||
memcpy (retdata, innerbuf + 6, innerlen);
|
|
||||||
}
|
|
||||||
udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
|
udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
|
||||||
retdata, innerlen, udata->user_data, NULL);
|
innerbuf + 6, innerlen, udata->user_data, NULL);
|
||||||
g_free (retdata);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -358,7 +353,8 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
gpointer user_data, GError *error)
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct read_msg_data *udata = user_data;
|
struct read_msg_data *udata = user_data;
|
||||||
guint16 len;
|
guint16 payload_len;
|
||||||
|
gsize packet_len;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -370,7 +366,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_err ("async msg read too short (%d)",
|
fp_err ("async msg read too short (%d)",
|
||||||
(gint) transfer->actual_length);
|
(gint) transfer->actual_length);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Packet from device was too short (%lu)",
|
"Packet from device was too short (%" G_GSSIZE_FORMAT ")",
|
||||||
transfer->actual_length);
|
transfer->actual_length);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -383,14 +379,15 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
|
payload_len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
|
||||||
|
packet_len = payload_len + 9;
|
||||||
if (transfer->actual_length != MSG_READ_BUF_SIZE &&
|
if (transfer->actual_length != MSG_READ_BUF_SIZE &&
|
||||||
(len + 9) > transfer->actual_length)
|
packet_len > transfer->actual_length)
|
||||||
{
|
{
|
||||||
/* Check that the length claimed inside the message is in line with
|
/* Check that the length claimed inside the message is in line with
|
||||||
* the amount of data that was transferred over USB. */
|
* the amount of data that was transferred over USB. */
|
||||||
fp_err ("msg didn't include enough data, expected=%d recv=%d",
|
fp_err ("msg didn't include enough data, expected=%d recv=%d",
|
||||||
len + 9, (gint) transfer->actual_length);
|
(gint) packet_len, (gint) transfer->actual_length);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Packet from device didn't include data");
|
"Packet from device didn't include data");
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -399,14 +396,14 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
/* We use a 64 byte buffer for reading messages. However, sometimes
|
/* We use a 64 byte buffer for reading messages. However, sometimes
|
||||||
* messages are longer, in which case we have to do another USB bulk read
|
* messages are longer, in which case we have to do another USB bulk read
|
||||||
* to read the remainder. This is handled below. */
|
* to read the remainder. This is handled below. */
|
||||||
if (len > MAX_DATA_IN_READ_BUF)
|
if (packet_len > MSG_READ_BUF_SIZE)
|
||||||
{
|
{
|
||||||
int needed = len - MAX_DATA_IN_READ_BUF;
|
int needed = packet_len - MSG_READ_BUF_SIZE;
|
||||||
FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
|
FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
|
||||||
|
|
||||||
fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
|
fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
|
||||||
udata->buffer = g_realloc ((gpointer) udata->buffer, len);
|
udata->buffer = g_realloc ((gpointer) udata->buffer, packet_len);
|
||||||
udata->buflen = len;
|
udata->buflen = packet_len;
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
|
fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
|
||||||
udata->buffer + MSG_READ_BUF_SIZE,
|
udata->buffer + MSG_READ_BUF_SIZE,
|
||||||
|
@ -531,15 +528,6 @@ initsm_read_msg_response_cb (FpiSsm *ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Unexpected response subcommand"));
|
"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
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
|
@ -700,7 +688,7 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEND_RESP03:;
|
case SEND_RESP03:;
|
||||||
transfer = alloc_send_cmd28_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
|
transfer = alloc_send_cmdresponse_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
@ -856,21 +844,14 @@ dev_init (FpDevice *dev)
|
||||||
fpi_ssm_start (ssm, initsm_done);
|
fpi_ssm_start (ssm, initsm_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
deinitsm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL);
|
|
||||||
|
|
||||||
fpi_device_close_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_exit (FpDevice *dev)
|
dev_exit (FpDevice *dev)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm;
|
GError *error = NULL;
|
||||||
|
|
||||||
ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
|
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, &error);
|
||||||
fpi_ssm_start (ssm, deinitsm_done);
|
|
||||||
|
fpi_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char enroll_init[] = {
|
static const unsigned char enroll_init[] = {
|
||||||
|
@ -902,8 +883,10 @@ enroll_start_sm_cb_msg28 (FpDevice *dev,
|
||||||
FpiSsm *ssm = user_data;
|
FpiSsm *ssm = user_data;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
{
|
||||||
fpi_ssm_mark_failed (ssm, error);
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
if (type != READ_MSG_RESPONSE)
|
}
|
||||||
|
else if (type != READ_MSG_RESPONSE)
|
||||||
{
|
{
|
||||||
fp_err ("expected response, got %d seq=%x", type, seq);
|
fp_err ("expected response, got %d seq=%x", type, seq);
|
||||||
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
|
@ -981,7 +964,9 @@ enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error)
|
if (error)
|
||||||
fp_warn ("Error deinitializing: %s", error->message);
|
fp_warn ("Error deinitializing: %s", error->message);
|
||||||
|
|
||||||
fpi_device_enroll_complete (dev, data->print, data->error);
|
fpi_device_enroll_complete (dev,
|
||||||
|
g_steal_pointer (&data->print),
|
||||||
|
g_steal_pointer (&data->error));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -990,7 +975,7 @@ do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error)
|
||||||
EnrollStopData *data = g_new0 (EnrollStopData, 1);
|
EnrollStopData *data = g_new0 (EnrollStopData, 1);
|
||||||
FpiSsm *ssm = deinitsm_new (dev, data);
|
FpiSsm *ssm = deinitsm_new (dev, data);
|
||||||
|
|
||||||
data->print = g_object_ref (print);
|
data->print = print;
|
||||||
data->error = error;
|
data->error = error;
|
||||||
|
|
||||||
fpi_ssm_start (ssm, enroll_stop_deinit_cb);
|
fpi_ssm_start (ssm, enroll_stop_deinit_cb);
|
||||||
|
@ -1008,7 +993,7 @@ e_handle_resp00 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len != 14)
|
if (data_len != 14)
|
||||||
{
|
{
|
||||||
fp_err ("received 3001 poll response of %lu bytes?", data_len);
|
fp_err ("received 3001 poll response of %" G_GSIZE_FORMAT " bytes?", data_len);
|
||||||
do_enroll_stop (dev, NULL,
|
do_enroll_stop (dev, NULL,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"received 3001 response with wrong length"));
|
"received 3001 response with wrong length"));
|
||||||
|
@ -1105,7 +1090,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len < sizeof (scan_comp))
|
if (data_len < sizeof (scan_comp))
|
||||||
{
|
{
|
||||||
fp_err ("fingerprint data too short (%lu bytes)", data_len);
|
fp_err ("fingerprint data too short (%" G_GSIZE_FORMAT "u bytes)", data_len);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
|
||||||
}
|
}
|
||||||
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
|
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
|
||||||
|
@ -1117,7 +1102,6 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GVariant *fp_data;
|
GVariant *fp_data;
|
||||||
print = fp_print_new (dev);
|
|
||||||
|
|
||||||
fpi_device_get_enroll_data (dev, &print);
|
fpi_device_get_enroll_data (dev, &print);
|
||||||
|
|
||||||
|
@ -1126,7 +1110,8 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
|
||||||
data_len - sizeof (scan_comp),
|
data_len - sizeof (scan_comp),
|
||||||
1);
|
1);
|
||||||
|
|
||||||
g_object_set (print, "fp-data", fp_data, NULL);
|
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||||
|
g_object_set (print, "fpi-data", fp_data, NULL);
|
||||||
g_object_ref (print);
|
g_object_ref (print);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1225,7 +1210,6 @@ enroll (FpDevice *dev)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
FpiMatchResult res;
|
|
||||||
GError *error;
|
GError *error;
|
||||||
} VerifyStopData;
|
} VerifyStopData;
|
||||||
|
|
||||||
|
@ -1244,7 +1228,12 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error)
|
if (error)
|
||||||
fp_warn ("Error deinitializing: %s", error->message);
|
fp_warn ("Error deinitializing: %s", error->message);
|
||||||
|
|
||||||
fpi_device_verify_complete (dev, data->res, NULL, data->error);
|
if (data->error)
|
||||||
|
fpi_device_verify_complete (dev, g_steal_pointer (&data->error));
|
||||||
|
else
|
||||||
|
fpi_device_verify_complete (dev, g_steal_pointer (&error));
|
||||||
|
|
||||||
|
g_clear_error (&error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1253,7 +1242,10 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
|
||||||
VerifyStopData *data = g_new0 (VerifyStopData, 1);
|
VerifyStopData *data = g_new0 (VerifyStopData, 1);
|
||||||
FpiSsm *ssm = deinitsm_new (dev, data);
|
FpiSsm *ssm = deinitsm_new (dev, data);
|
||||||
|
|
||||||
data->res = res;
|
/* Report the error immediately if possible, otherwise delay it. */
|
||||||
|
if (error && error->domain == FP_DEVICE_RETRY)
|
||||||
|
fpi_device_verify_report (dev, res, NULL, error);
|
||||||
|
else
|
||||||
data->error = error;
|
data->error = error;
|
||||||
|
|
||||||
fpi_ssm_start (ssm, verify_stop_deinit_cb);
|
fpi_ssm_start (ssm, verify_stop_deinit_cb);
|
||||||
|
@ -1293,7 +1285,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
|
||||||
case VERIFY_INIT:
|
case VERIFY_INIT:
|
||||||
fpi_device_get_verify_data (dev, &print);
|
fpi_device_get_verify_data (dev, &print);
|
||||||
g_object_get (dev, "fp-data", &fp_data, NULL);
|
g_object_get (print, "fpi-data", &fp_data, NULL);
|
||||||
|
|
||||||
data = g_variant_get_fixed_array (fp_data, &data_len, 1);
|
data = g_variant_get_fixed_array (fp_data, &data_len, 1);
|
||||||
|
|
||||||
|
@ -1326,7 +1318,7 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len != 14)
|
if (data_len != 14)
|
||||||
{
|
{
|
||||||
fp_warn ("received 3001 poll response of %lu bytes?", data_len);
|
fp_warn ("received 3001 poll response of %" G_GSIZE_FORMAT "u bytes?", data_len);
|
||||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1564,4 +1556,6 @@ fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
|
||||||
dev_class->verify = verify;
|
dev_class->verify = verify;
|
||||||
dev_class->enroll = enroll;
|
dev_class->enroll = enroll;
|
||||||
/* dev_class->cancel = cancel; */
|
/* dev_class->cancel = cancel; */
|
||||||
|
|
||||||
|
fpi_device_class_auto_initialize_features (dev_class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ static const struct uru4k_dev_profile
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
gboolean auth_cr;
|
gboolean auth_cr;
|
||||||
gboolean encryption;
|
gboolean image_not_flipped;
|
||||||
} uru4k_dev_info[] = {
|
} uru4k_dev_info[] = {
|
||||||
[MS_KBD] = {
|
[MS_KBD] = {
|
||||||
.name = "Microsoft Keyboard with Fingerprint Reader",
|
.name = "Microsoft Keyboard with Fingerprint Reader",
|
||||||
|
@ -106,7 +106,7 @@ static const struct uru4k_dev_profile
|
||||||
[DP_URU4000B] = {
|
[DP_URU4000B] = {
|
||||||
.name = "Digital Persona U.are.U 4000B",
|
.name = "Digital Persona U.are.U 4000B",
|
||||||
.auth_cr = FALSE,
|
.auth_cr = FALSE,
|
||||||
.encryption = TRUE,
|
.image_not_flipped = TRUE, /* See comment in the code where it is used. */
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ struct _FpiDeviceUru4000
|
||||||
|
|
||||||
const struct uru4k_dev_profile *profile;
|
const struct uru4k_dev_profile *profile;
|
||||||
uint8_t interface;
|
uint8_t interface;
|
||||||
FpImageDeviceState activate_state;
|
FpiImageDeviceState activate_state;
|
||||||
unsigned char last_reg_rd[16];
|
unsigned char last_reg_rd[16];
|
||||||
unsigned char last_hwstat;
|
unsigned char last_hwstat;
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@ struct _FpiDeviceUru4000
|
||||||
void *img_data;
|
void *img_data;
|
||||||
int img_data_actual_length;
|
int img_data_actual_length;
|
||||||
uint16_t img_lines_done, img_block;
|
uint16_t img_lines_done, img_block;
|
||||||
|
GRand *rand;
|
||||||
uint32_t img_enc_seed;
|
uint32_t img_enc_seed;
|
||||||
|
|
||||||
irq_cb_fn irq_cb;
|
irq_cb_fn irq_cb;
|
||||||
|
@ -359,7 +360,7 @@ start_irq_handler (FpImageDevice *dev)
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
transfer->ssm = NULL;
|
transfer->ssm = NULL;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_fill_bulk (transfer,
|
fpi_usb_transfer_fill_interrupt (transfer,
|
||||||
EP_INTR,
|
EP_INTR,
|
||||||
IRQ_LENGTH);
|
IRQ_LENGTH);
|
||||||
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
|
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
|
||||||
|
@ -375,6 +376,10 @@ stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb)
|
||||||
g_cancellable_cancel (self->irq_cancellable);
|
g_cancellable_cancel (self->irq_cancellable);
|
||||||
self->irqs_stopped_cb = cb;
|
self->irqs_stopped_cb = cb;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cb (dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** STATE CHANGING *****/
|
/***** STATE CHANGING *****/
|
||||||
|
@ -393,7 +398,7 @@ finger_presence_irq_cb (FpImageDevice *dev,
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
else if (type == IRQDATA_FINGER_OFF)
|
else if (type == IRQDATA_FINGER_OFF)
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
else
|
else if (type != IRQDATA_SCANPWR_ON)
|
||||||
fp_warn ("ignoring unexpected interrupt %04x", type);
|
fp_warn ("ignoring unexpected interrupt %04x", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,22 +413,10 @@ change_state_write_reg_cb (FpiUsbTransfer *transfer,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
|
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
{
|
{
|
||||||
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
|
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case FP_IMAGE_DEVICE_STATE_INACTIVE:
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
|
||||||
case FP_IMAGE_DEVICE_STATE_CAPTURE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
|
|
||||||
self->activate_state = state;
|
self->activate_state = state;
|
||||||
if (self->img_transfer != NULL)
|
if (self->img_transfer != NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -663,7 +656,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
case IMAGING_CAPTURE:
|
case IMAGING_CAPTURE:
|
||||||
self->img_lines_done = 0;
|
self->img_lines_done = 0;
|
||||||
self->img_block = 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;
|
break;
|
||||||
|
|
||||||
|
@ -680,8 +677,8 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!self->profile->encryption)
|
|
||||||
{
|
/* Detect whether image is encrypted (by checking how noisy it is) */
|
||||||
dev2 = calc_dev2 (img);
|
dev2 = calc_dev2 (img);
|
||||||
fp_dbg ("dev2: %d", dev2);
|
fp_dbg ("dev2: %d", dev2);
|
||||||
if (dev2 < ENC_THRESHOLD)
|
if (dev2 < ENC_THRESHOLD)
|
||||||
|
@ -690,7 +687,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fp_info ("image seems to be encrypted");
|
fp_info ("image seems to be encrypted");
|
||||||
}
|
|
||||||
buf[0] = img->key_number;
|
buf[0] = img->key_number;
|
||||||
buf[1] = self->img_enc_seed;
|
buf[1] = self->img_enc_seed;
|
||||||
buf[2] = self->img_enc_seed >> 8;
|
buf[2] = self->img_enc_seed >> 8;
|
||||||
|
@ -723,10 +720,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
num_lines);
|
num_lines);
|
||||||
if (flags & BLOCKF_CHANGE_KEY)
|
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->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
|
||||||
img->key_number++;
|
img->key_number++;
|
||||||
self->img_enc_seed = rand ();
|
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
|
||||||
|
fp_dbg ("New image encryption seed: %d", self->img_enc_seed);
|
||||||
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
|
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -769,11 +767,17 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fpimg->flags = FPI_IMAGE_COLORS_INVERTED;
|
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;
|
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||||
fpi_image_device_image_captured (dev, fpimg);
|
fpi_image_device_image_captured (dev, fpimg);
|
||||||
|
|
||||||
if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE)
|
if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
|
||||||
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
@ -793,8 +797,7 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error)
|
if (error)
|
||||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||||
|
|
||||||
/* Freed by callback or cancellation */
|
g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref);
|
||||||
self->img_transfer = NULL;
|
|
||||||
|
|
||||||
g_free (self->img_data);
|
g_free (self->img_data);
|
||||||
self->img_data = NULL;
|
self->img_data = NULL;
|
||||||
|
@ -864,7 +867,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL);
|
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -946,11 +949,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
else if (!self->profile->auth_cr)
|
else if (!self->profile->auth_cr)
|
||||||
{
|
{
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL);
|
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
fpi_ssm_next_state_delayed (ssm, 10);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1176,7 +1179,10 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
static void
|
static void
|
||||||
dev_deactivate (FpImageDevice *dev)
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
dev_change_state (dev, FP_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
|
static void
|
||||||
|
@ -1187,7 +1193,7 @@ execute_state_change (FpImageDevice *dev)
|
||||||
|
|
||||||
switch (self->activate_state)
|
switch (self->activate_state)
|
||||||
{
|
{
|
||||||
case FP_IMAGE_DEVICE_STATE_INACTIVE:
|
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
|
||||||
fp_dbg ("deactivating");
|
fp_dbg ("deactivating");
|
||||||
self->irq_cb = NULL;
|
self->irq_cb = NULL;
|
||||||
self->irq_cb_data = NULL;
|
self->irq_cb_data = NULL;
|
||||||
|
@ -1195,7 +1201,7 @@ execute_state_change (FpImageDevice *dev)
|
||||||
deactivate_write_reg_cb, NULL);
|
deactivate_write_reg_cb, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
||||||
fp_dbg ("wait finger on");
|
fp_dbg ("wait finger on");
|
||||||
if (!IRQ_HANDLER_IS_RUNNING (self))
|
if (!IRQ_HANDLER_IS_RUNNING (self))
|
||||||
{
|
{
|
||||||
|
@ -1209,13 +1215,14 @@ execute_state_change (FpImageDevice *dev)
|
||||||
change_state_write_reg_cb, NULL);
|
change_state_write_reg_cb, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_IMAGE_DEVICE_STATE_CAPTURE:
|
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
||||||
fp_dbg ("starting capture");
|
fp_dbg ("starting capture");
|
||||||
self->irq_cb = NULL;
|
self->irq_cb = NULL;
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
|
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
|
||||||
IMAGING_NUM_STATES);
|
IMAGING_NUM_STATES);
|
||||||
self->img_enc_seed = rand ();
|
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
|
||||||
|
fp_dbg ("Image encryption seed: %d", self->img_enc_seed);
|
||||||
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
self->img_transfer->ssm = ssm;
|
self->img_transfer->ssm = ssm;
|
||||||
self->img_transfer->short_is_error = FALSE;
|
self->img_transfer->short_is_error = FALSE;
|
||||||
|
@ -1229,7 +1236,7 @@ execute_state_change (FpImageDevice *dev)
|
||||||
change_state_write_reg_cb, NULL);
|
change_state_write_reg_cb, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
||||||
fp_dbg ("await finger off");
|
fp_dbg ("await finger off");
|
||||||
if (!IRQ_HANDLER_IS_RUNNING (self))
|
if (!IRQ_HANDLER_IS_RUNNING (self))
|
||||||
{
|
{
|
||||||
|
@ -1242,6 +1249,12 @@ execute_state_change (FpImageDevice *dev)
|
||||||
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
|
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
|
||||||
change_state_write_reg_cb, NULL);
|
change_state_write_reg_cb, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Ignored states */
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_IDLE:
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,6 +1358,11 @@ dev_init (FpImageDevice *dev)
|
||||||
|
|
||||||
self = FPI_DEVICE_URU4000 (dev);
|
self = FPI_DEVICE_URU4000 (dev);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->rand, g_rand_free);
|
||||||
|
self->rand = g_rand_new ();
|
||||||
|
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||||
|
g_rand_set_seed (self->rand, 0xFACADE);
|
||||||
|
|
||||||
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||||
self->profile = &uru4k_dev_info[driver_data];
|
self->profile = &uru4k_dev_info[driver_data];
|
||||||
self->interface = g_usb_interface_get_number (iface);
|
self->interface = g_usb_interface_get_number (iface);
|
||||||
|
@ -1397,6 +1415,7 @@ dev_deinit (FpImageDevice *dev)
|
||||||
PK11_FreeSlot (self->slot);
|
PK11_FreeSlot (self->slot);
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
self->interface, 0, &error);
|
self->interface, 0, &error);
|
||||||
|
g_clear_pointer (&self->rand, g_rand_free);
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send data to EP1, the only out endpoint */
|
/* Send data to EP1, the only out endpoint */
|
||||||
|
FP_GNUC_ACCESS (read_only, 3, 4)
|
||||||
static void
|
static void
|
||||||
async_write (FpiSsm *ssm,
|
async_write (FpiSsm *ssm,
|
||||||
FpDevice *dev,
|
FpDevice *dev,
|
||||||
|
@ -117,9 +118,10 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
int ep = transfer->endpoint;
|
int ep = transfer->endpoint;
|
||||||
|
|
||||||
/* In normal case endpoint is empty */
|
/* 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_free (error);
|
g_clear_error (&error);
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -156,6 +158,8 @@ async_abort (FpDevice *dev, FpiSsm *ssm, int ep)
|
||||||
else
|
else
|
||||||
fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
|
fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
|
||||||
|
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
|
||||||
async_abort_callback, NULL);
|
async_abort_callback, NULL);
|
||||||
}
|
}
|
||||||
|
@ -240,6 +244,7 @@ prepare_image (FpDeviceVfs0050 *vdev)
|
||||||
|
|
||||||
/* Building GSList */
|
/* Building GSList */
|
||||||
GSList *lines = NULL;
|
GSList *lines = NULL;
|
||||||
|
|
||||||
for (int i = height - 1; i >= 0; --i)
|
for (int i = height - 1; i >= 0; --i)
|
||||||
lines = g_slist_prepend (lines, vdev->lines_buffer + i);
|
lines = g_slist_prepend (lines, vdev->lines_buffer + i);
|
||||||
|
|
||||||
|
@ -464,8 +469,8 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
if (error)
|
if (error)
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
|
||||||
/* Check if fingerprint data is over */
|
/* Capture is done when there is no more data to transfer or device timed out */
|
||||||
if (transfer->actual_length == 0)
|
if (transfer->actual_length <= 0)
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
}
|
}
|
||||||
|
@ -473,7 +478,7 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
{
|
{
|
||||||
self->bytes += transfer->actual_length;
|
self->bytes += transfer->actual_length;
|
||||||
|
|
||||||
/* We need more data */
|
/* Try reading more data */
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
fpi_ssm_jump_to_state (transfer->ssm,
|
||||||
fpi_ssm_get_cur_state (transfer->ssm));
|
fpi_ssm_get_cur_state (transfer->ssm));
|
||||||
}
|
}
|
||||||
|
@ -595,8 +600,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
/* Receive chunk of data */
|
/* Receive chunk of data */
|
||||||
transfer = fpi_usb_transfer_new (dev);
|
transfer = fpi_usb_transfer_new (dev);
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
|
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
|
||||||
(guint8 *)
|
(guint8 *) self->lines_buffer + self->bytes,
|
||||||
(self->lines_buffer + self->bytes),
|
|
||||||
VFS_USB_BUFFER_SIZE, NULL);
|
VFS_USB_BUFFER_SIZE, NULL);
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
|
||||||
|
@ -609,7 +613,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
clear_data (self);
|
clear_data (self);
|
||||||
|
|
||||||
/* Wait for probable vdev->active changing */
|
/* Wait for probable vdev->active changing */
|
||||||
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL);
|
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSM_NEXT_RECEIVE:
|
case SSM_NEXT_RECEIVE:
|
||||||
|
@ -628,8 +632,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
|
||||||
case SSM_WAIT_ANOTHER_SCAN:
|
case SSM_WAIT_ANOTHER_SCAN:
|
||||||
/* Orange light is on now */
|
/* Orange light is on now */
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT,
|
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
|
||||||
NULL);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -668,6 +671,7 @@ dev_activate (FpImageDevice *idev)
|
||||||
self->ssm_active = 1;
|
self->ssm_active = 1;
|
||||||
|
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, dev_activate_callback);
|
fpi_ssm_start (ssm, dev_activate_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,6 +715,7 @@ dev_open (FpImageDevice *idev)
|
||||||
|
|
||||||
/* Clearing previous device state */
|
/* Clearing previous device state */
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, dev_open_callback);
|
fpi_ssm_start (ssm, dev_open_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_LOOP_0_SLEEP:
|
case M_LOOP_0_SLEEP:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 50, NULL);
|
fpi_ssm_next_state_delayed (ssm, 50);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_0_GET_STATE:
|
case M_LOOP_0_GET_STATE:
|
||||||
|
@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
img_extract (ssm, dev);
|
img_extract (ssm, dev);
|
||||||
|
|
||||||
/* Wait handling image */
|
/* Wait handling image */
|
||||||
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
fpi_ssm_next_state_delayed (ssm, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_0_CHECK_ACTION:
|
case M_LOOP_0_CHECK_ACTION:
|
||||||
|
@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
|
if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
|
||||||
{
|
{
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
fpi_ssm_next_state_delayed (ssm, 250, NULL);
|
fpi_ssm_next_state_delayed (ssm, 250);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_LOOP_1_SLEEP:
|
case M_LOOP_1_SLEEP:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
fpi_ssm_next_state_delayed (ssm, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_2_ABORT_PRINT:
|
case M_LOOP_2_ABORT_PRINT:
|
||||||
|
@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait aborting */
|
/* Wait aborting */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 100, NULL);
|
fpi_ssm_next_state_delayed (ssm, 100);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait aborting */
|
/* Wait aborting */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 100, NULL);
|
fpi_ssm_next_state_delayed (ssm, 100);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait removing finger */
|
/* Wait removing finger */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 250, NULL);
|
fpi_ssm_next_state_delayed (ssm, 250);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_WAIT_PRINT:
|
case M_WAIT_PRINT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
fpi_ssm_next_state_delayed (ssm, 200);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
case M_CHECK_PRINT:
|
||||||
|
@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_READ_PRINT_WAIT:
|
case M_READ_PRINT_WAIT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
fpi_ssm_next_state_delayed (ssm, 200);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
case M_READ_PRINT_POLL:
|
||||||
|
@ -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 */
|
/* Exec init sequential state machine */
|
||||||
static void
|
static void
|
||||||
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
@ -176,19 +164,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
static void
|
static void
|
||||||
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm_loop;
|
|
||||||
|
|
||||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
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 */
|
/* Activate device */
|
||||||
|
@ -213,6 +189,19 @@ dev_deactivate (FpImageDevice *dev)
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
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
|
static void
|
||||||
dev_open (FpImageDevice *dev)
|
dev_open (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
@ -273,6 +262,7 @@ fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
||||||
img_class->img_close = dev_close;
|
img_class->img_close = dev_close;
|
||||||
img_class->activate = dev_activate;
|
img_class->activate = dev_activate;
|
||||||
img_class->deactivate = dev_deactivate;
|
img_class->deactivate = dev_deactivate;
|
||||||
|
img_class->change_state = dev_change_state;
|
||||||
|
|
||||||
img_class->bz3_threshold = 24;
|
img_class->bz3_threshold = 24;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
|
||||||
*out = g_steal_pointer (&transfer);
|
*out = g_steal_pointer (&transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FP_GNUC_ACCESS (read_only, 2, 3)
|
||||||
static void
|
static void
|
||||||
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
||||||
{
|
{
|
||||||
|
@ -177,6 +178,7 @@ translate_str (const char **srcL, gssize *len)
|
||||||
src_len += tmp;
|
src_len += tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert (src_len >= 2);
|
||||||
*len = src_len / 2;
|
*len = src_len / 2;
|
||||||
res = g_malloc0 (*len);
|
res = g_malloc0 (*len);
|
||||||
dst = res;
|
dst = res;
|
||||||
|
@ -211,11 +213,9 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
*len = 1;
|
*len = 1;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
return vfs301_proto_generate_0B (subtype, len);
|
return vfs301_proto_generate_0B (subtype, len);
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x02D0:
|
case 0x02D0:
|
||||||
{
|
{
|
||||||
|
@ -231,22 +231,18 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
||||||
return translate_str (dataLs[subtype - 1], len);
|
return translate_str (dataLs[subtype - 1], len);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x0220:
|
case 0x0220:
|
||||||
switch (subtype)
|
switch (subtype)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return translate_str (vfs301_0220_01, len);
|
return translate_str (vfs301_0220_01, len);
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return translate_str (vfs301_0220_02, len);
|
return translate_str (vfs301_0220_02, len);
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return translate_str (vfs301_0220_03, len);
|
return translate_str (vfs301_0220_03, len);
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xFA00:
|
case 0xFA00:
|
||||||
case 0x2C01:
|
case 0x2C01:
|
||||||
|
@ -269,7 +265,6 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
field[3] = field[1];
|
field[3] = field[1];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -437,7 +432,7 @@ img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int l
|
||||||
usb_send (dev, data, len, NULL); \
|
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))
|
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
||||||
|
|
||||||
|
@ -470,7 +465,7 @@ int
|
||||||
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FpiUsbTransfer *transfer;
|
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
||||||
|
|
||||||
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
@ -507,30 +502,30 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
|
||||||
FpDevice *device,
|
FpDevice *device,
|
||||||
gpointer user_data, GError *error)
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *dev = user_data;
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
g_warning ("Error receiving data: %s", error->message);
|
g_warning ("Error receiving data: %s", error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
dev->recv_progress = VFS301_FAILURE;
|
self->recv_progress = VFS301_FAILURE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (transfer->actual_length < transfer->length)
|
else if (transfer->actual_length < transfer->length)
|
||||||
{
|
{
|
||||||
/* TODO: process the data anyway? */
|
/* TODO: process the data anyway? */
|
||||||
dev->recv_progress = VFS301_ENDED;
|
self->recv_progress = VFS301_ENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *new;
|
FpiUsbTransfer *new;
|
||||||
if (!vfs301_proto_process_data (dev,
|
if (!vfs301_proto_process_data (self,
|
||||||
transfer->length == VFS301_FP_RECV_LEN_1,
|
transfer->length == VFS301_FP_RECV_LEN_1,
|
||||||
transfer->buffer,
|
transfer->buffer,
|
||||||
transfer->actual_length))
|
transfer->actual_length))
|
||||||
{
|
{
|
||||||
dev->recv_progress = VFS301_ENDED;
|
self->recv_progress = VFS301_ENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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
|
/* There are many similar blocks in the data below, also the data are
|
||||||
* self-similar (looks like some config blocks? pokes like in vfs101?) */
|
* self-similar (looks like some config blocks? pokes like in vfs101?) */
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,7 @@ usb_exchange_async (FpiSsm *ssm,
|
||||||
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
|
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
|
||||||
usbexchange_loop,
|
usbexchange_loop,
|
||||||
data->stepcount,
|
data->stepcount,
|
||||||
|
data->stepcount,
|
||||||
exchange_name);
|
exchange_name);
|
||||||
|
|
||||||
fpi_ssm_set_data (subsm, data, NULL);
|
fpi_ssm_set_data (subsm, data, NULL);
|
||||||
|
@ -381,9 +382,8 @@ submit_image (FpiSsm *ssm,
|
||||||
{
|
{
|
||||||
FpImage *img;
|
FpImage *img;
|
||||||
|
|
||||||
if (self->lines_recorded == 0)
|
if (self->lines_recorded < VFS5011_IMAGE_WIDTH)
|
||||||
{
|
{
|
||||||
/* == FP_ENROLL_RETRY_TOO_SHORT */
|
|
||||||
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -706,7 +706,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_DATA_COMPLETE:
|
case DEV_ACTIVATE_DATA_COMPLETE:
|
||||||
fpi_ssm_next_state_delayed (ssm, 1, NULL);
|
fpi_ssm_next_state_delayed (ssm, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
||||||
|
@ -816,13 +816,11 @@ dev_close (FpImageDevice *dev)
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
|
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
0, 0, &error);
|
0, 0, &error);
|
||||||
|
|
||||||
g_free (self->capture_buffer);
|
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);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef __VFS5011_PROTO_H
|
#pragma once
|
||||||
#define __VFS5011_PROTO_H
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
#define VFS5011_LINE_SIZE 240
|
#define VFS5011_LINE_SIZE 240
|
||||||
#define VFS5011_IMAGE_WIDTH 160
|
#define VFS5011_IMAGE_WIDTH 160
|
||||||
|
@ -6182,5 +6183,3 @@ static unsigned char vfs5011_prepare_04[] = { /* 2903 B */
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
1072
libfprint/drivers/vfs7552.c
Normal file
1072
libfprint/drivers/vfs7552.c
Normal file
File diff suppressed because it is too large
Load diff
2986
libfprint/drivers/vfs7552_proto.h
Normal file
2986
libfprint/drivers/vfs7552_proto.h
Normal file
File diff suppressed because it is too large
Load diff
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 _FpiDeviceVirtualListener
|
||||||
|
{
|
||||||
|
GSocketListener parent_instance;
|
||||||
|
|
||||||
|
GSocketConnection *connection;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
guint cancellable_id;
|
||||||
|
|
||||||
|
FpiDeviceVirtualListenerConnectionCb ready_cb;
|
||||||
|
gpointer ready_cb_data;
|
||||||
|
|
||||||
|
gint socket_fd;
|
||||||
|
gint client_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
|
||||||
|
|
||||||
|
static void start_listen (FpiDeviceVirtualListener *self);
|
||||||
|
|
||||||
|
FpiDeviceVirtualListener *
|
||||||
|
fpi_device_virtual_listener_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (fpi_device_virtual_listener_get_type (), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_virtual_listener_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
FpiDeviceVirtualListener *self = FPI_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 (fpi_device_virtual_listener_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_virtual_listener_class_init (FpiDeviceVirtualListenerClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = fpi_device_virtual_listener_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_virtual_listener_init (FpiDeviceVirtualListener *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpiDeviceVirtualListener *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 (FpiDeviceVirtualListener *self)
|
||||||
|
{
|
||||||
|
g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
|
||||||
|
self->cancellable,
|
||||||
|
new_connection_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_cancelled (GCancellable *cancellable,
|
||||||
|
FpiDeviceVirtualListener *self)
|
||||||
|
{
|
||||||
|
fpi_device_virtual_listener_connection_close (self);
|
||||||
|
g_socket_listener_close (G_SOCKET_LISTENER (self));
|
||||||
|
g_clear_object (&self->cancellable);
|
||||||
|
self->ready_cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fpi_device_virtual_listener_start (FpiDeviceVirtualListener *self,
|
||||||
|
const char *address,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpiDeviceVirtualListenerConnectionCb cb,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GSocketAddress) addr = NULL;
|
||||||
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
|
g_return_val_if_fail (FPI_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
|
||||||
|
fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (FPI_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;
|
||||||
|
FpiDeviceVirtualListener *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
|
||||||
|
fpi_device_virtual_listener_read (FpiDeviceVirtualListener *self,
|
||||||
|
gboolean all,
|
||||||
|
void *buffer,
|
||||||
|
gsize count,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GTask) task = NULL;
|
||||||
|
GInputStream *stream;
|
||||||
|
|
||||||
|
g_return_if_fail (FPI_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
|
||||||
|
fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *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
|
||||||
|
fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *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);
|
||||||
|
}
|
111
libfprint/drivers/virtual-device-private.h
Normal file
111
libfprint/drivers/virtual-device-private.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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 (FpiDeviceVirtualListener, fpi_device_virtual_listener, FPI, DEVICE_VIRTUAL_LISTENER, GSocketListener)
|
||||||
|
|
||||||
|
typedef void (*FpiDeviceVirtualListenerConnectionCb) (FpiDeviceVirtualListener *listener,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
FpiDeviceVirtualListener * fpi_device_virtual_listener_new (void);
|
||||||
|
|
||||||
|
gboolean fpi_device_virtual_listener_start (FpiDeviceVirtualListener *listener,
|
||||||
|
const char *address,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
FpiDeviceVirtualListenerConnectionCb cb,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *listener);
|
||||||
|
|
||||||
|
void fpi_device_virtual_listener_read (FpiDeviceVirtualListener *listener,
|
||||||
|
gboolean all,
|
||||||
|
void *buffer,
|
||||||
|
gsize count,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gsize fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *listener,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
|
||||||
|
const char *buffer,
|
||||||
|
gsize count,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
struct _FpDeviceVirtualDevice
|
||||||
|
{
|
||||||
|
FpDevice parent;
|
||||||
|
|
||||||
|
FpiDeviceVirtualListener *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)
|
||||||
|
|
||||||
|
|
||||||
|
gboolean process_cmds (FpDeviceVirtualDevice * self,
|
||||||
|
gboolean scan,
|
||||||
|
char **scan_id,
|
||||||
|
GError **error);
|
||||||
|
gboolean start_scan_command (FpDeviceVirtualDevice *self,
|
||||||
|
char **scan_id,
|
||||||
|
GError **error);
|
||||||
|
gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self,
|
||||||
|
const char *scan_id,
|
||||||
|
GError *error);
|
284
libfprint/drivers/virtual-device-storage.c
Normal file
284
libfprint/drivers/virtual-device-storage.c
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
if (!start_scan_command (self, &scan_id, &error))
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
match = FALSE;
|
||||||
|
g_clear_object (&new_scan);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!process_cmds (vdev, FALSE, NULL, &error))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_device_list_complete (dev, NULL, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_device_list_complete (dev, get_stored_prints (vdev), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_clear_storage (FpDevice *dev)
|
||||||
|
{
|
||||||
|
g_autoptr(GPtrArray) prints_list = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||||
|
|
||||||
|
if (!process_cmds (vdev, FALSE, NULL, &error))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_device_clear_storage_complete (dev, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove_all (vdev->prints_storage);
|
||||||
|
|
||||||
|
fpi_device_clear_storage_complete (dev, 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;
|
||||||
|
|
||||||
|
if (!process_cmds (vdev, FALSE, NULL, &error))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
dev_probe (FpDevice *dev)
|
||||||
|
{
|
||||||
|
/* Disable features listed in driver_data */
|
||||||
|
fpi_device_update_features (dev, fpi_device_get_driver_data (dev), 0);
|
||||||
|
|
||||||
|
fpi_device_probe_complete (dev, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
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", .driver_data = 0 },
|
||||||
|
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE_NO_LIST", .driver_data = FP_DEVICE_FEATURE_STORAGE_LIST },
|
||||||
|
{ .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->probe = dev_probe;
|
||||||
|
dev_class->identify = dev_identify;
|
||||||
|
dev_class->list = dev_list;
|
||||||
|
dev_class->delete = dev_delete;
|
||||||
|
dev_class->clear_storage = dev_clear_storage;
|
||||||
|
|
||||||
|
fpi_device_class_auto_initialize_features (dev_class);
|
||||||
|
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
|
||||||
|
}
|
785
libfprint/drivers/virtual-device.c
Normal file
785
libfprint/drivers/virtual-device.c
Normal file
|
@ -0,0 +1,785 @@
|
||||||
|
/*
|
||||||
|
* 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 CONT_CMD_PREFIX "CONT "
|
||||||
|
#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;
|
||||||
|
|
||||||
|
g_assert (self->wait_command_id == 0);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
case FPI_DEVICE_ACTION_CLEAR_STORAGE:
|
||||||
|
FP_DEVICE_GET_CLASS (self)->clear_storage (dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Not implemented/nothing to do. */
|
||||||
|
case FPI_DEVICE_ACTION_NONE:
|
||||||
|
case FPI_DEVICE_ACTION_PROBE:
|
||||||
|
case FPI_DEVICE_ACTION_CAPTURE:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
wait_for_command_timeout (gpointer data)
|
||||||
|
{
|
||||||
|
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
|
||||||
|
FpiDeviceAction action;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
self->wait_command_id = 0;
|
||||||
|
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
if (action == FPI_DEVICE_ACTION_LIST || action == FPI_DEVICE_ACTION_DELETE)
|
||||||
|
{
|
||||||
|
self->ignore_wait = TRUE;
|
||||||
|
maybe_continue_current_action (self);
|
||||||
|
self->ignore_wait = FALSE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
process_cmds (FpDeviceVirtualDevice * self,
|
||||||
|
gboolean scan,
|
||||||
|
char **scan_id,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean removed;
|
||||||
|
|
||||||
|
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 TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self->pending_commands->len > 0)
|
||||||
|
{
|
||||||
|
g_autofree gchar *cmd = NULL;
|
||||||
|
|
||||||
|
/* TODO: g_ptr_array_steal_index requires GLib 2.58, we depend on 2.56 */
|
||||||
|
cmd = g_ptr_array_index (self->pending_commands, 0);
|
||||||
|
g_ptr_array_index (self->pending_commands, 0) = NULL;
|
||||||
|
g_ptr_array_remove_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)));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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 %" G_GUINT64_FORMAT "ms", sleep_ms);
|
||||||
|
self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
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)));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (!scan && g_str_has_prefix (cmd, CONT_CMD_PREFIX))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are not scanning, then we have to stop here. */
|
||||||
|
if (!scan)
|
||||||
|
{
|
||||||
|
g_warning ("Could not process command: %s", cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
|
||||||
|
{
|
||||||
|
if (scan_id)
|
||||||
|
*scan_id = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
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)));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Could not process command: %s", cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->ignore_wait)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
g_object_get (self, "removed", &removed, NULL);
|
||||||
|
|
||||||
|
g_assert (self->wait_command_id == 0);
|
||||||
|
if (!scan || removed)
|
||||||
|
self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_key_to_listener (void *key, void *val, void *user_data)
|
||||||
|
{
|
||||||
|
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (user_data);
|
||||||
|
|
||||||
|
if (!fpi_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
|
||||||
|
!fpi_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;
|
||||||
|
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||||
|
gsize bytes;
|
||||||
|
|
||||||
|
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
|
||||||
|
fp_dbg ("Got instructions of length %" G_GSIZE_FORMAT, 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));
|
||||||
|
maybe_continue_current_action (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_device_virtual_listener_connection_close (listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recv_instruction (FpDeviceVirtualDevice *self)
|
||||||
|
{
|
||||||
|
fpi_device_virtual_listener_read (self->listener,
|
||||||
|
FALSE,
|
||||||
|
self->recv_buf,
|
||||||
|
sizeof (self->recv_buf),
|
||||||
|
recv_instruction_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_listener_connected (FpiDeviceVirtualListener *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(FpiDeviceVirtualListener) listener = NULL;
|
||||||
|
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
|
||||||
|
|
||||||
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
|
self->ignore_wait = TRUE;
|
||||||
|
if (!process_cmds (self, FALSE, NULL, &error))
|
||||||
|
{
|
||||||
|
self->ignore_wait = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self->ignore_wait = FALSE;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_device_open_complete (dev, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (self->listener)
|
||||||
|
{
|
||||||
|
fpi_device_open_complete (dev, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener = fpi_device_virtual_listener_new ();
|
||||||
|
cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
|
if (!fpi_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
start_scan_command (FpDeviceVirtualDevice *self,
|
||||||
|
char **scan_id,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) local_error = NULL;
|
||||||
|
gboolean cont;
|
||||||
|
|
||||||
|
if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE)
|
||||||
|
self->injected_synthetic_cmd = FALSE;
|
||||||
|
|
||||||
|
cont = process_cmds (self, TRUE, scan_id, &local_error);
|
||||||
|
/* We report finger needed if we are waiting for instructions
|
||||||
|
* (i.e. we did not get an explicit SLEEP command).
|
||||||
|
*/
|
||||||
|
if (!self->sleep_timeout_id)
|
||||||
|
{
|
||||||
|
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||||
|
FP_FINGER_STATUS_NEEDED,
|
||||||
|
FP_FINGER_STATUS_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cont)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Scan or error*/
|
||||||
|
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
||||||
|
FP_FINGER_STATUS_NEEDED,
|
||||||
|
FP_FINGER_STATUS_NONE);
|
||||||
|
|
||||||
|
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 TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
process_cmds (self, FALSE, NULL, &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;
|
||||||
|
|
||||||
|
if (!start_scan_command (self, &scan_id, &error))
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
g_clear_object (&new_scan);
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!start_scan_command (self, &id, &error))
|
||||||
|
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);
|
||||||
|
g_clear_handle_id (&self->wait_command_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);
|
||||||
|
|
||||||
|
self->ignore_wait = TRUE;
|
||||||
|
if (!process_cmds (self, FALSE, NULL, &error))
|
||||||
|
{
|
||||||
|
self->ignore_wait = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self->ignore_wait = FALSE;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_device_close_complete (dev, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
fpi_device_class_auto_initialize_features (dev_class);
|
||||||
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
/*
|
/*
|
||||||
* This is a virtual driver to debug the image based drivers. A small
|
* This is a virtual driver to debug the image based drivers. A small
|
||||||
* python script is provided to connect to it via a socket, allowing
|
* python script is provided to connect to it via a socket, allowing
|
||||||
* prints to be sent to this device programatically.
|
* prints to be sent to this device programmatically.
|
||||||
* Using this it is possible to test libfprint and fprintd.
|
* Using this it is possible to test libfprint and fprintd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -29,24 +29,18 @@
|
||||||
|
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
|
|
||||||
|
#include "virtual-device-private.h"
|
||||||
|
|
||||||
#include "../fpi-image.h"
|
#include "../fpi-image.h"
|
||||||
#include "../fpi-image-device.h"
|
#include "../fpi-image-device.h"
|
||||||
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <gio/gunixsocketaddress.h>
|
|
||||||
|
|
||||||
struct _FpDeviceVirtualImage
|
struct _FpDeviceVirtualImage
|
||||||
{
|
{
|
||||||
FpImageDevice parent;
|
FpImageDevice parent;
|
||||||
|
|
||||||
GSocketListener *listener;
|
FpiDeviceVirtualListener *listener;
|
||||||
GSocketConnection *connection;
|
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
gint socket_fd;
|
|
||||||
gint client_fd;
|
|
||||||
|
|
||||||
gboolean automatic_finger;
|
gboolean automatic_finger;
|
||||||
FpImage *recv_img;
|
FpImage *recv_img;
|
||||||
gint recv_img_hdr[2];
|
gint recv_img_hdr[2];
|
||||||
|
@ -55,9 +49,7 @@ struct _FpDeviceVirtualImage
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
|
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)
|
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
|
||||||
|
|
||||||
static void start_listen (FpDeviceVirtualImage *dev);
|
static void recv_image (FpDeviceVirtualImage *self);
|
||||||
static void recv_image (FpDeviceVirtualImage *dev,
|
|
||||||
GInputStream *stream);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
recv_image_img_recv_cb (GObject *source_object,
|
recv_image_img_recv_cb (GObject *source_object,
|
||||||
|
@ -65,27 +57,16 @@ recv_image_img_recv_cb (GObject *source_object,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||||
FpDeviceVirtualImage *self;
|
FpDeviceVirtualImage *self;
|
||||||
FpImageDevice *device;
|
FpImageDevice *device;
|
||||||
gboolean success;
|
gsize bytes;
|
||||||
gsize bytes = 0;
|
|
||||||
|
|
||||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
|
||||||
|
|
||||||
if (!success || bytes == 0)
|
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))
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
||||||
return;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
device = FP_IMAGE_DEVICE (self);
|
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);
|
fpi_image_device_report_finger_status (device, FALSE);
|
||||||
|
|
||||||
/* And, listen for more images from the same client. */
|
/* And, listen for more images from the same client. */
|
||||||
recv_image (self, G_INPUT_STREAM (source_object));
|
recv_image (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -107,33 +88,30 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FpDeviceVirtualImage *self;
|
FpDeviceVirtualImage *self;
|
||||||
gboolean success;
|
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
|
||||||
gsize bytes;
|
gsize bytes;
|
||||||
|
|
||||||
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
bytes = fpi_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) ||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) ||
|
||||||
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_warning ("Error receiving header for image data: %s", error->message);
|
g_warning ("Error receiving header for image data: %s", error->message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
if (!bytes)
|
||||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
|
||||||
g_clear_object (&self->connection);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
|
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_warning ("Image header suggests an unrealistically large image, disconnecting client.");
|
||||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
fpi_device_virtual_listener_connection_close (listener);
|
||||||
g_clear_object (&self->connection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
||||||
|
@ -162,132 +140,100 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||||
!!self->recv_img_hdr[1]);
|
!!self->recv_img_hdr[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case -5:
|
||||||
|
/* -5 causes the device to disappear (no further data) */
|
||||||
|
fpi_device_remove (FP_DEVICE (self));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* disconnect client, it didn't play fair */
|
/* disconnect client, it didn't play fair */
|
||||||
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
fpi_device_virtual_listener_connection_close (listener);
|
||||||
g_clear_object (&self->connection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And, listen for more images from the same client. */
|
/* And, listen for more images from the same client. */
|
||||||
recv_image (self, G_INPUT_STREAM (source_object));
|
recv_image (self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
|
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_debug ("image data: %p", self->recv_img->data);
|
||||||
g_input_stream_read_all_async (G_INPUT_STREAM (source_object),
|
fpi_device_virtual_listener_read (listener,
|
||||||
|
TRUE,
|
||||||
(guint8 *) self->recv_img->data,
|
(guint8 *) self->recv_img->data,
|
||||||
self->recv_img->width * self->recv_img->height,
|
self->recv_img->width * self->recv_img->height,
|
||||||
G_PRIORITY_DEFAULT,
|
|
||||||
self->cancellable,
|
|
||||||
recv_image_img_recv_cb,
|
recv_image_img_recv_cb,
|
||||||
self);
|
self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
|
recv_image (FpDeviceVirtualImage *self)
|
||||||
{
|
{
|
||||||
g_input_stream_read_all_async (stream,
|
fpi_device_virtual_listener_read (self->listener,
|
||||||
dev->recv_img_hdr,
|
TRUE,
|
||||||
sizeof (dev->recv_img_hdr),
|
self->recv_img_hdr,
|
||||||
G_PRIORITY_DEFAULT,
|
sizeof (self->recv_img_hdr),
|
||||||
dev->cancellable,
|
|
||||||
recv_image_hdr_recv_cb,
|
recv_image_hdr_recv_cb,
|
||||||
dev);
|
self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
on_listener_connected (FpiDeviceVirtualListener *listener,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
GSocketConnection *connection;
|
FpiImageDeviceState state;
|
||||||
GInputStream *stream;
|
|
||||||
FpDeviceVirtualImage *dev = user_data;
|
|
||||||
|
|
||||||
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
|
self->automatic_finger = TRUE;
|
||||||
res,
|
|
||||||
NULL,
|
g_object_get (self,
|
||||||
&error);
|
"fpi-image-device-state", &state,
|
||||||
if (!connection)
|
NULL);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
{
|
{
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
case FPI_IMAGE_DEVICE_STATE_IDLE:
|
||||||
return;
|
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
||||||
|
recv_image (self);
|
||||||
|
|
||||||
g_warning ("Error accepting a new connection: %s", error->message);
|
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||||
start_listen (dev);
|
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
|
||||||
|
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_init (FpImageDevice *dev)
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autoptr(GSocketListener) listener = NULL;
|
g_autoptr(FpiDeviceVirtualListener) listener = NULL;
|
||||||
|
g_autoptr(GCancellable) cancellable = NULL;
|
||||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||||
const char *env;
|
|
||||||
g_autoptr(GSocketAddress) addr = NULL;
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
self->client_fd = -1;
|
listener = fpi_device_virtual_listener_new ();
|
||||||
|
cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
env = fpi_device_get_virtual_env (FP_DEVICE (self));
|
if (!fpi_device_virtual_listener_start (listener,
|
||||||
|
fpi_device_get_virtual_env (FP_DEVICE (self)),
|
||||||
listener = g_socket_listener_new ();
|
cancellable,
|
||||||
g_socket_listener_set_backlog (listener, 1);
|
on_listener_connected,
|
||||||
|
self,
|
||||||
/* 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))
|
&error))
|
||||||
{
|
{
|
||||||
g_warning ("Could not listen on unix socket: %s", error->message);
|
fpi_image_device_open_complete (dev, g_steal_pointer (&error));
|
||||||
|
|
||||||
fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->listener = g_steal_pointer (&listener);
|
self->listener = g_steal_pointer (&listener);
|
||||||
self->cancellable = g_cancellable_new ();
|
self->cancellable = g_steal_pointer (&cancellable);
|
||||||
|
|
||||||
start_listen (self);
|
/* 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);
|
||||||
fpi_image_device_open_complete (dev, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -300,14 +246,58 @@ dev_deinit (FpImageDevice *dev)
|
||||||
g_cancellable_cancel (self->cancellable);
|
g_cancellable_cancel (self->cancellable);
|
||||||
g_clear_object (&self->cancellable);
|
g_clear_object (&self->cancellable);
|
||||||
g_clear_object (&self->listener);
|
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
|
static void
|
||||||
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
|
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[] = {
|
static const FpIdEntry driver_ids[] = {
|
||||||
|
@ -328,4 +318,7 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
img_class->img_open = dev_init;
|
||||||
img_class->img_close = dev_deinit;
|
img_class->img_close = dev_deinit;
|
||||||
|
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Driver API definitions
|
* Driver API definitions
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||||
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -18,17 +19,15 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DRIVERS_API_H__
|
#pragma once
|
||||||
#define __DRIVERS_API_H__
|
|
||||||
|
|
||||||
#include <config.h>
|
#include "fpi-compat.h"
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
#include "fpi-log.h"
|
|
||||||
#include "fpi-usb-transfer.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
#include "fpi-assembling.h"
|
#include "fpi-assembling.h"
|
||||||
|
#include "fpi-device.h"
|
||||||
#include "fpi-image-device.h"
|
#include "fpi-image-device.h"
|
||||||
|
#include "fpi-image.h"
|
||||||
#endif
|
#include "fpi-log.h"
|
||||||
|
#include "fpi-print.h"
|
||||||
|
#include "fpi-usb-transfer.h"
|
||||||
|
#include "fpi-spi-transfer.h"
|
||||||
|
#include "fpi-ssm.h"
|
||||||
|
|
|
@ -23,6 +23,13 @@
|
||||||
#include "fpi-context.h"
|
#include "fpi-context.h"
|
||||||
#include "fpi-device.h"
|
#include "fpi-device.h"
|
||||||
#include <gusb.h>
|
#include <gusb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_UDEV
|
||||||
|
#include <gudev/gudev.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fp-context
|
* SECTION: fp-context
|
||||||
|
@ -41,6 +48,8 @@ typedef struct
|
||||||
GUsbContext *usb_ctx;
|
GUsbContext *usb_ctx;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
GSList *sources;
|
||||||
|
|
||||||
gint pending_devices;
|
gint pending_devices;
|
||||||
gboolean enumerated;
|
gboolean enumerated;
|
||||||
|
|
||||||
|
@ -57,6 +66,112 @@ enum {
|
||||||
};
|
};
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_drivers_whitelist_env (void)
|
||||||
|
{
|
||||||
|
return g_getenv ("FP_DRIVERS_WHITELIST");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_driver_allowed (const gchar *driver)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) whitelisted_drivers = NULL;
|
||||||
|
const char *fp_drivers_whitelist_env;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (driver, TRUE);
|
||||||
|
|
||||||
|
fp_drivers_whitelist_env = get_drivers_whitelist_env ();
|
||||||
|
|
||||||
|
if (!fp_drivers_whitelist_env)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
whitelisted_drivers = g_strsplit (fp_drivers_whitelist_env, ":", -1);
|
||||||
|
|
||||||
|
for (i = 0; whitelisted_drivers[i]; ++i)
|
||||||
|
if (g_strcmp0 (driver, whitelisted_drivers[i]) == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpContext *context;
|
||||||
|
FpDevice *device;
|
||||||
|
GSource *source;
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_device_data_free (RemoveDeviceData *data)
|
||||||
|
{
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
|
||||||
|
|
||||||
|
priv->sources = g_slist_remove (priv->sources, data->source);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_device (FpContext *context, FpDevice *device)
|
||||||
|
{
|
||||||
|
g_autoptr(GSource) source = NULL;
|
||||||
|
FpContextPrivate *priv = fp_context_get_instance_private (context);
|
||||||
|
RemoveDeviceData *data;
|
||||||
|
|
||||||
|
data = g_new (RemoveDeviceData, 1);
|
||||||
|
data->context = context;
|
||||||
|
data->device = device;
|
||||||
|
|
||||||
|
source = data->source = g_idle_source_new ();
|
||||||
|
g_source_set_callback (source,
|
||||||
|
G_SOURCE_FUNC (remove_device_idle_cb), data,
|
||||||
|
(GDestroyNotify) remove_device_data_free);
|
||||||
|
g_source_attach (source, g_main_context_get_thread_default ());
|
||||||
|
|
||||||
|
priv->sources = g_slist_prepend (priv->sources, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_object (device, "notify::open",
|
||||||
|
(GCallback) device_remove_on_notify_open_cb,
|
||||||
|
context,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remove_device (context, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -65,23 +180,28 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
|
||||||
FpContext *context;
|
FpContext *context;
|
||||||
FpContextPrivate *priv;
|
FpContextPrivate *priv;
|
||||||
|
|
||||||
device = (FpDevice *) g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error);
|
device = FP_DEVICE (g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
|
||||||
if (!device)
|
res, &error));
|
||||||
{
|
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
context = FP_CONTEXT (user_data);
|
context = FP_CONTEXT (user_data);
|
||||||
priv = fp_context_get_instance_private (context);
|
priv = fp_context_get_instance_private (context);
|
||||||
priv->pending_devices--;
|
priv->pending_devices--;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
g_message ("Ignoring device due to initialization error: %s", error->message);
|
g_message ("Ignoring device due to initialization error: %s", error->message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = FP_CONTEXT (user_data);
|
|
||||||
priv = fp_context_get_instance_private (context);
|
|
||||||
priv->pending_devices--;
|
|
||||||
g_ptr_array_add (priv->devices, device);
|
g_ptr_array_add (priv->devices, device);
|
||||||
|
|
||||||
|
g_signal_connect_object (device, "removed",
|
||||||
|
(GCallback) device_removed_cb,
|
||||||
|
context,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
|
||||||
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +222,11 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||||
for (i = 0; i < priv->drivers->len; i++)
|
for (i = 0; i < priv->drivers->len; i++)
|
||||||
{
|
{
|
||||||
GType driver = g_array_index (priv->drivers, GType, i);
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||||
const FpIdEntry *entry;
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
if (cls->type != FP_DEVICE_TYPE_USB)
|
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||||
{
|
|
||||||
g_type_class_unref (cls);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (entry = cls->id_table; entry->pid; entry++)
|
for (entry = cls->id_table; entry->pid; entry++)
|
||||||
{
|
{
|
||||||
|
@ -129,13 +246,11 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||||
found_driver = driver;
|
found_driver = driver;
|
||||||
found_entry = entry;
|
found_entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_type_class_unref (cls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_driver == G_TYPE_NONE)
|
if (found_driver == G_TYPE_NONE)
|
||||||
{
|
{
|
||||||
g_debug ("No driver found for USB device %04X:%04X", pid, vid);
|
g_debug ("No driver found for USB device %04X:%04X", vid, pid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +260,8 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
|
||||||
priv->cancellable,
|
priv->cancellable,
|
||||||
async_device_init_done_cb,
|
async_device_init_done_cb,
|
||||||
self,
|
self,
|
||||||
"fp-usb-device", device,
|
"fpi-usb-device", device,
|
||||||
"fp-driver-data", found_entry->driver_data,
|
"fpi-driver-data", found_entry->driver_data,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,12 +281,7 @@ usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fpi_device_get_usb_device (dev) == device)
|
if (fpi_device_get_usb_device (dev) == device)
|
||||||
{
|
fpi_device_remove (dev);
|
||||||
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
|
|
||||||
g_ptr_array_remove_index_fast (priv->devices, i);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +297,9 @@ fp_context_finalize (GObject *object)
|
||||||
g_clear_object (&priv->cancellable);
|
g_clear_object (&priv->cancellable);
|
||||||
g_clear_pointer (&priv->drivers, g_array_unref);
|
g_clear_pointer (&priv->drivers, g_array_unref);
|
||||||
|
|
||||||
|
g_slist_free_full (g_steal_pointer (&priv->sources), (GDestroyNotify) g_source_destroy);
|
||||||
|
|
||||||
|
if (priv->usb_ctx)
|
||||||
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
||||||
g_clear_object (&priv->usb_ctx);
|
g_clear_object (&priv->usb_ctx);
|
||||||
|
|
||||||
|
@ -224,6 +337,10 @@ fp_context_class_init (FpContextClass *klass)
|
||||||
* @device: A #FpDevice
|
* @device: A #FpDevice
|
||||||
*
|
*
|
||||||
* This signal is emitted when a fingerprint reader is removed.
|
* 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",
|
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
|
||||||
G_TYPE_FROM_CLASS (klass),
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
@ -242,9 +359,23 @@ fp_context_init (FpContext *self)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
FpContextPrivate *priv = fp_context_get_instance_private (self);
|
||||||
|
guint i;
|
||||||
|
|
||||||
priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType));
|
priv->drivers = fpi_get_driver_types ();
|
||||||
fpi_get_driver_types (priv->drivers);
|
|
||||||
|
if (get_drivers_whitelist_env ())
|
||||||
|
{
|
||||||
|
for (i = 0; i < priv->drivers->len;)
|
||||||
|
{
|
||||||
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
|
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||||
|
|
||||||
|
if (!is_driver_allowed (cls->id))
|
||||||
|
g_array_remove_index (priv->drivers, i);
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
|
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
|
|
||||||
|
@ -252,7 +383,7 @@ fp_context_init (FpContext *self)
|
||||||
priv->usb_ctx = g_usb_context_new (&error);
|
priv->usb_ctx = g_usb_context_new (&error);
|
||||||
if (!priv->usb_ctx)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -305,13 +436,14 @@ fp_context_enumerate (FpContext *context)
|
||||||
priv->enumerated = TRUE;
|
priv->enumerated = TRUE;
|
||||||
|
|
||||||
/* USB devices are handled from callbacks */
|
/* USB devices are handled from callbacks */
|
||||||
|
if (priv->usb_ctx)
|
||||||
g_usb_context_enumerate (priv->usb_ctx);
|
g_usb_context_enumerate (priv->usb_ctx);
|
||||||
|
|
||||||
/* Handle Virtual devices based on environment variables */
|
/* Handle Virtual devices based on environment variables */
|
||||||
for (i = 0; i < priv->drivers->len; i++)
|
for (i = 0; i < priv->drivers->len; i++)
|
||||||
{
|
{
|
||||||
GType driver = g_array_index (priv->drivers, GType, i);
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
|
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||||
const FpIdEntry *entry;
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
|
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
|
||||||
|
@ -332,15 +464,106 @@ fp_context_enumerate (FpContext *context)
|
||||||
priv->cancellable,
|
priv->cancellable,
|
||||||
async_device_init_done_cb,
|
async_device_init_done_cb,
|
||||||
context,
|
context,
|
||||||
"fp-environ", val,
|
"fpi-environ", val,
|
||||||
"fp-driver-data", entry->driver_data,
|
"fpi-driver-data", entry->driver_data,
|
||||||
NULL);
|
NULL);
|
||||||
g_debug ("created");
|
g_debug ("created");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_type_class_unref (cls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_UDEV
|
||||||
|
{
|
||||||
|
g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL);
|
||||||
|
|
||||||
|
/* This uses a very simple algorithm to allocate devices to drivers and assumes that no two drivers will want the same device. Future improvements
|
||||||
|
* could add a usb_discover style udev_discover that returns a score, however for internal devices the potential overlap should be very low between
|
||||||
|
* separate drivers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
g_autoptr(GList) spidev_devices = g_udev_client_query_by_subsystem (udev_client, "spidev");
|
||||||
|
g_autoptr(GList) hidraw_devices = g_udev_client_query_by_subsystem (udev_client, "hidraw");
|
||||||
|
|
||||||
|
/* for each potential driver, try to match all requested resources. */
|
||||||
|
for (i = 0; i < priv->drivers->len; i++)
|
||||||
|
{
|
||||||
|
GType driver = g_array_index (priv->drivers, GType, i);
|
||||||
|
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||||
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
|
if (cls->type != FP_DEVICE_TYPE_UDEV)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (entry = cls->id_table; entry->udev_types; entry++)
|
||||||
|
{
|
||||||
|
GList *matched_spidev = NULL, *matched_hidraw = NULL;
|
||||||
|
|
||||||
|
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV)
|
||||||
|
{
|
||||||
|
for (matched_spidev = spidev_devices; matched_spidev; matched_spidev = matched_spidev->next)
|
||||||
|
{
|
||||||
|
const gchar * sysfs = g_udev_device_get_sysfs_path (matched_spidev->data);
|
||||||
|
if (!sysfs)
|
||||||
|
continue;
|
||||||
|
if (strstr (sysfs, entry->spi_acpi_id))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* If match was not found exit */
|
||||||
|
if (matched_spidev == NULL)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
|
||||||
|
{
|
||||||
|
for (matched_hidraw = hidraw_devices; matched_hidraw; matched_hidraw = matched_hidraw->next)
|
||||||
|
{
|
||||||
|
/* Find the parent HID node, and check the vid/pid from its HID_ID property */
|
||||||
|
g_autoptr(GUdevDevice) parent = g_udev_device_get_parent_with_subsystem (matched_hidraw->data, "hid", NULL);
|
||||||
|
const gchar * hid_id = g_udev_device_get_property (parent, "HID_ID");
|
||||||
|
guint32 vendor, product;
|
||||||
|
|
||||||
|
if (!parent || !hid_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sscanf (hid_id, "%*X:%X:%X", &vendor, &product) != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vendor == entry->hid_id.vid && product == entry->hid_id.pid)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* If match was not found exit */
|
||||||
|
if (matched_hidraw == NULL)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
priv->pending_devices++;
|
||||||
|
g_async_initable_new_async (driver,
|
||||||
|
G_PRIORITY_LOW,
|
||||||
|
priv->cancellable,
|
||||||
|
async_device_init_done_cb,
|
||||||
|
context,
|
||||||
|
"fpi-driver-data", entry->driver_data,
|
||||||
|
"fpi-udev-data-spidev", (matched_spidev ? g_udev_device_get_device_file (matched_spidev->data) : NULL),
|
||||||
|
"fpi-udev-data-hidraw", (matched_hidraw ? g_udev_device_get_device_file (matched_hidraw->data) : NULL),
|
||||||
|
NULL);
|
||||||
|
/* remove entries from list to avoid conflicts */
|
||||||
|
if (matched_spidev)
|
||||||
|
{
|
||||||
|
g_object_unref (matched_spidev->data);
|
||||||
|
spidev_devices = g_list_delete_link (spidev_devices, matched_spidev);
|
||||||
|
}
|
||||||
|
if (matched_hidraw)
|
||||||
|
{
|
||||||
|
g_object_unref (matched_hidraw->data);
|
||||||
|
hidraw_devices = g_list_delete_link (hidraw_devices, matched_hidraw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free all unused elemnts in both lists */
|
||||||
|
g_list_foreach (spidev_devices, (GFunc) g_object_unref, NULL);
|
||||||
|
g_list_foreach (hidraw_devices, (GFunc) g_object_unref, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
while (priv->pending_devices)
|
while (priv->pending_devices)
|
||||||
g_main_context_iteration (NULL, TRUE);
|
g_main_context_iteration (NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
@ -351,7 +574,7 @@ fp_context_enumerate (FpContext *context)
|
||||||
*
|
*
|
||||||
* Get all devices. fp_context_enumerate() will be called as needed.
|
* Get all devices. fp_context_enumerate() will be called as needed.
|
||||||
*
|
*
|
||||||
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's.
|
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #FpDevice's.
|
||||||
*/
|
*/
|
||||||
GPtrArray *
|
GPtrArray *
|
||||||
fp_context_get_devices (FpContext *context)
|
fp_context_get_devices (FpContext *context)
|
||||||
|
|
136
libfprint/fp-device-private.h
Normal file
136
libfprint/fp-device-private.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* FpDevice - A fingerprint reader device
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
* Copyright (C) 2019 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-device.h"
|
||||||
|
|
||||||
|
/* Chosen so that if we turn on after WARM -> COLD, it takes exactly one time
|
||||||
|
* constant to go from COLD -> HOT.
|
||||||
|
* TEMP_COLD_THRESH = 1 / (e + 1)
|
||||||
|
*/
|
||||||
|
#define TEMP_COLD_THRESH (0.26894142136999512075)
|
||||||
|
#define TEMP_WARM_HOT_THRESH (1.0 - TEMP_COLD_THRESH)
|
||||||
|
#define TEMP_HOT_WARM_THRESH (0.5)
|
||||||
|
|
||||||
|
/* Delay updates by 100ms to avoid hitting the border exactly */
|
||||||
|
#define TEMP_DELAY_SECONDS 0.1
|
||||||
|
|
||||||
|
/* Hopefully 3min is long enough to not get in the way, while also not
|
||||||
|
* properly overheating any devices.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_TEMP_HOT_SECONDS (3 * 60)
|
||||||
|
#define DEFAULT_TEMP_COLD_SECONDS (9 * 60)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpDeviceType type;
|
||||||
|
|
||||||
|
GUsbDevice *usb_device;
|
||||||
|
const gchar *virtual_env;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
gchar *spidev_path;
|
||||||
|
gchar *hidraw_path;
|
||||||
|
} udev_data;
|
||||||
|
|
||||||
|
gboolean is_removed;
|
||||||
|
gboolean is_open;
|
||||||
|
gboolean is_suspended;
|
||||||
|
|
||||||
|
gchar *device_id;
|
||||||
|
gchar *device_name;
|
||||||
|
FpScanType scan_type;
|
||||||
|
FpDeviceFeature features;
|
||||||
|
|
||||||
|
guint64 driver_data;
|
||||||
|
|
||||||
|
gint nr_enroll_stages;
|
||||||
|
GSList *sources;
|
||||||
|
|
||||||
|
/* We always make sure that only one task is run at a time. */
|
||||||
|
FpiDeviceAction current_action;
|
||||||
|
GTask *current_task;
|
||||||
|
GError *current_cancellation_reason;
|
||||||
|
GAsyncReadyCallback current_user_cb;
|
||||||
|
GCancellable *current_cancellable;
|
||||||
|
gulong current_cancellable_id;
|
||||||
|
gulong current_task_cancellable_id;
|
||||||
|
GSource *current_idle_cancel_source;
|
||||||
|
GSource *current_task_idle_return_source;
|
||||||
|
|
||||||
|
/* State for tasks */
|
||||||
|
gboolean wait_for_finger;
|
||||||
|
FpFingerStatusFlags finger_status;
|
||||||
|
|
||||||
|
/* Driver critical sections */
|
||||||
|
guint critical_section;
|
||||||
|
GSource *critical_section_flush_source;
|
||||||
|
gboolean cancel_queued;
|
||||||
|
gboolean suspend_queued;
|
||||||
|
gboolean resume_queued;
|
||||||
|
|
||||||
|
/* Suspend/resume tasks */
|
||||||
|
GTask *suspend_resume_task;
|
||||||
|
GError *suspend_error;
|
||||||
|
|
||||||
|
/* Device temperature model information and state */
|
||||||
|
GSource *temp_timeout;
|
||||||
|
FpTemperature temp_current;
|
||||||
|
gint32 temp_hot_seconds;
|
||||||
|
gint32 temp_cold_seconds;
|
||||||
|
gint64 temp_last_update;
|
||||||
|
gboolean temp_last_active;
|
||||||
|
gdouble temp_current_ratio;
|
||||||
|
} FpDevicePrivate;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpPrint *print;
|
||||||
|
|
||||||
|
FpEnrollProgress enroll_progress_cb;
|
||||||
|
gpointer enroll_progress_data;
|
||||||
|
GDestroyNotify enroll_progress_destroy;
|
||||||
|
} FpEnrollData;
|
||||||
|
|
||||||
|
void enroll_data_free (FpEnrollData *enroll_data);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpPrint *enrolled_print; /* verify */
|
||||||
|
GPtrArray *gallery; /* identify */
|
||||||
|
|
||||||
|
gboolean result_reported;
|
||||||
|
FpPrint *match;
|
||||||
|
FpPrint *print;
|
||||||
|
GError *error;
|
||||||
|
|
||||||
|
FpMatchCb match_cb;
|
||||||
|
gpointer match_data;
|
||||||
|
GDestroyNotify match_destroy;
|
||||||
|
} FpMatchData;
|
||||||
|
|
||||||
|
void match_data_free (FpMatchData *match_data);
|
||||||
|
|
||||||
|
void fpi_device_configure_wakeup (FpDevice *device,
|
||||||
|
gboolean enabled);
|
||||||
|
void fpi_device_update_temp (FpDevice *device,
|
||||||
|
gboolean is_active);
|
File diff suppressed because it is too large
Load diff
|
@ -38,13 +38,41 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
||||||
/**
|
/**
|
||||||
* FpDeviceType:
|
* FpDeviceType:
|
||||||
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
||||||
|
* @FP_DEVICE_TYPE_UDEV: The device is a udev device
|
||||||
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FP_DEVICE_TYPE_VIRTUAL,
|
FP_DEVICE_TYPE_VIRTUAL,
|
||||||
|
FP_DEVICE_TYPE_UDEV,
|
||||||
FP_DEVICE_TYPE_USB,
|
FP_DEVICE_TYPE_USB,
|
||||||
} FpDeviceType;
|
} FpDeviceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpDeviceFeature:
|
||||||
|
* @FP_DEVICE_FEATURE_NONE: Device does not support any feature
|
||||||
|
* @FP_DEVICE_FEATURE_CAPTURE: Supports image capture
|
||||||
|
* @FP_DEVICE_FEATURE_VERIFY: Supports finger verification
|
||||||
|
* @FP_DEVICE_FEATURE_IDENTIFY: Supports finger identification
|
||||||
|
* @FP_DEVICE_FEATURE_STORAGE: Device has a persistent storage
|
||||||
|
* @FP_DEVICE_FEATURE_STORAGE_LIST: Supports listing the storage templates
|
||||||
|
* @FP_DEVICE_FEATURE_STORAGE_DELETE: Supports deleting stored templates
|
||||||
|
* @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage
|
||||||
|
* @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection
|
||||||
|
* @FP_DEVICE_FEATURE_ALWAYS_ON: Whether the device can run continuously
|
||||||
|
*/
|
||||||
|
typedef enum /*< flags >*/ {
|
||||||
|
FP_DEVICE_FEATURE_NONE = 0,
|
||||||
|
FP_DEVICE_FEATURE_CAPTURE = 1 << 0,
|
||||||
|
FP_DEVICE_FEATURE_IDENTIFY = 1 << 1,
|
||||||
|
FP_DEVICE_FEATURE_VERIFY = 1 << 2,
|
||||||
|
FP_DEVICE_FEATURE_STORAGE = 1 << 3,
|
||||||
|
FP_DEVICE_FEATURE_STORAGE_LIST = 1 << 4,
|
||||||
|
FP_DEVICE_FEATURE_STORAGE_DELETE = 1 << 5,
|
||||||
|
FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6,
|
||||||
|
FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7,
|
||||||
|
FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8,
|
||||||
|
} FpDeviceFeature;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpScanType:
|
* FpScanType:
|
||||||
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
||||||
|
@ -55,6 +83,23 @@ typedef enum {
|
||||||
FP_SCAN_TYPE_PRESS,
|
FP_SCAN_TYPE_PRESS,
|
||||||
} FpScanType;
|
} FpScanType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpTemperature:
|
||||||
|
* @FP_TEMPERATURE_COLD: Sensor is considered cold.
|
||||||
|
* @FP_TEMPERATURE_WARM: Sensor is warm, usage time may be limited.
|
||||||
|
* @FP_TEMPERATURE_HOT: Sensor is hot and cannot be used.
|
||||||
|
*
|
||||||
|
* When a device is created, it is assumed to be cold. Applications such as
|
||||||
|
* fprintd may want to ensure all devices on the system are cold before
|
||||||
|
* shutting down in order to ensure that the cool-off period is not violated
|
||||||
|
* because the internal libfprint state about the device is lost.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_TEMPERATURE_COLD,
|
||||||
|
FP_TEMPERATURE_WARM,
|
||||||
|
FP_TEMPERATURE_HOT,
|
||||||
|
} FpTemperature;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpDeviceRetry:
|
* FpDeviceRetry:
|
||||||
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
||||||
|
@ -79,7 +124,7 @@ typedef enum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpDeviceError:
|
* FpDeviceError:
|
||||||
* @FP_DEVICE_ERROR_GENERAL: A general error occured.
|
* @FP_DEVICE_ERROR_GENERAL: A general error occurred.
|
||||||
* @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested
|
* @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested
|
||||||
* operation.
|
* operation.
|
||||||
* @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this
|
* @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this
|
||||||
|
@ -90,6 +135,9 @@ typedef enum {
|
||||||
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
* @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_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_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_TOO_HOT: The device might be getting too hot
|
||||||
*
|
*
|
||||||
* Error codes for device operations. More specific errors from other domains
|
* 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.
|
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||||
|
@ -104,6 +152,10 @@ typedef enum {
|
||||||
FP_DEVICE_ERROR_DATA_INVALID,
|
FP_DEVICE_ERROR_DATA_INVALID,
|
||||||
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
||||||
FP_DEVICE_ERROR_DATA_FULL,
|
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_TOO_HOT,
|
||||||
} FpDeviceError;
|
} FpDeviceError;
|
||||||
|
|
||||||
GQuark fp_device_retry_quark (void);
|
GQuark fp_device_retry_quark (void);
|
||||||
|
@ -113,7 +165,7 @@ GQuark fp_device_error_quark (void);
|
||||||
* FpEnrollProgress:
|
* FpEnrollProgress:
|
||||||
* @device: a #FpDevice
|
* @device: a #FpDevice
|
||||||
* @completed_stages: Number of completed stages
|
* @completed_stages: Number of completed stages
|
||||||
* @print: (nullable) (transfer none): The last scaned print
|
* @print: (nullable) (transfer none): The last scanned print
|
||||||
* @user_data: (nullable) (transfer none): User provided data
|
* @user_data: (nullable) (transfer none): User provided data
|
||||||
* @error: (nullable) (transfer none): #GError or %NULL
|
* @error: (nullable) (transfer none): #GError or %NULL
|
||||||
*
|
*
|
||||||
|
@ -125,16 +177,56 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GError *error);
|
GError *error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpMatchCb:
|
||||||
|
* @device: a #FpDevice
|
||||||
|
* @match: (nullable) (transfer none): The matching print if any matched @print
|
||||||
|
* @print: (nullable) (transfer none): The newly scanned print
|
||||||
|
* @user_data: (nullable) (transfer none): User provided data
|
||||||
|
* @error: (nullable) (transfer none): #GError or %NULL
|
||||||
|
*
|
||||||
|
* Report the result of a match (identify or verify) operation.
|
||||||
|
*
|
||||||
|
* If @match is non-%NULL, then it is set to the matching #FpPrint as passed
|
||||||
|
* to the match operation. In this case @error will always be %NULL.
|
||||||
|
*
|
||||||
|
* If @error is not %NULL then its domain is guaranteed to be
|
||||||
|
* %FP_DEVICE_RETRY. All other error conditions will not be reported using
|
||||||
|
* this callback. If such an error occurs before a match/no-match decision
|
||||||
|
* can be made, then this callback will not be called. Should an error
|
||||||
|
* happen afterwards, then you will get a match report through this callback
|
||||||
|
* and an error when the operation finishes.
|
||||||
|
*
|
||||||
|
* If @match and @error are %NULL, then a finger was presented but it did not
|
||||||
|
* match any known print.
|
||||||
|
*
|
||||||
|
* @print represents the newly scanned print. The driver may or may not
|
||||||
|
* provide this information. Image based devices will provide it and it
|
||||||
|
* allows access to the raw data.
|
||||||
|
*
|
||||||
|
* This callback exists because it makes sense for drivers to wait e.g. on
|
||||||
|
* finger removal before completing the match operation. However, the
|
||||||
|
* success/failure can often be reported at an earlier time, and there is
|
||||||
|
* no need to make the user wait.
|
||||||
|
*/
|
||||||
|
typedef void (*FpMatchCb) (FpDevice *device,
|
||||||
|
FpPrint *match,
|
||||||
|
FpPrint *print,
|
||||||
|
gpointer user_data,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
const gchar *fp_device_get_driver (FpDevice *device);
|
const gchar *fp_device_get_driver (FpDevice *device);
|
||||||
const gchar *fp_device_get_device_id (FpDevice *device);
|
const gchar *fp_device_get_device_id (FpDevice *device);
|
||||||
const gchar *fp_device_get_name (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);
|
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);
|
gint fp_device_get_nr_enroll_stages (FpDevice *device);
|
||||||
|
FpTemperature fp_device_get_temperature (FpDevice *device);
|
||||||
|
|
||||||
gboolean fp_device_supports_identify (FpDevice *device);
|
FpDeviceFeature fp_device_get_features (FpDevice *device);
|
||||||
gboolean fp_device_supports_capture (FpDevice *device);
|
gboolean fp_device_has_feature (FpDevice *device,
|
||||||
gboolean fp_device_has_storage (FpDevice *device);
|
FpDeviceFeature feature);
|
||||||
|
|
||||||
/* Opening the device */
|
/* Opening the device */
|
||||||
void fp_device_open (FpDevice *device,
|
void fp_device_open (FpDevice *device,
|
||||||
|
@ -147,6 +239,16 @@ void fp_device_close (FpDevice *device,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_suspend (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_resume (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
void fp_device_enroll (FpDevice *device,
|
void fp_device_enroll (FpDevice *device,
|
||||||
FpPrint *template_print,
|
FpPrint *template_print,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
@ -159,12 +261,18 @@ void fp_device_enroll (FpDevice *device,
|
||||||
void fp_device_verify (FpDevice *device,
|
void fp_device_verify (FpDevice *device,
|
||||||
FpPrint *enrolled_print,
|
FpPrint *enrolled_print,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
FpMatchCb match_cb,
|
||||||
|
gpointer match_data,
|
||||||
|
GDestroyNotify match_destroy,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
void fp_device_identify (FpDevice *device,
|
void fp_device_identify (FpDevice *device,
|
||||||
GPtrArray *prints,
|
GPtrArray *prints,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
FpMatchCb match_cb,
|
||||||
|
gpointer match_data,
|
||||||
|
GDestroyNotify match_destroy,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
@ -185,12 +293,23 @@ void fp_device_list_prints (FpDevice *device,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
void fp_device_clear_storage (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
gboolean fp_device_open_finish (FpDevice *device,
|
gboolean fp_device_open_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fp_device_close_finish (FpDevice *device,
|
gboolean fp_device_close_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fp_device_suspend_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_resume_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
FpPrint *fp_device_enroll_finish (FpDevice *device,
|
FpPrint *fp_device_enroll_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -213,7 +332,9 @@ gboolean fp_device_delete_print_finish (FpDevice *device,
|
||||||
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fp_device_clear_storage_finish (FpDevice *device,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean fp_device_open_sync (FpDevice *device,
|
gboolean fp_device_open_sync (FpDevice *device,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
@ -230,12 +351,16 @@ FpPrint * fp_device_enroll_sync (FpDevice *device,
|
||||||
gboolean fp_device_verify_sync (FpDevice *device,
|
gboolean fp_device_verify_sync (FpDevice *device,
|
||||||
FpPrint *enrolled_print,
|
FpPrint *enrolled_print,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
FpMatchCb match_cb,
|
||||||
|
gpointer match_data,
|
||||||
gboolean *match,
|
gboolean *match,
|
||||||
FpPrint **print,
|
FpPrint **print,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fp_device_identify_sync (FpDevice *device,
|
gboolean fp_device_identify_sync (FpDevice *device,
|
||||||
GPtrArray *prints,
|
GPtrArray *prints,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
FpMatchCb match_cb,
|
||||||
|
gpointer match_data,
|
||||||
FpPrint **match,
|
FpPrint **match,
|
||||||
FpPrint **print,
|
FpPrint **print,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -250,6 +375,22 @@ gboolean fp_device_delete_print_sync (FpDevice *device,
|
||||||
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean fp_device_clear_storage_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_suspend_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
gboolean fp_device_resume_sync (FpDevice *device,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
/* Deprecated functions */
|
||||||
|
G_DEPRECATED_FOR (fp_device_get_features)
|
||||||
|
gboolean fp_device_supports_identify (FpDevice *device);
|
||||||
|
G_DEPRECATED_FOR (fp_device_get_features)
|
||||||
|
gboolean fp_device_supports_capture (FpDevice *device);
|
||||||
|
G_DEPRECATED_FOR (fp_device_get_features)
|
||||||
|
gboolean fp_device_has_storage (FpDevice *device);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Driver IDs
|
* FpImageDevice - An image based fingerprint reader device
|
||||||
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,31 +17,29 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DRIVER_IDS
|
#pragma once
|
||||||
#define __DRIVER_IDS
|
|
||||||
|
|
||||||
enum {
|
#include "fpi-image-device.h"
|
||||||
UPEKTS_ID = 1,
|
|
||||||
URU4000_ID = 2,
|
|
||||||
AES4000_ID = 3,
|
|
||||||
AES2501_ID = 4,
|
|
||||||
UPEKTC_ID = 5,
|
|
||||||
AES1610_ID = 6,
|
|
||||||
/* FDU2000_ID = 7, */
|
|
||||||
VCOM5S_ID = 8,
|
|
||||||
UPEKSONLY_ID = 9,
|
|
||||||
VFS101_ID = 10,
|
|
||||||
VFS301_ID = 11,
|
|
||||||
AES2550_ID = 12,
|
|
||||||
/* UPEKE2_ID = 13 */
|
|
||||||
AES1660_ID = 14,
|
|
||||||
AES2660_ID = 15,
|
|
||||||
AES3500_ID = 16,
|
|
||||||
UPEKTC_IMG_ID = 17,
|
|
||||||
ETES603_ID = 18,
|
|
||||||
VFS5011_ID = 19,
|
|
||||||
VFS0050_ID = 20,
|
|
||||||
ELAN_ID = 21,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#define IMG_ENROLL_STAGES 5
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpiImageDeviceState state;
|
||||||
|
gboolean active;
|
||||||
|
|
||||||
|
gboolean finger_present;
|
||||||
|
|
||||||
|
gint enroll_stage;
|
||||||
|
|
||||||
|
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,
|
||||||
|
gboolean cancelling);
|
|
@ -20,14 +20,9 @@
|
||||||
#define FP_COMPONENT "image_device"
|
#define FP_COMPONENT "image_device"
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
|
|
||||||
#include "fpi-image-device.h"
|
#include "fp-image-device-private.h"
|
||||||
#include "fpi-enums.h"
|
|
||||||
#include "fpi-print.h"
|
|
||||||
#include "fpi-image.h"
|
|
||||||
|
|
||||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
|
||||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||||
#define IMG_ENROLL_STAGES 5
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fp-image-device
|
* SECTION: fp-image-device
|
||||||
|
@ -37,30 +32,6 @@
|
||||||
* This is a helper class for the commonly found image based devices.
|
* This is a helper class for the commonly found image based devices.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION: fpi-image-device
|
|
||||||
* @title: Internal FpImageDevice
|
|
||||||
* @short_description: Internal image device routines
|
|
||||||
*
|
|
||||||
* See #FpImageDeviceClass for more details. Also see the public
|
|
||||||
* #FpImageDevice routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
FpImageDeviceState state;
|
|
||||||
gboolean active;
|
|
||||||
gboolean cancelling;
|
|
||||||
|
|
||||||
gboolean enroll_await_on_pending;
|
|
||||||
gint enroll_stage;
|
|
||||||
|
|
||||||
guint pending_activation_timeout_id;
|
|
||||||
gboolean pending_activation_timeout_waiting_finger_off;
|
|
||||||
|
|
||||||
gint bz3_threshold;
|
|
||||||
} FpImageDevicePrivate;
|
|
||||||
|
|
||||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -85,91 +56,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/* Static helper functions */
|
|
||||||
|
|
||||||
static void
|
|
||||||
fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
|
|
||||||
/* Cannot change to inactive using this function. */
|
|
||||||
g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
|
|
||||||
|
|
||||||
priv->state = state;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
|
||||||
g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fp_image_device_activate (FpImageDevice *self)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (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 = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_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");
|
|
||||||
cls->activate (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fp_image_device_deactivate (FpDevice *device)
|
|
||||||
{
|
|
||||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
|
||||||
|
|
||||||
if (!priv->active)
|
|
||||||
{
|
|
||||||
/* 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 == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
|
|
||||||
|
|
||||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
|
||||||
|
|
||||||
fp_dbg ("Deactivating image device\n");
|
|
||||||
cls->deactivate (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
/* Callbacks/vfuncs */
|
||||||
static void
|
static void
|
||||||
fp_image_device_open (FpDevice *device)
|
fp_image_device_open (FpDevice *device)
|
||||||
|
@ -188,47 +74,25 @@ fp_image_device_close (FpDevice *device)
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
/* In the close case we may need to wait/force deactivation first.
|
g_assert (priv->active == FALSE);
|
||||||
* Three possible cases:
|
|
||||||
* 1. We are inactive
|
|
||||||
* -> immediately close
|
|
||||||
* 2. We are waiting for finger off
|
|
||||||
* -> imediately deactivate
|
|
||||||
* 3. We are deactivating
|
|
||||||
* -> handled by deactivate_complete */
|
|
||||||
|
|
||||||
if (!priv->active)
|
|
||||||
cls->img_close (self);
|
cls->img_close (self);
|
||||||
else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE)
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fp_image_device_cancel_action (FpDevice *device)
|
fp_image_device_cancel_action (FpDevice *device)
|
||||||
{
|
{
|
||||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpiDeviceAction action;
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (device);
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
/* We can only cancel capture operations, in that case, deactivate and return
|
/* We can only cancel capture operations, in that case, deactivate and return
|
||||||
* an error immediately. */
|
* an error immediately. */
|
||||||
if (action == FP_DEVICE_ACTION_ENROLL ||
|
if (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||||
action == FP_DEVICE_ACTION_VERIFY ||
|
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||||
action == FP_DEVICE_ACTION_CAPTURE)
|
action == FPI_DEVICE_ACTION_CAPTURE)
|
||||||
{
|
fpi_image_device_deactivate (self, TRUE);
|
||||||
priv->cancelling = TRUE;
|
|
||||||
fp_image_device_deactivate (FP_DEVICE (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"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -236,14 +100,14 @@ fp_image_device_start_capture_action (FpDevice *device)
|
||||||
{
|
{
|
||||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
FpDeviceAction action;
|
FpiDeviceAction action;
|
||||||
|
|
||||||
/* There is just one action that we cannot support out
|
/* There is just one action that we cannot support out
|
||||||
* of the box, which is a capture without first waiting
|
* of the box, which is a capture without first waiting
|
||||||
* for a finger to be on the device.
|
* for a finger to be on the device.
|
||||||
*/
|
*/
|
||||||
action = fpi_device_get_current_action (device);
|
action = fpi_device_get_current_action (device);
|
||||||
if (action == FP_DEVICE_ACTION_CAPTURE)
|
if (action == FPI_DEVICE_ACTION_CAPTURE)
|
||||||
{
|
{
|
||||||
gboolean wait_for_finger;
|
gboolean wait_for_finger;
|
||||||
|
|
||||||
|
@ -255,40 +119,22 @@ fp_image_device_start_capture_action (FpDevice *device)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (action == FP_DEVICE_ACTION_ENROLL)
|
else if (action == FPI_DEVICE_ACTION_ENROLL)
|
||||||
{
|
{
|
||||||
FpPrint *enroll_print = NULL;
|
FpPrint *enroll_print = NULL;
|
||||||
|
|
||||||
fpi_device_get_enroll_data (device, &enroll_print);
|
fpi_device_get_enroll_data (device, &enroll_print);
|
||||||
fpi_print_set_type (enroll_print, FP_PRINT_NBIS);
|
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->enroll_stage = 0;
|
priv->enroll_stage = 0;
|
||||||
priv->enroll_await_on_pending = FALSE;
|
/* The internal state machine guarantees both of these. */
|
||||||
|
g_assert (!priv->finger_present);
|
||||||
/* The device might still be deactivating from a previous call.
|
g_assert (!priv->minutiae_scan_active);
|
||||||
* 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 != FP_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 == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
|
||||||
priv->pending_activation_timeout_waiting_finger_off = TRUE;
|
|
||||||
else
|
|
||||||
priv->pending_activation_timeout_waiting_finger_off = FALSE;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
||||||
* to be called when done (or immediately). */
|
* to be called when done (or immediately). */
|
||||||
fp_image_device_activate (self);
|
fpi_image_device_activate (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,7 +147,6 @@ fp_image_device_finalize (GObject *object)
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
g_assert (priv->active == FALSE);
|
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);
|
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -338,6 +183,21 @@ fp_image_device_get_property (GObject *object,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fp_image_device_constructed (GObject *obj)
|
||||||
|
{
|
||||||
|
FpImageDevice *self = FP_IMAGE_DEVICE (obj);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
|
||||||
|
/* Set default threshold. */
|
||||||
|
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
|
if (cls->bz3_threshold > 0)
|
||||||
|
priv->bz3_threshold = cls->bz3_threshold;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (fp_image_device_parent_class)->constructed (obj);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fp_image_device_class_init (FpImageDeviceClass *klass)
|
fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
{
|
{
|
||||||
|
@ -346,6 +206,10 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
|
|
||||||
object_class->finalize = fp_image_device_finalize;
|
object_class->finalize = fp_image_device_finalize;
|
||||||
object_class->get_property = fp_image_device_get_property;
|
object_class->get_property = fp_image_device_get_property;
|
||||||
|
object_class->constructed = fp_image_device_constructed;
|
||||||
|
|
||||||
|
/* Set default enroll stage count. */
|
||||||
|
fp_device_class->nr_enroll_stages = IMG_ENROLL_STAGES;
|
||||||
|
|
||||||
fp_device_class->open = fp_image_device_open;
|
fp_device_class->open = fp_image_device_open;
|
||||||
fp_device_class->close = fp_image_device_close;
|
fp_device_class->close = fp_image_device_close;
|
||||||
|
@ -356,25 +220,43 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
|
|
||||||
fp_device_class->cancel = fp_image_device_cancel_action;
|
fp_device_class->cancel = fp_image_device_cancel_action;
|
||||||
|
|
||||||
|
fpi_device_class_auto_initialize_features (fp_device_class);
|
||||||
|
|
||||||
/* Default implementations */
|
/* Default implementations */
|
||||||
klass->activate = fp_image_device_default_activate;
|
klass->activate = fp_image_device_default_activate;
|
||||||
klass->deactivate = fp_image_device_default_deactivate;
|
klass->deactivate = fp_image_device_default_deactivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpImageDevice::fpi-image-device-state: (skip)
|
||||||
|
*
|
||||||
|
* This property is only for internal purposes.
|
||||||
|
*
|
||||||
|
* Stability: private
|
||||||
|
*/
|
||||||
properties[PROP_FPI_STATE] =
|
properties[PROP_FPI_STATE] =
|
||||||
g_param_spec_enum ("fp-image-device-state",
|
g_param_spec_enum ("fpi-image-device-state",
|
||||||
"Image Device State",
|
"Image Device State",
|
||||||
"Private: The state of the image device",
|
"Private: The state of the image device",
|
||||||
FP_TYPE_IMAGE_DEVICE_STATE,
|
FPI_TYPE_IMAGE_DEVICE_STATE,
|
||||||
FP_IMAGE_DEVICE_STATE_INACTIVE,
|
FPI_IMAGE_DEVICE_STATE_INACTIVE,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpImageDevice::fpi-image-device-state-changed: (skip)
|
||||||
|
* @image_device: A #FpImageDevice
|
||||||
|
* @new_state: The new state of the device
|
||||||
|
*
|
||||||
|
* This signal is only for internal purposes.
|
||||||
|
*
|
||||||
|
* Stability: private
|
||||||
|
*/
|
||||||
signals[FPI_STATE_CHANGED] =
|
signals[FPI_STATE_CHANGED] =
|
||||||
g_signal_new ("fp-image-device-state-changed",
|
g_signal_new ("fpi-image-device-state-changed",
|
||||||
G_TYPE_FROM_CLASS (object_class),
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
G_SIGNAL_RUN_FIRST,
|
G_SIGNAL_RUN_FIRST,
|
||||||
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
|
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE);
|
G_TYPE_NONE, 1, FPI_TYPE_IMAGE_DEVICE_STATE);
|
||||||
|
|
||||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||||
}
|
}
|
||||||
|
@ -382,497 +264,4 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
static void
|
static void
|
||||||
fp_image_device_init (FpImageDevice *self)
|
fp_image_device_init (FpImageDevice *self)
|
||||||
{
|
{
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
|
||||||
|
|
||||||
/* Set default values. */
|
|
||||||
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
|
|
||||||
|
|
||||||
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
|
||||||
if (cls->bz3_threshold > 0)
|
|
||||||
priv->bz3_threshold = cls->bz3_threshold;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
priv->enroll_await_on_pending = FALSE;
|
|
||||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
priv->enroll_await_on_pending = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(FpImage) image = FP_IMAGE (source_object);
|
|
||||||
g_autoptr(FpPrint) print = NULL;
|
|
||||||
GError *error = NULL;
|
|
||||||
FpDevice *device = FP_DEVICE (user_data);
|
|
||||||
FpImageDevicePrivate *priv;
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
/* Note: We rely on the device to not disappear during an operation. */
|
|
||||||
|
|
||||||
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));
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Replace error with a retry condition. */
|
|
||||||
g_warning ("Failed to detect minutiae: %s", error->message);
|
|
||||||
g_clear_pointer (&error, g_error_free);
|
|
||||||
|
|
||||||
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 == FP_DEVICE_ACTION_CAPTURE)
|
|
||||||
{
|
|
||||||
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error)
|
|
||||||
{
|
|
||||||
print = fp_print_new (device);
|
|
||||||
fpi_print_set_type (print, FP_PRINT_NBIS);
|
|
||||||
if (!fpi_print_add_from_image (print, image, &error))
|
|
||||||
g_clear_object (&print);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == FP_DEVICE_ACTION_ENROLL)
|
|
||||||
{
|
|
||||||
FpPrint *enroll_print;
|
|
||||||
fpi_device_get_enroll_data (device, &enroll_print);
|
|
||||||
|
|
||||||
if (print)
|
|
||||||
{
|
|
||||||
fpi_print_add_print (enroll_print, print);
|
|
||||||
priv->enroll_stage += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_device_enroll_progress (device, priv->enroll_stage,
|
|
||||||
g_steal_pointer (&print), error);
|
|
||||||
|
|
||||||
/* Start another scan or deactivate. */
|
|
||||||
if (priv->enroll_stage == IMG_ENROLL_STAGES)
|
|
||||||
{
|
|
||||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (action == FP_DEVICE_ACTION_VERIFY)
|
|
||||||
{
|
|
||||||
FpPrint *template;
|
|
||||||
FpiMatchResult result;
|
|
||||||
|
|
||||||
fpi_device_get_verify_data (device, &template);
|
|
||||||
if (print)
|
|
||||||
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
|
|
||||||
else
|
|
||||||
result = FPI_MATCH_ERROR;
|
|
||||||
|
|
||||||
fpi_device_verify_complete (device, result, g_steal_pointer (&print), error);
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
}
|
|
||||||
else if (action == FP_DEVICE_ACTION_IDENTIFY)
|
|
||||||
{
|
|
||||||
gint i;
|
|
||||||
GPtrArray *templates;
|
|
||||||
FpPrint *result = NULL;
|
|
||||||
|
|
||||||
fpi_device_get_identify_data (device, &templates);
|
|
||||||
for (i = 0; !error && i < templates->len; i++)
|
|
||||||
{
|
|
||||||
FpPrint *template = g_ptr_array_index (templates, i);
|
|
||||||
|
|
||||||
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
|
|
||||||
{
|
|
||||||
result = g_object_ref (template);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_device_identify_complete (device, result, g_steal_pointer (&print), error);
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* XXX: This can be hit currently due to a race condition in the enroll code!
|
|
||||||
* In that case we scan a further image even though the minutiae for the previous
|
|
||||||
* one have not yet been detected.
|
|
||||||
* We need to keep track on the pending minutiae detection and the fact that
|
|
||||||
* it will finish eventually (or we may need to retry on error and activate the
|
|
||||||
* device again). */
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************/
|
|
||||||
/* Private API */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_set_bz3_threshold:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @bz3_threshold: BZ3 threshold to use
|
|
||||||
*
|
|
||||||
* Dynamically adjust the bz3 threshold. This is only needed for drivers
|
|
||||||
* that support devices with different properties. It should generally be
|
|
||||||
* called from the probe callback, but is acceptable to call from the open
|
|
||||||
* callback.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
|
|
||||||
gint bz3_threshold)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
|
|
||||||
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
|
|
||||||
g_return_if_fail (bz3_threshold > 0);
|
|
||||||
|
|
||||||
priv->bz3_threshold = bz3_threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_report_finger_status:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @present: whether the finger is present on the sensor
|
|
||||||
*
|
|
||||||
* Reports from the driver whether the user's finger is on
|
|
||||||
* the sensor.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_report_finger_status (FpImageDevice *self,
|
|
||||||
gboolean present)
|
|
||||||
{
|
|
||||||
FpDevice *device = FP_DEVICE (self);
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
|
||||||
{
|
|
||||||
/* Do we really want to always ignore such reports? We could
|
|
||||||
* also track the state in case the user had the finger on
|
|
||||||
* the device at initialisation time and the driver reports
|
|
||||||
* this early.
|
|
||||||
*/
|
|
||||||
g_debug ("Ignoring finger presence report as the device is not active!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (device);
|
|
||||||
|
|
||||||
g_assert (action != FP_DEVICE_ACTION_OPEN);
|
|
||||||
g_assert (action != FP_DEVICE_ACTION_CLOSE);
|
|
||||||
|
|
||||||
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
|
||||||
|
|
||||||
if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
{
|
|
||||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE);
|
|
||||||
}
|
|
||||||
else if (!present && priv->state == FP_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.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
if (action != FP_DEVICE_ACTION_ENROLL)
|
|
||||||
fp_image_device_deactivate (device);
|
|
||||||
else
|
|
||||||
fp_image_device_enroll_maybe_await_finger_on (self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_image_captured:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @image: whether the finger is present on the sensor
|
|
||||||
*
|
|
||||||
* Reports an image capture. Only use this function if the image was
|
|
||||||
* captured successfully. If there was an issue where the user should
|
|
||||||
* retry, use fpi_image_device_retry_scan() to report the retry condition.
|
|
||||||
*
|
|
||||||
* In the event of a fatal error for the operation use
|
|
||||||
* fpi_image_device_session_error(). This will abort the entire operation
|
|
||||||
* including e.g. an enroll operation which captures multiple images during
|
|
||||||
* one session.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
g_return_if_fail (image != NULL);
|
|
||||||
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE);
|
|
||||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
|
||||||
action == FP_DEVICE_ACTION_VERIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_CAPTURE);
|
|
||||||
|
|
||||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
|
||||||
|
|
||||||
g_debug ("Image device captured an image");
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_retry_scan:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @retry: The #FpDeviceRetry error code to report
|
|
||||||
*
|
|
||||||
* Reports a scan failure to the user. This may or may not abort the
|
|
||||||
* current session. It is the equivalent of fpi_image_device_image_captured()
|
|
||||||
* in the case of a retryable error condition (e.g. short swipe).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
/* We might be waiting for a finger at this point, so just accept
|
|
||||||
* all but INACTIVE */
|
|
||||||
g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE);
|
|
||||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
|
||||||
action == FP_DEVICE_ACTION_VERIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_CAPTURE);
|
|
||||||
|
|
||||||
error = fpi_device_retry_new (retry);
|
|
||||||
|
|
||||||
if (action == FP_DEVICE_ACTION_ENROLL)
|
|
||||||
{
|
|
||||||
g_debug ("Reporting retry during enroll");
|
|
||||||
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
|
||||||
}
|
|
||||||
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)");
|
|
||||||
fp_image_device_deactivate (FP_DEVICE (self));
|
|
||||||
fpi_device_action_error (FP_DEVICE (self), error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_session_error:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @error: The #GError to report
|
|
||||||
*
|
|
||||||
* Report an error while interacting with the device. This effectively
|
|
||||||
* aborts the current ongoing action.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_session_error (FpImageDevice *self, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
|
|
||||||
g_return_if_fail (self);
|
|
||||||
|
|
||||||
if (!error)
|
|
||||||
{
|
|
||||||
g_warning ("Driver did not provide an error, generating a generic one");
|
|
||||||
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!priv->active)
|
|
||||||
{
|
|
||||||
FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
g_warning ("Driver reported session error, but device is inactive.");
|
|
||||||
|
|
||||||
if (action != FP_DEVICE_ACTION_NONE)
|
|
||||||
{
|
|
||||||
g_warning ("Translating to activation failure!");
|
|
||||||
fpi_image_device_activate_complete (self, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
|
|
||||||
{
|
|
||||||
g_warning ("Driver reported session error; translating to deactivation failure.");
|
|
||||||
fpi_image_device_deactivate_complete (self, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error->domain == FP_DEVICE_RETRY)
|
|
||||||
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
|
||||||
|
|
||||||
fp_image_device_deactivate (FP_DEVICE (self));
|
|
||||||
fpi_device_action_error (FP_DEVICE (self), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_activate_complete:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @error: A #GError or %NULL on success
|
|
||||||
*
|
|
||||||
* Reports completion of device activation.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
g_return_if_fail (priv->active == FALSE);
|
|
||||||
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
|
|
||||||
action == FP_DEVICE_ACTION_VERIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_IDENTIFY ||
|
|
||||||
action == FP_DEVICE_ACTION_CAPTURE);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
g_debug ("Image device activation failed");
|
|
||||||
fpi_device_action_error (FP_DEVICE (self), error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("Image device activation completed");
|
|
||||||
|
|
||||||
priv->active = TRUE;
|
|
||||||
|
|
||||||
/* We always want to capture at this point, move to AWAIT_FINGER
|
|
||||||
* state. */
|
|
||||||
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_deactivate_complete:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @error: A #GError or %NULL on success
|
|
||||||
*
|
|
||||||
* Reports completion of device deactivation.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
g_return_if_fail (priv->active == TRUE);
|
|
||||||
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE);
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
/* Special case, if we should be closing, but didn't due to a running
|
|
||||||
* deactivation, then do so now. */
|
|
||||||
if (action == FP_DEVICE_ACTION_CLOSE)
|
|
||||||
{
|
|
||||||
cls->img_close (self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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) fp_image_device_activate, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_open_complete:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @error: A #GError or %NULL on success
|
|
||||||
*
|
|
||||||
* Reports completion of open operation.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
g_return_if_fail (priv->active == FALSE);
|
|
||||||
g_return_if_fail (action == FP_DEVICE_ACTION_OPEN);
|
|
||||||
|
|
||||||
g_debug ("Image device open completed");
|
|
||||||
|
|
||||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
|
||||||
|
|
||||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_image_device_close_complete:
|
|
||||||
* @self: a #FpImageDevice imaging fingerprint device
|
|
||||||
* @error: A #GError or %NULL on success
|
|
||||||
*
|
|
||||||
* Reports completion of close operation.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDeviceAction action;
|
|
||||||
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
g_debug ("Image device close completed");
|
|
||||||
|
|
||||||
g_return_if_fail (priv->active == FALSE);
|
|
||||||
g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE);
|
|
||||||
|
|
||||||
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
|
|
||||||
|
|
||||||
fpi_device_close_complete (FP_DEVICE (self), error);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fp-device.h>
|
#include "fp-device.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,13 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "image"
|
||||||
|
|
||||||
#include "fpi-image.h"
|
#include "fpi-image.h"
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
|
|
||||||
#include <nbis.h>
|
#include <nbis.h>
|
||||||
|
|
||||||
#if HAVE_PIXMAN
|
|
||||||
#include <pixman.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fp-image
|
* SECTION: fp-image
|
||||||
* @title: FpImage
|
* @title: FpImage
|
||||||
|
@ -36,15 +34,6 @@
|
||||||
* this object allows accessing this data.
|
* this object allows accessing this data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION: fpi-image
|
|
||||||
* @title: Internal FpImage
|
|
||||||
* @short_description: Internal image handling routines
|
|
||||||
*
|
|
||||||
* Internal image handling routines. Also see the public <ulink
|
|
||||||
* url="libfprint-FpImage.html">FpImage routines</ulink>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -195,10 +184,8 @@ fp_image_detect_minutiae_cb (GObject *source_object,
|
||||||
GTask *task = G_TASK (res);
|
GTask *task = G_TASK (res);
|
||||||
FpImage *image;
|
FpImage *image;
|
||||||
DetectMinutiaeData *data = g_task_get_task_data (task);
|
DetectMinutiaeData *data = g_task_get_task_data (task);
|
||||||
GCancellable *cancellable;
|
|
||||||
|
|
||||||
cancellable = g_task_get_cancellable (task);
|
if (!g_task_had_error (task))
|
||||||
if (!cancellable || !g_cancellable_is_cancelled (cancellable))
|
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
image = FP_IMAGE (source_object);
|
image = FP_IMAGE (source_object);
|
||||||
|
@ -294,6 +281,7 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
gint map_w, map_h;
|
gint map_w, map_h;
|
||||||
gint bw, bh, bd;
|
gint bw, bh, bd;
|
||||||
gint r;
|
gint r;
|
||||||
|
g_autofree LFSPARMS *lfsparms = NULL;
|
||||||
|
|
||||||
/* Normalize the image first */
|
/* Normalize the image first */
|
||||||
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
||||||
|
@ -307,12 +295,15 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
|
|
||||||
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
|
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
|
||||||
|
|
||||||
|
lfsparms = g_memdup (&g_lfsparms_V2, sizeof (LFSPARMS));
|
||||||
|
lfsparms->remove_perimeter_pts = data->flags & FPI_IMAGE_PARTIAL ? TRUE : FALSE;
|
||||||
|
|
||||||
timer = g_timer_new ();
|
timer = g_timer_new ();
|
||||||
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
||||||
&low_contrast_map, &low_flow_map, &high_curve_map,
|
&low_contrast_map, &low_flow_map, &high_curve_map,
|
||||||
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
||||||
data->image, data->width, data->height, 8,
|
data->image, data->width, data->height, 8,
|
||||||
data->ppmm, &g_lfsparms_V2);
|
data->ppmm, lfsparms);
|
||||||
g_timer_stop (timer);
|
g_timer_stop (timer);
|
||||||
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||||
|
|
||||||
|
@ -327,6 +318,14 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->minutiae || data->minutiae->num == 0)
|
||||||
|
{
|
||||||
|
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"No minutiae found");
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_task_return_boolean (task, TRUE);
|
g_task_return_boolean (task, TRUE);
|
||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
}
|
}
|
||||||
|
@ -479,78 +478,6 @@ fp_image_detect_minutiae_finish (FpImage *self,
|
||||||
return g_task_propagate_boolean (G_TASK (result), error);
|
return g_task_propagate_boolean (G_TASK (result), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_std_sq_dev:
|
|
||||||
* @buf: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @size: size of @buffer
|
|
||||||
*
|
|
||||||
* Calculates the squared standard deviation of the individual
|
|
||||||
* pixels in the buffer, as per the following formula:
|
|
||||||
* |[<!-- -->
|
|
||||||
* mean = sum (buf[0..size]) / size
|
|
||||||
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
|
||||||
* ]|
|
|
||||||
* This function is usually used to determine whether image
|
|
||||||
* is empty.
|
|
||||||
*
|
|
||||||
* Returns: the squared standard deviation for @buffer
|
|
||||||
*/
|
|
||||||
gint
|
|
||||||
fpi_std_sq_dev (const guint8 *buf,
|
|
||||||
gint size)
|
|
||||||
{
|
|
||||||
guint64 res = 0, mean = 0;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
mean += buf[i];
|
|
||||||
|
|
||||||
mean /= size;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
int dev = (int) buf[i] - mean;
|
|
||||||
res += dev * dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_mean_sq_diff_norm:
|
|
||||||
* @buf1: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @buf2: buffer (usually bitmap, one byte per pixel)
|
|
||||||
* @size: buffer size of smallest buffer
|
|
||||||
*
|
|
||||||
* This function calculates the normalized mean square difference of
|
|
||||||
* two buffers, usually two lines, as per the following formula:
|
|
||||||
* |[<!-- -->
|
|
||||||
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
|
||||||
* ]|
|
|
||||||
*
|
|
||||||
* This functions is usually used to get numerical difference
|
|
||||||
* between two images.
|
|
||||||
*
|
|
||||||
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
|
||||||
*/
|
|
||||||
gint
|
|
||||||
fpi_mean_sq_diff_norm (const guint8 *buf1,
|
|
||||||
const guint8 *buf2,
|
|
||||||
gint size)
|
|
||||||
{
|
|
||||||
int res = 0, i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
int dev = (int) buf1[i] - (int) buf2[i];
|
|
||||||
res += dev * dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fp_minutia_get_coords:
|
* fp_minutia_get_coords:
|
||||||
* @min: A #FpMinutia
|
* @min: A #FpMinutia
|
||||||
|
@ -568,44 +495,3 @@ fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
|
||||||
if (y)
|
if (y)
|
||||||
*y = min->y;
|
*y = min->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_PIXMAN
|
|
||||||
FpImage *
|
|
||||||
fpi_image_resize (FpImage *orig_img,
|
|
||||||
guint w_factor,
|
|
||||||
guint h_factor)
|
|
||||||
{
|
|
||||||
int new_width = orig_img->width * w_factor;
|
|
||||||
int new_height = orig_img->height * h_factor;
|
|
||||||
pixman_image_t *orig, *resized;
|
|
||||||
pixman_transform_t transform;
|
|
||||||
FpImage *newimg;
|
|
||||||
|
|
||||||
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
|
|
||||||
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
|
|
||||||
|
|
||||||
pixman_transform_init_identity (&transform);
|
|
||||||
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
|
|
||||||
pixman_image_set_transform (orig, &transform);
|
|
||||||
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
|
||||||
pixman_image_composite32 (PIXMAN_OP_SRC,
|
|
||||||
orig, /* src */
|
|
||||||
NULL, /* mask */
|
|
||||||
resized, /* dst */
|
|
||||||
0, 0, /* src x y */
|
|
||||||
0, 0, /* mask x y */
|
|
||||||
0, 0, /* dst x y */
|
|
||||||
new_width, new_height /* width height */
|
|
||||||
);
|
|
||||||
|
|
||||||
newimg = fp_image_new (new_width, new_height);
|
|
||||||
newimg->flags = orig_img->flags;
|
|
||||||
|
|
||||||
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
|
|
||||||
|
|
||||||
pixman_image_unref (orig);
|
|
||||||
pixman_image_unref (resized);
|
|
||||||
|
|
||||||
return newimg;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Internal/private definitions for libfprint
|
* FPrint Print handling
|
||||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,9 +18,29 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#include "fpi-print.h"
|
||||||
|
|
||||||
#include "fpi-log.h"
|
|
||||||
#include "fpi-image.h"
|
#include "fpi-image.h"
|
||||||
#include "fpi-image-device.h"
|
|
||||||
#include "fpi-minutiae.h"
|
#include <nbis.h>
|
||||||
|
|
||||||
|
struct _FpPrint
|
||||||
|
{
|
||||||
|
GInitiallyUnowned parent_instance;
|
||||||
|
|
||||||
|
FpiPrintType type;
|
||||||
|
|
||||||
|
gchar *driver;
|
||||||
|
gchar *device_id;
|
||||||
|
gboolean device_stored;
|
||||||
|
|
||||||
|
FpImage *image;
|
||||||
|
|
||||||
|
/* Metadata */
|
||||||
|
FpFinger finger;
|
||||||
|
gchar *username;
|
||||||
|
gchar *description;
|
||||||
|
GDate *enroll_date;
|
||||||
|
|
||||||
|
GVariant *data;
|
||||||
|
GPtrArray *prints;
|
||||||
|
};
|
|
@ -18,12 +18,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fpi-print.h"
|
#define FP_COMPONENT "print"
|
||||||
#include "fpi-image.h"
|
|
||||||
#include "fpi-log.h"
|
|
||||||
#include "fpi-device.h"
|
|
||||||
|
|
||||||
#include <nbis.h>
|
#include "fp-print-private.h"
|
||||||
|
#include "fpi-compat.h"
|
||||||
|
#include "fpi-log.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fp-print
|
* SECTION: fp-print
|
||||||
|
@ -42,28 +41,6 @@
|
||||||
* #FpPrint routines.
|
* #FpPrint routines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct _FpPrint
|
|
||||||
{
|
|
||||||
GInitiallyUnowned parent_instance;
|
|
||||||
|
|
||||||
FpPrintType type;
|
|
||||||
|
|
||||||
gchar *driver;
|
|
||||||
gchar *device_id;
|
|
||||||
gboolean device_stored;
|
|
||||||
|
|
||||||
FpImage *image;
|
|
||||||
|
|
||||||
/* Metadata */
|
|
||||||
FpFinger finger;
|
|
||||||
gchar *username;
|
|
||||||
gchar *description;
|
|
||||||
GDate *enroll_date;
|
|
||||||
|
|
||||||
GVariant *data;
|
|
||||||
GPtrArray *prints;
|
|
||||||
};
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED)
|
G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -74,7 +51,7 @@ enum {
|
||||||
PROP_IMAGE,
|
PROP_IMAGE,
|
||||||
|
|
||||||
/* The following is metadata that is stored by default for each print.
|
/* The following is metadata that is stored by default for each print.
|
||||||
* Drivers may make use of these during enrollment (e.g. to additionaly store
|
* Drivers may make use of these during enrollment (e.g. to additionally store
|
||||||
* the metadata on the device). */
|
* the metadata on the device). */
|
||||||
PROP_FINGER,
|
PROP_FINGER,
|
||||||
PROP_USERNAME,
|
PROP_USERNAME,
|
||||||
|
@ -292,16 +269,30 @@ fp_print_class_init (FpPrintClass *klass)
|
||||||
G_TYPE_DATE,
|
G_TYPE_DATE,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpPrint::fpi-type: (skip)
|
||||||
|
*
|
||||||
|
* This property is only for internal purposes.
|
||||||
|
*
|
||||||
|
* Stability: private
|
||||||
|
*/
|
||||||
properties[PROP_FPI_TYPE] =
|
properties[PROP_FPI_TYPE] =
|
||||||
g_param_spec_enum ("fp-type",
|
g_param_spec_enum ("fpi-type",
|
||||||
"Type",
|
"Type",
|
||||||
"Private: The type of the print data",
|
"Private: The type of the print data",
|
||||||
FP_TYPE_PRINT_TYPE,
|
FPI_TYPE_PRINT_TYPE,
|
||||||
FP_PRINT_RAW,
|
FPI_PRINT_UNDEFINED,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpPrint::fpi-data: (skip)
|
||||||
|
*
|
||||||
|
* This property is only for internal purposes.
|
||||||
|
*
|
||||||
|
* Stability: private
|
||||||
|
*/
|
||||||
properties[PROP_FPI_DATA] =
|
properties[PROP_FPI_DATA] =
|
||||||
g_param_spec_variant ("fp-data",
|
g_param_spec_variant ("fpi-data",
|
||||||
"Raw Data",
|
"Raw Data",
|
||||||
"The raw data for internal use only",
|
"The raw data for internal use only",
|
||||||
G_VARIANT_TYPE_ANY,
|
G_VARIANT_TYPE_ANY,
|
||||||
|
@ -540,223 +531,6 @@ fp_print_set_enroll_date (FpPrint *print,
|
||||||
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]);
|
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_print_add_print:
|
|
||||||
* @print: A #FpPrint
|
|
||||||
* @add: Print to append to @print
|
|
||||||
*
|
|
||||||
* Appends the single #FP_PRINT_NBIS print from @add to the collection of
|
|
||||||
* prints in @print. Both print objects need to be of type #FP_PRINT_NBIS
|
|
||||||
* for this to work.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_print_add_print (FpPrint *print, FpPrint *add)
|
|
||||||
{
|
|
||||||
g_return_if_fail (print->type == FP_PRINT_NBIS);
|
|
||||||
g_return_if_fail (add->type == FP_PRINT_NBIS);
|
|
||||||
|
|
||||||
g_assert (add->prints->len == 1);
|
|
||||||
g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_print_set_type:
|
|
||||||
* @print: A #FpPrint
|
|
||||||
* @type: The newly type of the print data
|
|
||||||
*
|
|
||||||
* This function can only be called exactly once. Drivers should
|
|
||||||
* call it after creating a new print, or to initialize the template
|
|
||||||
* print passed during enrollment.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_print_set_type (FpPrint *print,
|
|
||||||
FpPrintType type)
|
|
||||||
{
|
|
||||||
g_return_if_fail (FP_IS_PRINT (print));
|
|
||||||
/* We only allow setting this once! */
|
|
||||||
g_return_if_fail (print->type == FP_PRINT_UNDEFINED);
|
|
||||||
|
|
||||||
print->type = type;
|
|
||||||
if (print->type == FP_PRINT_NBIS)
|
|
||||||
{
|
|
||||||
g_assert_null (print->prints);
|
|
||||||
print->prints = g_ptr_array_new_with_free_func (g_free);
|
|
||||||
}
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_print_set_device_stored:
|
|
||||||
* @print: A #FpPrint
|
|
||||||
* @device_stored: Whether the print is stored on the device or not
|
|
||||||
*
|
|
||||||
* Drivers must set this to %TRUE for any print that is really a handle
|
|
||||||
* for data that is stored on the device itself.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_print_set_device_stored (FpPrint *print,
|
|
||||||
gboolean device_stored)
|
|
||||||
{
|
|
||||||
g_return_if_fail (FP_IS_PRINT (print));
|
|
||||||
|
|
||||||
print->device_stored = device_stored;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DEVICE_STORED]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: This is the old version, but wouldn't it be smarter to instead
|
|
||||||
* use the highest quality mintutiae? Possibly just using bz_prune from
|
|
||||||
* upstream? */
|
|
||||||
static void
|
|
||||||
minutiae_to_xyt (struct fp_minutiae *minutiae,
|
|
||||||
int bwidth,
|
|
||||||
int bheight,
|
|
||||||
struct xyt_struct *xyt)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct fp_minutia *minutia;
|
|
||||||
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
|
||||||
|
|
||||||
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
|
|
||||||
int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
|
|
||||||
|
|
||||||
for (i = 0; i < nmin; i++)
|
|
||||||
{
|
|
||||||
minutia = minutiae->list[i];
|
|
||||||
|
|
||||||
lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
|
|
||||||
minutia, bwidth, bheight);
|
|
||||||
c[i].col[3] = sround (minutia->reliability * 100.0);
|
|
||||||
|
|
||||||
if (c[i].col[2] > 180)
|
|
||||||
c[i].col[2] -= 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
|
|
||||||
sort_x_y);
|
|
||||||
|
|
||||||
for (i = 0; i < nmin; i++)
|
|
||||||
{
|
|
||||||
xyt->xcol[i] = c[i].col[0];
|
|
||||||
xyt->ycol[i] = c[i].col[1];
|
|
||||||
xyt->thetacol[i] = c[i].col[2];
|
|
||||||
}
|
|
||||||
xyt->nrows = nmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_print_add_from_image:
|
|
||||||
* @print: A #FpPrint
|
|
||||||
* @image: A #FpImage
|
|
||||||
* @error: Return location for error
|
|
||||||
*
|
|
||||||
* Extracts the minutiae from the given image and adds it to @print of
|
|
||||||
* type #FP_PRINT_NBIS.
|
|
||||||
*
|
|
||||||
* The @image will be kept so that API users can get retrieve it e.g.
|
|
||||||
* for debugging purposes.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE on success
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
fpi_print_add_from_image (FpPrint *print,
|
|
||||||
FpImage *image,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
GPtrArray *minutiae;
|
|
||||||
struct fp_minutiae _minutiae;
|
|
||||||
struct xyt_struct *xyt;
|
|
||||||
|
|
||||||
if (print->type != FP_PRINT_NBIS || !image)
|
|
||||||
{
|
|
||||||
g_set_error (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_DATA,
|
|
||||||
"Cannot add print data from image!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
minutiae = fp_image_get_minutiae (image);
|
|
||||||
if (!minutiae || minutiae->len == 0)
|
|
||||||
{
|
|
||||||
g_set_error (error,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_DATA,
|
|
||||||
"No minutiae found in image or not yet detected!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
_minutiae.num = minutiae->len;
|
|
||||||
_minutiae.list = (struct fp_minutia **) minutiae->pdata;
|
|
||||||
_minutiae.alloc = minutiae->len;
|
|
||||||
|
|
||||||
xyt = g_new0 (struct xyt_struct, 1);
|
|
||||||
minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
|
|
||||||
g_ptr_array_add (print->prints, xyt);
|
|
||||||
|
|
||||||
g_clear_object (&print->image);
|
|
||||||
print->image = g_object_ref (image);
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_IMAGE]);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_print_bz3_match:
|
|
||||||
* @template: A #FpPrint containing one or more prints
|
|
||||||
* @print: A newly scanned #FpPrint to test
|
|
||||||
* @bz3_threshold: The BZ3 match threshold
|
|
||||||
* @error: Return location for error
|
|
||||||
*
|
|
||||||
* Match the newly scanned @print (containing exactly one print) against the
|
|
||||||
* prints contained in @template which will have been stored during enrollment.
|
|
||||||
*
|
|
||||||
* Both @template and @print need to be of type #FP_PRINT_NBIS for this to
|
|
||||||
* work.
|
|
||||||
*
|
|
||||||
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
|
|
||||||
*/
|
|
||||||
FpiMatchResult
|
|
||||||
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
|
|
||||||
{
|
|
||||||
struct xyt_struct *pstruct;
|
|
||||||
gint probe_len;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
/* XXX: Use a different error type? */
|
|
||||||
if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS)
|
|
||||||
{
|
|
||||||
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
|
||||||
"It is only possible to match NBIS type print data");
|
|
||||||
return FPI_MATCH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (print->prints->len != 1)
|
|
||||||
{
|
|
||||||
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
|
||||||
"New print contains more than one print!");
|
|
||||||
return FPI_MATCH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
pstruct = g_ptr_array_index (print->prints, 0);
|
|
||||||
probe_len = bozorth_probe_init (pstruct);
|
|
||||||
|
|
||||||
for (i = 0; i < template->prints->len; i++)
|
|
||||||
{
|
|
||||||
struct xyt_struct *gstruct;
|
|
||||||
gint score;
|
|
||||||
gstruct = g_ptr_array_index (template->prints, i);
|
|
||||||
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
|
|
||||||
fp_dbg ("score %d", score);
|
|
||||||
|
|
||||||
if (score >= bz3_threshold)
|
|
||||||
return FPI_MATCH_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FPI_MATCH_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fp_print_compatible:
|
* fp_print_compatible:
|
||||||
* @self: A #FpPrint
|
* @self: A #FpPrint
|
||||||
|
@ -796,8 +570,8 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (FP_IS_PRINT (self), FALSE);
|
g_return_val_if_fail (FP_IS_PRINT (self), FALSE);
|
||||||
g_return_val_if_fail (FP_IS_PRINT (other), FALSE);
|
g_return_val_if_fail (FP_IS_PRINT (other), FALSE);
|
||||||
g_return_val_if_fail (self->type != FP_PRINT_UNDEFINED, FALSE);
|
g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE);
|
||||||
g_return_val_if_fail (other->type != FP_PRINT_UNDEFINED, FALSE);
|
g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE);
|
||||||
|
|
||||||
if (self->type != other->type)
|
if (self->type != other->type)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -808,13 +582,13 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||||
if (g_strcmp0 (self->device_id, other->device_id))
|
if (g_strcmp0 (self->device_id, other->device_id))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (self->type == FP_PRINT_RAW)
|
if (self->type == FPI_PRINT_RAW)
|
||||||
{
|
{
|
||||||
return g_variant_equal (self->data, other->data);
|
return g_variant_equal (self->data, other->data);
|
||||||
}
|
}
|
||||||
else if (self->type == FP_PRINT_NBIS)
|
else if (self->type == FPI_PRINT_NBIS)
|
||||||
{
|
{
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
if (self->prints->len != other->prints->len)
|
if (self->prints->len != other->prints->len)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -836,7 +610,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FP_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
|
#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
|
||||||
|
|
||||||
G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4);
|
G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4);
|
||||||
|
|
||||||
|
@ -859,7 +633,7 @@ fp_print_serialize (FpPrint *print,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(GVariant) result = NULL;
|
g_autoptr(GVariant) result = NULL;
|
||||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FP_PRINT_VARIANT_TYPE);
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FPI_PRINT_VARIANT_TYPE);
|
||||||
gsize len;
|
gsize len;
|
||||||
|
|
||||||
g_assert (data);
|
g_assert (data);
|
||||||
|
@ -884,45 +658,34 @@ fp_print_serialize (FpPrint *print,
|
||||||
g_variant_builder_close (&builder);
|
g_variant_builder_close (&builder);
|
||||||
|
|
||||||
/* Insert NBIS print data for type NBIS, otherwise the GVariant directly */
|
/* Insert NBIS print data for type NBIS, otherwise the GVariant directly */
|
||||||
if (print->type == FP_PRINT_NBIS)
|
if (print->type == FPI_PRINT_NBIS)
|
||||||
{
|
{
|
||||||
GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))"));
|
GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))"));
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_variant_builder_open (&nested, G_VARIANT_TYPE ("a(aiaiai)"));
|
g_variant_builder_open (&nested, G_VARIANT_TYPE ("a(aiaiai)"));
|
||||||
for (i = 0; i < print->prints->len; i++)
|
for (i = 0; i < print->prints->len; i++)
|
||||||
{
|
{
|
||||||
struct xyt_struct *xyt = g_ptr_array_index (print->prints, 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)"));
|
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_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
col,
|
xyt->xcol,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (col[0])));
|
sizeof (xyt->xcol[0])));
|
||||||
|
|
||||||
for (j = 0; j < xyt->nrows; j++)
|
|
||||||
col[j] = GINT32_TO_LE (xyt->ycol[j]);
|
|
||||||
g_variant_builder_add_value (&nested,
|
g_variant_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
col,
|
xyt->ycol,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (col[0])));
|
sizeof (xyt->ycol[0])));
|
||||||
|
|
||||||
for (j = 0; j < xyt->nrows; j++)
|
|
||||||
col[j] = GINT32_TO_LE (xyt->thetacol[j]);
|
|
||||||
g_variant_builder_add_value (&nested,
|
g_variant_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
col,
|
xyt->thetacol,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (col[0])));
|
sizeof (xyt->thetacol[0])));
|
||||||
g_variant_builder_close (&nested);
|
g_variant_builder_close (&nested);
|
||||||
g_free (col);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_builder_close (&nested);
|
g_variant_builder_close (&nested);
|
||||||
|
@ -979,14 +742,14 @@ fp_print_deserialize (const guchar *data,
|
||||||
g_autoptr(GVariant) raw_value = NULL;
|
g_autoptr(GVariant) raw_value = NULL;
|
||||||
g_autoptr(GVariant) value = NULL;
|
g_autoptr(GVariant) value = NULL;
|
||||||
g_autoptr(GVariant) print_data = NULL;
|
g_autoptr(GVariant) print_data = NULL;
|
||||||
|
g_autoptr(GDate) date = NULL;
|
||||||
guchar *aligned_data = NULL;
|
guchar *aligned_data = NULL;
|
||||||
GDate *date = NULL;
|
|
||||||
guint8 finger_int8;
|
guint8 finger_int8;
|
||||||
FpFinger finger;
|
FpFinger finger;
|
||||||
g_autofree gchar *username = NULL;
|
g_autofree gchar *username = NULL;
|
||||||
g_autofree gchar *description = NULL;
|
g_autofree gchar *description = NULL;
|
||||||
gint julian_date;
|
gint julian_date;
|
||||||
FpPrintType type;
|
FpiPrintType type;
|
||||||
const gchar *driver;
|
const gchar *driver;
|
||||||
const gchar *device_id;
|
const gchar *device_id;
|
||||||
gboolean device_stored;
|
gboolean device_stored;
|
||||||
|
@ -1007,7 +770,7 @@ fp_print_deserialize (const guchar *data,
|
||||||
* longer. */
|
* longer. */
|
||||||
aligned_data = g_malloc (length - 3);
|
aligned_data = g_malloc (length - 3);
|
||||||
memcpy (aligned_data, data + 3, length - 3);
|
memcpy (aligned_data, data + 3, length - 3);
|
||||||
raw_value = g_variant_new_from_data (FP_PRINT_VARIANT_TYPE,
|
raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE,
|
||||||
aligned_data, length - 3,
|
aligned_data, length - 3,
|
||||||
FALSE, g_free, aligned_data);
|
FALSE, g_free, aligned_data);
|
||||||
|
|
||||||
|
@ -1035,20 +798,21 @@ fp_print_deserialize (const guchar *data,
|
||||||
finger = finger_int8;
|
finger = finger_int8;
|
||||||
|
|
||||||
/* Assume data is valid at this point if the values are somewhat sane. */
|
/* Assume data is valid at this point if the values are somewhat sane. */
|
||||||
if (type == FP_PRINT_NBIS)
|
if (type == FPI_PRINT_NBIS)
|
||||||
{
|
{
|
||||||
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
|
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
result = g_object_new (FP_TYPE_PRINT,
|
result = g_object_new (FP_TYPE_PRINT,
|
||||||
"driver", driver,
|
"driver", driver,
|
||||||
"device-id", device_id,
|
"device-id", device_id,
|
||||||
"device-stored", device_stored,
|
"device-stored", device_stored,
|
||||||
NULL);
|
NULL);
|
||||||
fpi_print_set_type (result, FP_PRINT_NBIS);
|
g_object_ref_sink (result);
|
||||||
|
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
||||||
for (i = 0; i < g_variant_n_children (prints); i++)
|
for (i = 0; i < g_variant_n_children (prints); i++)
|
||||||
{
|
{
|
||||||
g_autofree struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1);
|
g_autofree struct xyt_struct *xyt = NULL;
|
||||||
const gint32 *xcol, *ycol, *thetacol;
|
const gint32 *xcol, *ycol, *thetacol;
|
||||||
gsize xlen, ylen, thetalen;
|
gsize xlen, ylen, thetalen;
|
||||||
g_autoptr(GVariant) xyt_data = NULL;
|
g_autoptr(GVariant) xyt_data = NULL;
|
||||||
|
@ -1074,6 +838,7 @@ fp_print_deserialize (const guchar *data,
|
||||||
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
||||||
goto invalid_format;
|
goto invalid_format;
|
||||||
|
|
||||||
|
xyt = g_new0 (struct xyt_struct, 1);
|
||||||
xyt->nrows = xlen;
|
xyt->nrows = xlen;
|
||||||
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
||||||
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
||||||
|
@ -1082,17 +847,18 @@ fp_print_deserialize (const guchar *data,
|
||||||
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == FP_PRINT_RAW)
|
else if (type == FPI_PRINT_RAW)
|
||||||
{
|
{
|
||||||
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
||||||
|
|
||||||
result = g_object_new (FP_TYPE_PRINT,
|
result = g_object_new (FP_TYPE_PRINT,
|
||||||
"fp-type", type,
|
"fpi-type", type,
|
||||||
"driver", driver,
|
"driver", driver,
|
||||||
"device-id", device_id,
|
"device-id", device_id,
|
||||||
"device-stored", device_stored,
|
"device-stored", device_stored,
|
||||||
"fp-data", fp_data,
|
"fpi-data", fp_data,
|
||||||
NULL);
|
NULL);
|
||||||
|
g_object_ref_sink (result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1108,13 +874,10 @@ fp_print_deserialize (const guchar *data,
|
||||||
"enroll_date", date,
|
"enroll_date", date,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
g_date_free (date);
|
|
||||||
|
|
||||||
return g_steal_pointer (&result);
|
return g_steal_pointer (&result);
|
||||||
|
|
||||||
invalid_format:
|
invalid_format:
|
||||||
*error = g_error_new_literal (G_IO_ERROR,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
G_IO_ERROR_INVALID_DATA,
|
|
||||||
"Data could not be parsed");
|
"Data could not be parsed");
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ G_BEGIN_DECLS
|
||||||
#define FP_TYPE_PRINT (fp_print_get_type ())
|
#define FP_TYPE_PRINT (fp_print_get_type ())
|
||||||
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
|
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
|
||||||
|
|
||||||
|
#define FP_FINGER_IS_VALID(finger) \
|
||||||
|
((finger) >= FP_FINGER_FIRST && (finger) <= FP_FINGER_LAST)
|
||||||
|
|
||||||
#include "fp-device.h"
|
#include "fp-device.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +46,8 @@ G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
|
||||||
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
|
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
|
||||||
* @FP_FINGER_RIGHT_RING: Right ring finger
|
* @FP_FINGER_RIGHT_RING: Right ring finger
|
||||||
* @FP_FINGER_RIGHT_LITTLE: Right little finger
|
* @FP_FINGER_RIGHT_LITTLE: Right little finger
|
||||||
|
* @FP_FINGER_FIRST: The first finger in the fp-print order
|
||||||
|
* @FP_FINGER_LAST: The last finger in the fp-print order
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FP_FINGER_UNKNOWN = 0,
|
FP_FINGER_UNKNOWN = 0,
|
||||||
|
@ -56,14 +61,24 @@ typedef enum {
|
||||||
FP_FINGER_RIGHT_MIDDLE,
|
FP_FINGER_RIGHT_MIDDLE,
|
||||||
FP_FINGER_RIGHT_RING,
|
FP_FINGER_RIGHT_RING,
|
||||||
FP_FINGER_RIGHT_LITTLE,
|
FP_FINGER_RIGHT_LITTLE,
|
||||||
|
|
||||||
|
FP_FINGER_FIRST = FP_FINGER_LEFT_THUMB,
|
||||||
|
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
|
||||||
} FpFinger;
|
} 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,
|
FpPrint *fp_print_new (FpDevice *device);
|
||||||
gsize length);
|
|
||||||
gboolean fp_print_to_data (guchar **data,
|
|
||||||
gsize length);
|
|
||||||
|
|
||||||
const gchar *fp_print_get_driver (FpPrint *print);
|
const gchar *fp_print_get_driver (FpPrint *print);
|
||||||
const gchar *fp_print_get_device_id (FpPrint *print);
|
const gchar *fp_print_get_device_id (FpPrint *print);
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "assembling"
|
#define FP_COMPONENT "assembling"
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fpi-log.h"
|
||||||
|
#include "fpi-image.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -51,6 +52,9 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
width = ctx->frame_width - (dx > 0 ? dx : -dx);
|
width = ctx->frame_width - (dx > 0 ? dx : -dx);
|
||||||
height = ctx->frame_height - dy;
|
height = ctx->frame_height - dy;
|
||||||
|
|
||||||
|
if (height == 0 || width == 0)
|
||||||
|
return INT_MAX;
|
||||||
|
|
||||||
y1 = 0;
|
y1 = 0;
|
||||||
y2 = dy;
|
y2 = dy;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -85,9 +89,6 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
err *= (ctx->frame_height * ctx->frame_width);
|
err *= (ctx->frame_height * ctx->frame_width);
|
||||||
err /= (height * width);
|
err /= (height * width);
|
||||||
|
|
||||||
if (err == 0)
|
|
||||||
return INT_MAX;
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +99,8 @@ static void
|
||||||
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
|
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *first_frame,
|
struct fpi_frame *first_frame,
|
||||||
struct fpi_frame *second_frame,
|
struct fpi_frame *second_frame,
|
||||||
|
int *dx_out,
|
||||||
|
int *dy_out,
|
||||||
unsigned int *min_error)
|
unsigned int *min_error)
|
||||||
{
|
{
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
|
@ -119,8 +122,8 @@ find_overlap (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
if (err < *min_error)
|
if (err < *min_error)
|
||||||
{
|
{
|
||||||
*min_error = err;
|
*min_error = err;
|
||||||
second_frame->delta_x = -dx;
|
*dx_out = -dx;
|
||||||
second_frame->delta_y = dy;
|
*dy_out = dy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +135,7 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
{
|
{
|
||||||
GSList *l;
|
GSList *l;
|
||||||
GTimer *timer;
|
GTimer *timer;
|
||||||
guint num_frames = 0;
|
guint num_frames = 1;
|
||||||
struct fpi_frame *prev_stripe;
|
struct fpi_frame *prev_stripe;
|
||||||
unsigned int min_error;
|
unsigned int min_error;
|
||||||
/* Max error is width * height * 255, for AES2501 which has the largest
|
/* Max error is width * height * 255, for AES2501 which has the largest
|
||||||
|
@ -142,20 +145,27 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
unsigned long long total_error = 0;
|
unsigned long long total_error = 0;
|
||||||
|
|
||||||
timer = g_timer_new ();
|
timer = g_timer_new ();
|
||||||
|
|
||||||
|
/* Skip the first frame */
|
||||||
prev_stripe = stripes->data;
|
prev_stripe = stripes->data;
|
||||||
for (l = stripes; l != NULL; l = l->next, num_frames++)
|
|
||||||
|
for (l = stripes->next; l != NULL; l = l->next, num_frames++)
|
||||||
{
|
{
|
||||||
struct fpi_frame *cur_stripe = l->data;
|
struct fpi_frame *cur_stripe = l->data;
|
||||||
|
|
||||||
if (reverse)
|
if (reverse)
|
||||||
{
|
{
|
||||||
find_overlap (ctx, prev_stripe, cur_stripe, &min_error);
|
find_overlap (ctx, prev_stripe, cur_stripe,
|
||||||
|
&cur_stripe->delta_x, &cur_stripe->delta_y,
|
||||||
|
&min_error);
|
||||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
cur_stripe->delta_y = -cur_stripe->delta_y;
|
||||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
cur_stripe->delta_x = -cur_stripe->delta_x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
find_overlap (ctx, cur_stripe, prev_stripe, &min_error);
|
find_overlap (ctx, cur_stripe, prev_stripe,
|
||||||
|
&cur_stripe->delta_x, &cur_stripe->delta_y,
|
||||||
|
&min_error);
|
||||||
}
|
}
|
||||||
total_error += min_error;
|
total_error += min_error;
|
||||||
|
|
||||||
|
@ -200,69 +210,36 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *stripe,
|
struct fpi_frame *stripe,
|
||||||
int x, int y)
|
int x, int y)
|
||||||
{
|
{
|
||||||
unsigned int ix, iy;
|
unsigned int ix1, iy1;
|
||||||
unsigned int fx, fy;
|
unsigned int fx1, fy1;
|
||||||
unsigned int width, height;
|
unsigned int fx, fy, ix, iy;
|
||||||
|
|
||||||
/* Find intersection */
|
/* Select starting point inside image and frame */
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
width = ctx->frame_width + x;
|
ix1 = 0;
|
||||||
ix = 0;
|
fx1 = -x;
|
||||||
fx = -x;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ix = x;
|
ix1 = x;
|
||||||
fx = 0;
|
fx1 = 0;
|
||||||
width = ctx->frame_width;
|
|
||||||
}
|
}
|
||||||
if ((ix + width) > img->width)
|
|
||||||
width = img->width - ix;
|
|
||||||
|
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
{
|
{
|
||||||
iy = 0;
|
iy1 = 0;
|
||||||
fy = -y;
|
fy1 = -y;
|
||||||
height = ctx->frame_height + y;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iy = y;
|
iy1 = y;
|
||||||
fy = 0;
|
fy1 = 0;
|
||||||
height = ctx->frame_height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fx > ctx->frame_width)
|
for (fy = fy1, iy = iy1; fy < ctx->frame_height && iy < img->height; fy++, iy++)
|
||||||
return;
|
for (fx = fx1, ix = ix1; fx < ctx->frame_width && ix < img->width; fx++, ix++)
|
||||||
|
|
||||||
if (fy > ctx->frame_height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ix > img->width)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (iy > img->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((iy + height) > img->height)
|
|
||||||
height = img->height - iy;
|
|
||||||
|
|
||||||
for (; fy < height; fy++, iy++)
|
|
||||||
{
|
|
||||||
if (x < 0)
|
|
||||||
{
|
|
||||||
ix = 0;
|
|
||||||
fx = -x;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ix = x;
|
|
||||||
fx = 0;
|
|
||||||
}
|
|
||||||
for (; fx < width; fx++, ix++)
|
|
||||||
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
|
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -288,7 +265,6 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
|
||||||
//FIXME g_return_if_fail
|
//FIXME g_return_if_fail
|
||||||
g_return_val_if_fail (stripes != NULL, NULL);
|
g_return_val_if_fail (stripes != NULL, NULL);
|
||||||
BUG_ON (ctx->image_width < ctx->frame_width);
|
|
||||||
|
|
||||||
/* No offset for 1st image */
|
/* No offset for 1st image */
|
||||||
fpi_frame = stripes->data;
|
fpi_frame = stripes->data;
|
||||||
|
@ -321,25 +297,16 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
|
||||||
/* Assemble stripes */
|
/* Assemble stripes */
|
||||||
y = reverse ? (height - ctx->frame_height) : 0;
|
y = reverse ? (height - ctx->frame_height) : 0;
|
||||||
x = (ctx->image_width - ctx->frame_width) / 2;
|
x = ((int) ctx->image_width - (int) ctx->frame_width) / 2;
|
||||||
|
|
||||||
for (l = stripes; l != NULL; l = l->next)
|
for (l = stripes; l != NULL; l = l->next)
|
||||||
{
|
{
|
||||||
fpi_frame = l->data;
|
fpi_frame = l->data;
|
||||||
|
|
||||||
if(reverse)
|
|
||||||
{
|
|
||||||
y += fpi_frame->delta_y;
|
y += fpi_frame->delta_y;
|
||||||
x += fpi_frame->delta_x;
|
x += fpi_frame->delta_x;
|
||||||
}
|
|
||||||
|
|
||||||
aes_blit_stripe (ctx, img, fpi_frame, x, y);
|
aes_blit_stripe (ctx, img, fpi_frame, x, y);
|
||||||
|
|
||||||
if(!reverse)
|
|
||||||
{
|
|
||||||
y += fpi_frame->delta_y;
|
|
||||||
x += fpi_frame->delta_x;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FPI_ASSEMBLING_H__
|
#pragma once
|
||||||
#define __FPI_ASSEMBLING_H__
|
|
||||||
|
|
||||||
#include <fprint.h>
|
#include "fp-image.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_frame:
|
* fpi_frame:
|
||||||
|
@ -116,5 +115,3 @@ struct fpi_line_asmbl_ctx
|
||||||
FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *lines,
|
GSList *lines,
|
||||||
size_t num_lines);
|
size_t num_lines);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue