Compare commits
1575 Commits
v_0_5_1
...
0726462d3b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0726462d3b | ||
|
|
05f7631023 | ||
|
|
2050902767 | ||
|
|
7c97dcd985 | ||
|
|
596b5f8032 | ||
|
|
7f5304d6ee | ||
|
|
bde868f05e | ||
|
|
a7448fbb4a | ||
|
|
f84ab3d104 | ||
|
|
da42268911 | ||
|
|
d83a785260 | ||
|
|
2b100a912b | ||
|
|
dc8b05f0a3 | ||
|
|
c37da8568f | ||
|
|
e401fc10e8 | ||
|
|
db48d1a4e4 | ||
|
|
d1504a30b7 | ||
|
|
7208b29756 | ||
|
|
e9dbfbec39 | ||
|
|
c6ca915067 | ||
|
|
385bc5e384 | ||
|
|
ee73d67765 | ||
|
|
4dd51f38c7 | ||
|
|
5b300edbe5 | ||
|
|
817281f6fd | ||
|
|
aa18595ec7 | ||
|
|
fa5828f8c0 | ||
|
|
fc3effd73b | ||
|
|
63b5908f38 | ||
|
|
7b97bed91f | ||
|
|
41949db6ce | ||
|
|
d8e0791554 | ||
|
|
c7059dc61c | ||
|
|
0c315b4f0a | ||
|
|
b04553cac9 | ||
|
|
c1dcaa805d | ||
|
|
7b2895271d | ||
|
|
3e653fe85b | ||
|
|
830a9977c0 | ||
|
|
6b914a2070 | ||
|
|
22e6670aa0 | ||
|
|
6723b74f86 | ||
|
|
7d9638bc43 | ||
|
|
559c18785b | ||
|
|
9e8dda5f17 | ||
|
|
f906afb757 | ||
|
|
1c4ed2e225 | ||
|
|
cdc22b4553 | ||
|
|
57c535d0cb | ||
|
|
a94a55b8df | ||
|
|
133eaab061 | ||
|
|
7a60912b61 | ||
|
|
6702c32b2b | ||
|
|
b8ed4b5d63 | ||
|
|
8433563602 | ||
|
|
026c09d0b4 | ||
|
|
3abdda4391 | ||
|
|
981f8e0a42 | ||
|
|
f18e11b435 | ||
|
|
42d10118a3 | ||
|
|
51d827fc74 | ||
|
|
1859a1e5d1 | ||
|
|
7292dd642c | ||
|
|
8e22b2e22e | ||
|
|
28b9ab7e37 | ||
|
|
9141014456 | ||
|
|
6f3ab36b2e | ||
|
|
d3035d5703 | ||
|
|
042365dbec | ||
|
|
0c7211329e | ||
|
|
e1b6d8a461 | ||
|
|
09ec6e66e3 | ||
|
|
8ce356fccc | ||
|
|
98f5ad1f80 | ||
|
|
29f919b4eb | ||
|
|
e57bab2f1e | ||
|
|
a88582761f | ||
|
|
75adfd37d1 | ||
|
|
990bd40cbf | ||
|
|
c7e95bb41f | ||
|
|
4611cc4a1b | ||
|
|
78c78432b9 | ||
|
|
10e1cd76aa | ||
|
|
c84d3774cf | ||
|
|
04a167b09b | ||
|
|
538a18cf17 | ||
|
|
2e766904f0 | ||
|
|
9f55ef690d | ||
|
|
b6061c0af8 | ||
|
|
3f70bde21c | ||
|
|
dd6f020378 | ||
| 2a4c05662a | |||
|
|
eaec2339cc | ||
|
|
83035be830 | ||
|
|
4709efc678 | ||
|
|
37ded921fd | ||
|
|
b7f3544e98 | ||
|
|
093f2fc0a6 | ||
|
|
c5def9a528 | ||
|
|
e71f3de786 | ||
|
|
420fd7416d | ||
|
|
f505158c04 | ||
|
|
fb13722629 | ||
|
|
666cd0c08d | ||
|
|
e055781006 | ||
|
|
48c8c539c7 | ||
|
|
40c7599fb1 | ||
|
|
28c26c7d7e | ||
|
|
dd5a71695f | ||
|
|
977d324970 | ||
|
|
4992110829 | ||
|
|
53f2539b6a | ||
|
|
18e2906d62 | ||
|
|
19806546a2 | ||
|
|
75559415fe | ||
|
|
7dbb21e77a | ||
|
|
4b72f27de6 | ||
|
|
5ada931ede | ||
|
|
bebe8565cd | ||
|
|
5501dc7b47 | ||
|
|
3e5ab6fdad | ||
|
|
5462db9901 | ||
|
|
59dc585ccd | ||
|
|
6768bd0ff4 | ||
|
|
ed1815c3d9 | ||
|
|
057c209beb | ||
|
|
90c4afded4 | ||
|
|
f8f28a066b | ||
|
|
adc66edd8d | ||
|
|
9af211cc89 | ||
|
|
904bddd988 | ||
|
|
8badfa84e9 | ||
|
|
b97efa6fed | ||
|
|
591f9ad3cf | ||
|
|
6767cd1a4f | ||
|
|
226b6abfab | ||
|
|
9e2c14d64e | ||
|
|
92aeb53ee8 | ||
|
|
87f68e3ac1 | ||
|
|
8073a5dc34 | ||
|
|
eb09156244 | ||
|
|
b8cfb95b49 | ||
|
|
a7843add0f | ||
|
|
b0f0322726 | ||
|
|
7476faba68 | ||
|
|
89ab54794e | ||
|
|
85da0e104b | ||
|
|
47fe3668e4 | ||
|
|
7aae2181e2 | ||
|
|
a9269980eb | ||
|
|
0b9a64331f | ||
|
|
54ff730f0c | ||
|
|
e05fbaa8ab | ||
|
|
61f9346aaf | ||
|
|
d878148b5e | ||
|
|
ee509c7ee6 | ||
|
|
2fa0975dec | ||
|
|
f3ab1f996f | ||
|
|
92c5fc4643 | ||
|
|
c64fa9c81b | ||
|
|
85ec9ec5b2 | ||
|
|
b8933d8f81 | ||
|
|
631da4654f | ||
|
|
1701d72ff9 | ||
|
|
d3ec9a80d3 | ||
|
|
5a1253e37c | ||
|
|
2b008b52d7 | ||
|
|
83939abe10 | ||
|
|
16d02b3ed5 | ||
|
|
79be91831c | ||
|
|
427139f347 | ||
|
|
3ebd2c3f97 | ||
|
|
2414dbdbd4 | ||
|
|
0eae0e8cc0 | ||
|
|
efba965b0c | ||
|
|
26d2c77c3d | ||
|
|
eb01d7c97d | ||
|
|
5bff5bfea6 | ||
|
|
206e92218c | ||
|
|
af3dca9003 | ||
|
|
b924d715c9 | ||
|
|
1372d6f081 | ||
|
|
135a015b6a | ||
|
|
96645eaa7a | ||
|
|
d37b255a11 | ||
|
|
903ee43b2d | ||
|
|
8562f8a964 | ||
|
|
5ff794c105 | ||
|
|
f68e0972c2 | ||
|
|
ba3cc04e84 | ||
|
|
3d4cf44f9b | ||
|
|
8e702012fd | ||
|
|
f49879b522 | ||
|
|
5e0bf2446b | ||
|
|
4d96a3efaa | ||
|
|
c27d72e3a1 | ||
|
|
0819df6988 | ||
|
|
28579239a6 | ||
|
|
e48d2b467a | ||
|
|
1c589336a2 | ||
|
|
9546659c15 | ||
|
|
c782298ae4 | ||
|
|
682fce6a5b | ||
|
|
6ed1b707d5 | ||
|
|
9fd2ccff29 | ||
|
|
b6223a9d0a | ||
|
|
5e98f10011 | ||
|
|
e7ca05e1bf | ||
|
|
677c50fc51 | ||
|
|
bb5feeca77 | ||
|
|
22683ec490 | ||
|
|
0bf7d58c5e | ||
|
|
86566e8d0b | ||
|
|
7080a5ff8b | ||
|
|
5e52ad2ad1 | ||
|
|
bfaa9a9241 | ||
|
|
9c900789de | ||
|
|
29a24ba67f | ||
|
|
987f23698e | ||
|
|
cda4e6136c | ||
|
|
522b481297 | ||
|
|
fafe70f985 | ||
|
|
62818b9407 | ||
|
|
db2fa81358 | ||
|
|
d492901c3e | ||
|
|
a5d52eb853 | ||
|
|
89509c76f4 | ||
|
|
6395dda012 | ||
|
|
54bb0c12e6 | ||
|
|
1f1ed80dbf | ||
|
|
36bcb24b3a | ||
|
|
ddacf07e3b | ||
|
|
86961a9429 | ||
|
|
3ca20a8e70 | ||
|
|
3100404419 | ||
|
|
892c9767a2 | ||
|
|
2718dc02e0 | ||
|
|
abd7c66833 | ||
|
|
8716ddb07a | ||
|
|
fd7d93e619 | ||
|
|
0592c0e5ad | ||
|
|
684e3c460a | ||
|
|
4278668c8f | ||
|
|
a86ab6c854 | ||
|
|
b04eed0aea | ||
|
|
669e091b03 | ||
|
|
0b6a92150c | ||
|
|
cca2b6a624 | ||
|
|
1d24037f14 | ||
|
|
6395228bb8 | ||
|
|
b718f4d567 | ||
|
|
be88884315 | ||
|
|
d2a0eda56c | ||
|
|
5d9fc8b3c8 | ||
|
|
62f2f34655 | ||
|
|
171e65f73f | ||
|
|
446cedbcfc | ||
|
|
4012a4fe6f | ||
|
|
70dc61d647 | ||
|
|
ca481cce50 | ||
|
|
4d74838c50 | ||
|
|
c429052e5e | ||
|
|
1e55a066dc | ||
|
|
06abc256a4 | ||
|
|
7ea2e55793 | ||
|
|
34e8655a08 | ||
|
|
c512a47e8a | ||
|
|
012d77ac41 | ||
|
|
2acd3ca571 | ||
|
|
c74a1ab6d1 | ||
|
|
beac7f934d | ||
|
|
114097718a | ||
|
|
151551b52b | ||
|
|
89a0d5f958 | ||
|
|
3a82991586 | ||
|
|
08a90e911e | ||
|
|
3176eb8821 | ||
|
|
f74b3f7794 | ||
|
|
fc6403899e | ||
|
|
b10baf02ea | ||
|
|
96013a03c5 | ||
|
|
3b3fc573da | ||
|
|
e782de3747 | ||
|
|
c3e88f6e46 | ||
|
|
ac3b0d07ba | ||
|
|
9ca1564e2d | ||
|
|
fb63c39750 | ||
|
|
f007161bcd | ||
|
|
489332c07d | ||
|
|
15bee898b8 | ||
|
|
fb9e054637 | ||
|
|
7f6ab61292 | ||
|
|
f03d9361e3 | ||
|
|
24e7e1f100 | ||
|
|
61f0f86904 | ||
|
|
08da0eb1e1 | ||
|
|
8552290bec | ||
|
|
42c9003f49 | ||
|
|
7899bf4240 | ||
|
|
d1fbf34fdf | ||
|
|
9c12b762a7 | ||
|
|
f20b8bc311 | ||
|
|
8b8dc0fec2 | ||
|
|
82d0f4288a | ||
|
|
e86c45c988 | ||
|
|
56ae75d2b2 | ||
|
|
54a98bb286 | ||
|
|
bfbe24b172 | ||
|
|
1f925fef7c | ||
|
|
7b0093b4c6 | ||
|
|
0fd5a617ab | ||
|
|
e7d041d258 | ||
|
|
eda8d13927 | ||
|
|
5ba7ff8be9 | ||
|
|
da1a56a600 | ||
|
|
2b760dfa38 | ||
|
|
f1a61c060f | ||
|
|
5fb3b8b43a | ||
|
|
8fad2652ee | ||
|
|
6f5ba3cbb5 | ||
|
|
754ccfb865 | ||
|
|
d3014f1684 | ||
|
|
3568051686 | ||
|
|
9ce6ed4164 | ||
|
|
e0fd178bec | ||
|
|
168ab98021 | ||
|
|
ae5696a9bb | ||
|
|
038c7108a6 | ||
|
|
eb1013cdb6 | ||
|
|
5beac0ded7 | ||
|
|
7565562903 | ||
|
|
999bca076c | ||
|
|
e198b04222 | ||
|
|
3981c42d3e | ||
|
|
31afd3ba5c | ||
|
|
05fd2c58cb | ||
|
|
a033154b2e | ||
|
|
5e4bb26801 | ||
|
|
2cfff27729 | ||
|
|
378fae0ea2 | ||
|
|
01b0f7aba0 | ||
|
|
17ff49f85c | ||
|
|
de46e1e4b8 | ||
|
|
5e934a4fa0 | ||
|
|
5d0a3eab5c | ||
|
|
7efb860381 | ||
|
|
f9492d5345 | ||
|
|
46669e9f53 | ||
|
|
a949594050 | ||
|
|
20e8355c01 | ||
|
|
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 | ||
|
|
f404a69b73 | ||
|
|
50a837573d | ||
|
|
3e958ab7b4 | ||
|
|
a8a2a757ed | ||
|
|
702255b182 | ||
|
|
a64ac2296b | ||
|
|
a522e3fd6f | ||
|
|
65828e0e56 | ||
|
|
fe967d0ac2 | ||
|
|
10c5bdade7 | ||
|
|
8f21aa1b26 | ||
|
|
7b68344394 | ||
|
|
dccb5b3ab2 | ||
|
|
2fcc2deb43 | ||
|
|
c678b9021c | ||
|
|
b2e55308d6 | ||
|
|
a176fa1d34 | ||
|
|
cacce50ef9 | ||
|
|
5ab4d6c454 | ||
|
|
0c655be159 | ||
|
|
2b8c524928 | ||
|
|
2f2ea65d32 | ||
|
|
1d48b70f38 | ||
|
|
35e9f19c0c | ||
|
|
70a0d6f0fe | ||
|
|
7ed9b0c2f9 | ||
|
|
6a090656b6 | ||
|
|
e1d181887f | ||
|
|
e143f12e57 | ||
|
|
e64c18f8de | ||
|
|
7e70344b4a | ||
|
|
44af2173a8 | ||
|
|
e7c7f368c9 | ||
|
|
a29586f398 | ||
|
|
98cd1c2680 | ||
|
|
ae285e790d | ||
|
|
1e2f19ea3d | ||
|
|
b0effae990 | ||
|
|
ff67bf5a16 | ||
|
|
bac6382f67 | ||
|
|
e12978f402 | ||
|
|
1ba95db379 | ||
|
|
7ec2df2405 | ||
|
|
3ed73aa17c | ||
|
|
0241617713 | ||
|
|
20a52593eb | ||
|
|
42db16364d | ||
|
|
ee606ae49e | ||
|
|
f9b2c7f9c3 | ||
|
|
4115ae7ced | ||
|
|
8cc0fd321f | ||
|
|
a7541b1f76 | ||
|
|
b9ff75c4e9 | ||
|
|
4447a0d183 | ||
|
|
545af23536 | ||
|
|
db905a2048 | ||
|
|
712853d1e3 | ||
|
|
c6298ede72 | ||
|
|
b1d99e7608 | ||
|
|
5927a205e3 | ||
|
|
8c05f3b78c | ||
|
|
92db82e3d4 | ||
|
|
f6f689f9cd | ||
|
|
5dc3edf07c | ||
|
|
71625ec1cf | ||
|
|
c9216cf96c | ||
|
|
53713c0098 | ||
|
|
222c33ec32 | ||
|
|
19a50cfdc3 | ||
|
|
9892eb1c03 | ||
|
|
587131a6bd | ||
|
|
65d0d5e3e0 | ||
|
|
2642fc6560 | ||
|
|
a855c0cc79 | ||
|
|
876924df6a | ||
|
|
519b5acc91 | ||
|
|
e812653acd | ||
|
|
1b23f0efe1 | ||
|
|
f6559ba8b1 | ||
|
|
3b72b925b0 | ||
|
|
15d218a112 | ||
|
|
0a08a24896 | ||
|
|
cca6d3b04b | ||
|
|
be367988ae | ||
|
|
ea4da08af0 | ||
|
|
60ad1ab9e3 | ||
|
|
201b5a9614 | ||
|
|
8b270141f3 | ||
|
|
ceb62d7617 | ||
|
|
099fa9f005 | ||
|
|
dd7d1baece | ||
|
|
d8efa336e5 | ||
|
|
76dd4066f3 | ||
|
|
9b48864c5b | ||
|
|
14a41bdd48 | ||
|
|
25bc89a4f5 | ||
|
|
2f0824ab88 | ||
|
|
8ba6f4dad2 | ||
|
|
ada5d488fa | ||
|
|
b16245ad58 | ||
|
|
8b28133bee | ||
|
|
7a4dd96406 | ||
|
|
81a446db82 | ||
|
|
7bc62821ee | ||
|
|
1319daba54 | ||
|
|
39e3e2b794 | ||
|
|
ab804f7f49 | ||
|
|
f2b932960e | ||
|
|
d1fb1e26f3 | ||
|
|
fd5f511b33 | ||
|
|
cddd0f4653 | ||
|
|
256c7cea07 | ||
|
|
d91ec2d044 | ||
|
|
ad920f9597 | ||
|
|
728335581f | ||
|
|
9b37256175 | ||
|
|
951d482bc6 | ||
|
|
33530d62c7 | ||
|
|
65e602d8c7 | ||
|
|
6a1e7103f6 | ||
|
|
f25d0a0dc9 | ||
|
|
3b480caab1 | ||
|
|
dcc04089d1 | ||
|
|
0b87b21d52 | ||
|
|
b92e6d6acd | ||
|
|
538038867b | ||
|
|
e372311afe | ||
|
|
4a95f795cb | ||
|
|
fcfe82a7b8 | ||
|
|
a8d15bccba | ||
|
|
aec1b7caad | ||
|
|
5eba6067a3 | ||
|
|
664d18836e | ||
|
|
ac65cf455e | ||
|
|
b8bb08649d | ||
|
|
57866c45cd | ||
|
|
fbf4b45e76 | ||
|
|
431ed7210b | ||
|
|
043b31df70 | ||
|
|
2e30572364 | ||
|
|
fd64c46c74 | ||
|
|
61e49c2659 | ||
|
|
441b1238a5 | ||
|
|
0a47df7bb7 | ||
|
|
5e05afecf2 | ||
|
|
7ef64b5f5f | ||
|
|
0169fe8cf6 | ||
|
|
f119c273fd | ||
|
|
dac489b7f6 | ||
|
|
6ec11a2b26 | ||
|
|
4640e3f5b0 | ||
|
|
36777896c2 | ||
|
|
6e25a27870 | ||
|
|
0b4f682233 | ||
|
|
d184a7662c | ||
|
|
3f0a143037 | ||
|
|
b46d336d2b | ||
|
|
7d6b0c1376 | ||
|
|
dd40aeaa79 | ||
|
|
2b6f22b84d | ||
|
|
689aff0232 | ||
|
|
30a449841c | ||
|
|
56543e1311 | ||
|
|
9b175a7681 | ||
|
|
d67a801f1f | ||
|
|
95d7c0e800 | ||
|
|
059fc5ef7d | ||
|
|
7fed33fb49 | ||
|
|
ce9702571b | ||
|
|
01ec1c5777 | ||
|
|
ec8dd6410e | ||
|
|
45d7046f99 | ||
|
|
5fcd41b962 | ||
|
|
6ba8a15d3a | ||
|
|
5b615e33a0 | ||
|
|
823f2c1067 | ||
|
|
19732341d6 | ||
|
|
0e44eb4c1c | ||
|
|
50461b4d7d | ||
|
|
c11126181e | ||
|
|
658c301e3c | ||
|
|
dce52ed081 | ||
|
|
f309f586c9 | ||
|
|
ae1b10dba8 | ||
|
|
860a256f4b | ||
|
|
cb2f46ed08 | ||
|
|
13deaa66fd | ||
|
|
3597a5b0ed | ||
|
|
0352995cb3 | ||
|
|
e9041da7f4 | ||
|
|
252180e088 | ||
|
|
6361c208bd | ||
|
|
2ef8ace543 | ||
|
|
0400bcc85e | ||
|
|
76db6a5a16 | ||
|
|
5b171f9577 | ||
|
|
4cec28416e | ||
|
|
3b32baccf6 | ||
|
|
16875d7776 | ||
|
|
a9600e23a1 | ||
|
|
a4b6813ebf | ||
|
|
ef90938eb9 | ||
|
|
66891274a7 | ||
|
|
f52276bd06 | ||
|
|
7dce8dbfaa | ||
|
|
3b757ee738 | ||
|
|
0a45ed7af6 | ||
|
|
1db2dc3f58 | ||
|
|
953c75575b | ||
|
|
8c7ff259af | ||
|
|
3e666130c2 | ||
|
|
2babfa0625 | ||
|
|
83af40679a | ||
|
|
ce31c1d704 | ||
|
|
b20a74a22c | ||
|
|
66461e4c81 | ||
|
|
6ba9439bbb | ||
|
|
6764ec79ae | ||
|
|
6f4c378933 | ||
|
|
b121fa2cc9 | ||
|
|
ca26e85fd4 | ||
|
|
0714380360 | ||
|
|
b9af7952a4 | ||
|
|
ea6820ed51 | ||
|
|
a1e46de462 | ||
|
|
1abe213844 | ||
|
|
0372ae8ba5 | ||
|
|
a1e69a0e9d | ||
|
|
49e1e98914 | ||
|
|
34b316d7d5 | ||
|
|
9abc6791c7 | ||
|
|
5459823667 | ||
|
|
4fa8c5ec47 | ||
|
|
239034714f | ||
|
|
8a3a974ea3 | ||
|
|
db607c4a6f | ||
|
|
a53f07a8f6 | ||
|
|
c3e996b96c | ||
|
|
a218437cf4 | ||
|
|
0add0ca9b1 | ||
|
|
eaa4aa964c | ||
|
|
74bb899ce2 | ||
|
|
69fe7a1b8c | ||
|
|
ce856efa25 | ||
|
|
b54514df6e | ||
|
|
551616c3ab | ||
|
|
cec307ce7f | ||
|
|
e7bc8e03fc | ||
|
|
9a025bde8b | ||
|
|
6845e400cd | ||
|
|
25d0fa42e2 | ||
|
|
52208a6606 | ||
|
|
6725b22fd4 | ||
|
|
21bac43015 | ||
|
|
0ddd11f81b | ||
|
|
6d47c44335 | ||
|
|
3cbc908a6e | ||
|
|
95b1e75f1b | ||
|
|
bcfe0ad12c | ||
|
|
2088a6177f | ||
|
|
c9733d27df | ||
|
|
dd24cf57c6 | ||
|
|
451a4c0969 | ||
|
|
dabcae7b4d | ||
|
|
eae5721f8e | ||
|
|
ce1a675dd5 | ||
|
|
6ba1016024 | ||
|
|
b5f175b78e | ||
|
|
aff7efd891 | ||
|
|
1d00c2d4b4 | ||
|
|
61483a4c47 | ||
|
|
2b21430abe | ||
|
|
1781ad140e | ||
|
|
d2e3ad4dbc | ||
|
|
7615aaef7a | ||
|
|
92e3168309 | ||
|
|
ca148cbcf1 | ||
|
|
e57f037a10 | ||
|
|
46ad86fab2 | ||
|
|
511e164f17 | ||
|
|
6f18fc4bf4 | ||
|
|
8ca34303f2 | ||
|
|
882fc8ab54 | ||
|
|
9e5ae25abf | ||
|
|
9316dfed2e | ||
|
|
702932c69b | ||
|
|
29461fa910 | ||
|
|
f7173e6645 | ||
|
|
11b11a9d71 | ||
|
|
9da69dfc36 | ||
|
|
e5f4021a4f | ||
|
|
4dcbc6a3aa | ||
|
|
7a72d8fd58 | ||
|
|
5edfd55e00 | ||
|
|
2951daaa01 | ||
|
|
23f7c4aaf7 | ||
|
|
3dc5c4a6de | ||
|
|
a97ae3bc35 | ||
|
|
53d2fb3ad2 | ||
|
|
4f7e507716 | ||
|
|
f2e3a840db | ||
|
|
f45c18116a | ||
|
|
2365c608f9 | ||
|
|
6c6daaa619 | ||
|
|
857a399bfa | ||
|
|
6e230f0a07 | ||
|
|
7402401057 | ||
|
|
fe17dfe01d | ||
|
|
4885b38be5 | ||
|
|
5d4a5981d0 | ||
|
|
0fcb4533b5 | ||
|
|
422f81b60c | ||
|
|
e0d2f3ae53 | ||
|
|
531d9048b3 | ||
|
|
18495d122d | ||
|
|
9bcacd97df | ||
|
|
d91eae26e5 | ||
|
|
d113ed9d83 | ||
|
|
e113754312 | ||
|
|
b1afa9da5d | ||
|
|
700c5791f8 | ||
|
|
97d0a6dfe6 | ||
|
|
a54d020c97 | ||
|
|
36b696f433 | ||
|
|
f42cd6eefd | ||
|
|
46ebb39f65 | ||
|
|
c88a51cce8 | ||
|
|
3a7b03f022 | ||
|
|
94450a1d74 | ||
|
|
c35ad20249 | ||
|
|
5e8b4a81e9 | ||
|
|
21a779235d | ||
|
|
1006467f33 | ||
|
|
cffe49de5c | ||
|
|
7962d8cdab | ||
|
|
36dba33808 | ||
|
|
c273908471 | ||
|
|
bf8661bf45 | ||
|
|
499b522183 | ||
|
|
13bfe7a65c | ||
|
|
e90ec04441 | ||
|
|
a59a5caaf3 | ||
|
|
5b9f81fb46 | ||
|
|
d3aaebb352 | ||
|
|
a99f920fe0 | ||
|
|
fb5527c58c | ||
|
|
fcd3c1dd89 | ||
|
|
3a9500be67 | ||
|
|
1d93b86569 | ||
|
|
aca2cd41d8 | ||
|
|
1035f733aa | ||
|
|
2818d94010 | ||
|
|
1d1c34eb60 | ||
|
|
ca06fae22e | ||
|
|
36f527269b | ||
|
|
7cfe20e07f | ||
|
|
1fd82b5162 | ||
|
|
0ace5f64f8 | ||
|
|
e532524c7e | ||
|
|
ebd96f892e | ||
|
|
4b9b34fa4d | ||
|
|
bcc1e7ae73 | ||
|
|
27accf42f2 | ||
|
|
96f2e07cdd | ||
|
|
192c4f3cfc | ||
|
|
cb274032da | ||
|
|
b890fa56d8 | ||
|
|
b817b46494 | ||
|
|
49ba59369a | ||
|
|
d09cb88e9a | ||
|
|
44c3f4f772 | ||
|
|
948a67a51f | ||
|
|
de79609550 | ||
|
|
d18e10535e | ||
|
|
2954583373 | ||
|
|
ccdecdea11 | ||
|
|
946388d1e9 | ||
|
|
10ae8ffb55 | ||
|
|
bdba9990fb | ||
|
|
50166e88c0 | ||
|
|
f2bc826a20 | ||
|
|
ac48d66203 | ||
|
|
f68e7fcb9f | ||
|
|
0c3a22758b | ||
|
|
9cc859a318 | ||
|
|
7dfc8f3364 | ||
|
|
e397571f83 | ||
|
|
d34d7c26de | ||
|
|
77defa1d8b | ||
|
|
5d01497b8b | ||
|
|
cb8732b255 | ||
|
|
3f64b2ea5a | ||
|
|
57b38a2876 | ||
|
|
058f91909d | ||
|
|
4f75e63e25 | ||
|
|
2e50ff5e7c | ||
|
|
0b7477e72c | ||
|
|
4dc8aa6dfa | ||
|
|
161c3ccf1c | ||
|
|
170da7fec1 | ||
|
|
d7af9a4498 | ||
|
|
3cb3b1d63a | ||
|
|
fc66919e1f | ||
|
|
de5b4e7dcb | ||
|
|
561576961c | ||
|
|
2946dabd24 | ||
|
|
969eefc81f | ||
|
|
efee7262b6 | ||
|
|
1102d6e478 | ||
|
|
603aab0a81 | ||
|
|
10e934e234 | ||
|
|
48b9e6c517 | ||
|
|
5ae2ef5407 | ||
|
|
cafa05dab5 | ||
|
|
6345835b02 | ||
|
|
1d453b5732 | ||
|
|
d3a1b86ea4 | ||
|
|
bb27ca5720 | ||
|
|
065c0b6202 | ||
|
|
b4819701b4 | ||
|
|
daed05755a | ||
|
|
fb192f706c | ||
|
|
350b0a38e2 | ||
|
|
9ccbda4a40 | ||
|
|
821cbae187 | ||
|
|
528f3556ea | ||
|
|
489afea605 | ||
|
|
688a133f3f | ||
|
|
0cd37b0142 | ||
|
|
9fb789dc78 | ||
|
|
770444af55 | ||
|
|
703d9b2a07 | ||
|
|
a96509f286 | ||
|
|
8553f2e41c | ||
|
|
56c96dde8b | ||
|
|
9793d60c5a | ||
|
|
4ff97e7cbd | ||
|
|
75fe328f64 | ||
|
|
b28b006d61 | ||
|
|
c3b1c982bc | ||
|
|
b098399bbc | ||
|
|
65bbdff3fc | ||
|
|
fba3e682ea | ||
|
|
bccff4ffef | ||
|
|
9843c2d764 | ||
|
|
c9abbec48a | ||
|
|
bc79f9504b | ||
|
|
626b0f1a8f | ||
|
|
da95af0f48 | ||
|
|
28b6f643d8 | ||
|
|
22277c7277 | ||
|
|
19e7b217c1 | ||
|
|
29d3541b74 | ||
|
|
b9e5b3a55c | ||
|
|
b1ac865abd | ||
|
|
21504c0621 | ||
|
|
056ea541dd | ||
|
|
871fddf5fb | ||
|
|
c284858d06 | ||
|
|
bb4d888661 | ||
|
|
ff77cfc9b5 | ||
|
|
80f91ecb7b | ||
|
|
6cb77465ab | ||
|
|
6f6127cbb6 | ||
|
|
e1d85fb636 | ||
|
|
74b5c92787 | ||
|
|
ac1f97e2eb | ||
|
|
40f486b108 | ||
|
|
b62e67401c | ||
|
|
dd0a0134a6 | ||
|
|
5e24000799 | ||
|
|
c5cdfcb120 | ||
|
|
549a6694d2 | ||
|
|
14e34e1d15 | ||
|
|
e5393bf46a | ||
|
|
878a201bb1 | ||
|
|
b0e4619e0a | ||
|
|
aec65777a7 | ||
|
|
31bad8ddd2 | ||
|
|
79d65c907f | ||
|
|
92231d984f | ||
|
|
2fbc77955e | ||
|
|
c91819f551 | ||
|
|
b3f6ff5a36 | ||
|
|
52f84bee3c | ||
|
|
dda6857fee | ||
|
|
0215483fb3 | ||
|
|
37bb59df13 | ||
|
|
db34837d2d | ||
|
|
ba49677794 | ||
|
|
1a376c1bfa | ||
|
|
ef807d9d0e | ||
|
|
2a4893d946 | ||
|
|
cee061b363 | ||
|
|
1bbdf304ab | ||
|
|
6155068f9e | ||
|
|
0c4e3bb1c4 | ||
|
|
4547ff0c19 | ||
|
|
b7cce4d91d | ||
|
|
475250ce71 | ||
|
|
f40f231a63 | ||
|
|
d83d92adf2 | ||
|
|
d15282bff1 | ||
|
|
00637c4f0b | ||
|
|
2e035a7f45 | ||
|
|
17577175f8 | ||
|
|
933fab6ed4 | ||
|
|
7e5661caff | ||
|
|
19dfb138a6 | ||
|
|
0930f2614c | ||
|
|
1b20521e5c | ||
|
|
0e351db91a | ||
|
|
9cca501650 | ||
|
|
2481cbe4ab | ||
|
|
bc3959d1e0 | ||
|
|
1ac815e457 | ||
|
|
55b83062d0 | ||
|
|
391f77ce5e | ||
|
|
bc30a3d2e5 | ||
|
|
ff5de4ff03 | ||
|
|
f433a4d67c | ||
|
|
994061af44 | ||
|
|
501020921e | ||
|
|
53c09405b2 | ||
|
|
1f0079a274 | ||
|
|
15afe43cf0 | ||
|
|
eb8f7ba3b2 | ||
|
|
901a6f7fed | ||
|
|
fc92f62136 | ||
|
|
ff09456cf5 | ||
|
|
32fcfde86b | ||
|
|
363a1b3371 | ||
|
|
c376c6fb02 | ||
|
|
8e6e23b8d0 | ||
|
|
63e5d56441 | ||
|
|
e9bfd943fc | ||
|
|
614e2286c2 | ||
|
|
768a74c4bf | ||
|
|
612e9e11de | ||
|
|
06c72d54be | ||
|
|
be68bacc94 | ||
|
|
317d7bc988 | ||
|
|
b44e417bca | ||
|
|
9d67ce484d | ||
|
|
78b8602cf6 | ||
|
|
83a0a7681b | ||
|
|
c5e0e41ce7 | ||
|
|
b3fe4a1e91 | ||
|
|
f59bf389d9 | ||
|
|
231b8f9f92 | ||
|
|
dac153d24a | ||
|
|
3661d146a7 | ||
|
|
3bf55a3e07 | ||
|
|
5226467fc2 | ||
|
|
54deaa1b24 | ||
|
|
7ff667f58d | ||
|
|
58ba9b02ed | ||
|
|
d35da0ce99 | ||
|
|
041e6a1078 | ||
|
|
1c73c36ed7 | ||
|
|
69de32f700 | ||
|
|
4bfee76ead | ||
|
|
4d7afd9b4f | ||
|
|
cfe60c0640 | ||
|
|
d82847a6b4 | ||
|
|
5a7e6e07ff | ||
|
|
2162aa9f48 | ||
|
|
a1f36c71c9 | ||
|
|
e4eedef27e | ||
|
|
5e29695969 | ||
|
|
49a46668ad | ||
|
|
76269decdd | ||
|
|
8454a25ecf | ||
|
|
a0bbbd7d32 | ||
|
|
12f6dae8cd | ||
|
|
9570c36fd4 | ||
|
|
487dae0d2f | ||
|
|
d71018bd8f | ||
|
|
61fa57b05d | ||
|
|
fc1781e317 | ||
|
|
ffef6c2bcc | ||
|
|
67d29f7936 | ||
|
|
9437c98d54 | ||
|
|
f7d00a828d | ||
|
|
0f0a4b2da6 | ||
|
|
c9cdbaf880 | ||
|
|
83f29dad9f | ||
|
|
c2a11c5918 | ||
|
|
3746b2ad5c | ||
|
|
b51fa446e3 | ||
|
|
6fc5293e83 | ||
|
|
aab3daa28b | ||
|
|
e40f7bd1f7 | ||
|
|
6664f87d8f | ||
|
|
6e8d5cd6a1 | ||
|
|
9f7e1ecf40 | ||
|
|
d9567002e4 | ||
|
|
a656a4a9f3 | ||
|
|
2944a35e74 | ||
|
|
391373fb0c | ||
|
|
985e8c4577 | ||
|
|
bd0d4258e4 | ||
|
|
9bbd9b208a | ||
|
|
59fe0fb699 | ||
|
|
f1fdd71613 | ||
|
|
bb66780cb5 | ||
|
|
45fb6d7908 | ||
|
|
9f408bf51b | ||
|
|
ee32166267 | ||
|
|
a3c90f2b24 | ||
|
|
dc537ef2c9 | ||
|
|
061a457658 | ||
|
|
82ae7c1c09 | ||
|
|
79d79c3c87 | ||
|
|
35e356f625 | ||
|
|
948ab02d1a | ||
|
|
a6101026d2 | ||
|
|
e0966cb20f | ||
|
|
e278e8321c | ||
|
|
e1728e7c25 | ||
|
|
e215b05094 | ||
|
|
fe3fdd1f50 | ||
|
|
5ff45658c0 | ||
|
|
d12b294783 | ||
|
|
2bba4fb073 | ||
|
|
aeca32fc12 | ||
|
|
12c1088777 |
113
.ci/check-abi
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import contextlib
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def format_title(title):
|
||||||
|
box = {
|
||||||
|
'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║',
|
||||||
|
}
|
||||||
|
hline = box['h'] * (len(title) + 2)
|
||||||
|
|
||||||
|
return '\n'.join([
|
||||||
|
f"{box['tl']}{hline}{box['tr']}",
|
||||||
|
f"{box['v']} {title} {box['v']}",
|
||||||
|
f"{box['bl']}{hline}{box['br']}",
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def rm_rf(path):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_path(name):
|
||||||
|
return name.replace('/', '-')
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_revision():
|
||||||
|
revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
|
||||||
|
encoding='utf-8').strip()
|
||||||
|
|
||||||
|
if revision == 'HEAD':
|
||||||
|
# This is a detached HEAD, get the commit hash
|
||||||
|
revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')
|
||||||
|
|
||||||
|
return revision
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def checkout_git_revision(revision):
|
||||||
|
current_revision = get_current_revision()
|
||||||
|
subprocess.check_call(['git', 'checkout', '-q', revision])
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
subprocess.check_call(['git', 'checkout', '-q', current_revision])
|
||||||
|
|
||||||
|
|
||||||
|
def build_install(revision):
|
||||||
|
build_dir = '_build'
|
||||||
|
dest_dir = os.path.abspath(sanitize_path(revision))
|
||||||
|
print(format_title(f'# Building and installing {revision} in {dest_dir}'),
|
||||||
|
end='\n\n', flush=True)
|
||||||
|
|
||||||
|
with checkout_git_revision(revision):
|
||||||
|
rm_rf(build_dir)
|
||||||
|
rm_rf(revision)
|
||||||
|
|
||||||
|
subprocess.check_call(['meson', build_dir,
|
||||||
|
'--prefix=/usr', '--libdir=lib',
|
||||||
|
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
|
||||||
|
subprocess.check_call(['ninja', '-v', '-C', build_dir])
|
||||||
|
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
|
||||||
|
env={'DESTDIR': dest_dir})
|
||||||
|
|
||||||
|
return dest_dir
|
||||||
|
|
||||||
|
|
||||||
|
def compare(old_tree, new_tree):
|
||||||
|
print(format_title(f'# Comparing the two ABIs'), end='\n\n', flush=True)
|
||||||
|
|
||||||
|
old_headers = os.path.join(old_tree, 'usr', 'include')
|
||||||
|
old_lib = os.path.join(old_tree, 'usr', 'lib', 'libfprint.so')
|
||||||
|
|
||||||
|
new_headers = os.path.join(new_tree, 'usr', 'include')
|
||||||
|
new_lib = os.path.join(new_tree, 'usr', 'lib', 'libfprint.so')
|
||||||
|
|
||||||
|
subprocess.check_call([
|
||||||
|
'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers,
|
||||||
|
'--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument('old', help='the previous revision, considered the reference')
|
||||||
|
parser.add_argument('new', help='the new revision, to compare to the reference')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.old == args.new:
|
||||||
|
print("Let's not waste time comparing something to itself")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
old_tree = build_install(args.old)
|
||||||
|
new_tree = build_install(args.new)
|
||||||
|
|
||||||
|
try:
|
||||||
|
compare(old_tree, new_tree)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f'Hurray! {args.old} and {args.new} are ABI-compatible!')
|
||||||
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
@@ -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
|
|
||||||
|
|||||||
296
.gitlab-ci.yml
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
include:
|
||||||
|
- local: '.gitlab-ci/libfprint-image-variables.yaml'
|
||||||
|
- local: '.gitlab-ci/libfprint-templates.yaml'
|
||||||
|
- project: 'freedesktop/ci-templates'
|
||||||
|
ref: master
|
||||||
|
file: '/templates/fedora.yml'
|
||||||
|
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/71e636e012ae0ab04c5e0fe40ca73ada91ae6bde/flatpak/flatpak_ci_initiative.yml'
|
||||||
|
|
||||||
|
default:
|
||||||
|
# Auto-retry jobs in case of infra failures
|
||||||
|
retry:
|
||||||
|
max: 1
|
||||||
|
when:
|
||||||
|
- 'runner_system_failure'
|
||||||
|
- 'stuck_or_timeout_failure'
|
||||||
|
- 'scheduler_failure'
|
||||||
|
- 'api_failure'
|
||||||
|
|
||||||
|
variables:
|
||||||
|
extends: .libfprint_common_variables
|
||||||
|
FDO_DISTRIBUTION_TAG: $LIBFPRINT_IMAGE_TAG
|
||||||
|
FDO_DISTRIBUTION_VERSION: 41
|
||||||
|
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
|
||||||
|
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||||
|
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||||
|
|
||||||
|
workflow:
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||||
|
- if: $CI_PIPELINE_SOURCE == 'push'
|
||||||
|
- if: $CI_PIPELINE_SOURCE == 'schedule'
|
||||||
|
- if: $CI_PROJECT_NAMESPACE == 'libfprint' && $LIBFPRINT_CI_ACTION != ''
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- image-build
|
||||||
|
- check-source
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
- flatpak
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
image: $FEDORA_IMAGE
|
||||||
|
|
||||||
|
.build_one_driver_template: &build_one_driver
|
||||||
|
script:
|
||||||
|
# Build with a driver that doesn't need imaging, or openssl
|
||||||
|
- meson setup _build --werror -Ddrivers=$driver
|
||||||
|
- meson compile -C _build
|
||||||
|
- rm -rf _build/
|
||||||
|
|
||||||
|
.build_template: &build
|
||||||
|
script:
|
||||||
|
# And build with everything
|
||||||
|
- meson setup _build --werror -Ddrivers=all
|
||||||
|
- meson compile -C _build
|
||||||
|
- meson install -C _build
|
||||||
|
|
||||||
|
.build_template: &check_abi
|
||||||
|
script:
|
||||||
|
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
|
||||||
|
|
||||||
|
.standard_job:
|
||||||
|
rules:
|
||||||
|
- when: on_success
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
when: never
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
variables:
|
||||||
|
driver: virtual_image
|
||||||
|
<<: *build_one_driver
|
||||||
|
<<: *build
|
||||||
|
# <<: *check_abi
|
||||||
|
artifacts:
|
||||||
|
expose_as: "HTML Documentation"
|
||||||
|
paths:
|
||||||
|
- _build/doc/html
|
||||||
|
- _build/doc/html/index.html
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
script:
|
||||||
|
- meson setup _build --werror -Ddrivers=all -Db_coverage=true
|
||||||
|
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
||||||
|
- ninja -C _build coverage || true
|
||||||
|
- cat _build/meson-logs/coverage.txt || true
|
||||||
|
artifacts:
|
||||||
|
reports:
|
||||||
|
junit: "_build/meson-logs/testlog.junit.xml"
|
||||||
|
coverage_report:
|
||||||
|
coverage_format: cobertura
|
||||||
|
path: _build/meson-logs/coverage.xml
|
||||||
|
expose_as: 'Coverage Report'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
- _build/meson-logs/coveragereport/index.html
|
||||||
|
expire_in: 1 week
|
||||||
|
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
||||||
|
|
||||||
|
test_valgrind:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
script:
|
||||||
|
- meson setup _build -Ddrivers=all
|
||||||
|
- meson compile -C _build
|
||||||
|
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
|
||||||
|
artifacts:
|
||||||
|
reports:
|
||||||
|
junit: "_build/meson-logs/testlog-valgrind.junit.xml"
|
||||||
|
expose_as: 'Valgrind test logs'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
- _build/meson-logs/testlog-valgrind.txt
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
test_asan:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
script:
|
||||||
|
- meson setup _build -Ddrivers=all -Db_sanitize=address,undefined
|
||||||
|
- meson test -C _build --print-errorlogs --no-stdsplit
|
||||||
|
artifacts:
|
||||||
|
reports:
|
||||||
|
junit: "_build/meson-logs/testlog.junit.xml"
|
||||||
|
expose_as: 'Sanitizers test logs'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
- _build/meson-logs/testlog.txt
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
test_installed:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
script:
|
||||||
|
- meson setup _build --prefix=/usr -Ddrivers=all
|
||||||
|
- meson install -C _build
|
||||||
|
- mv _build _build_dir
|
||||||
|
- rm -rf tests
|
||||||
|
- gnome-desktop-testing-runner --list libfprint-2
|
||||||
|
- gnome-desktop-testing-runner libfprint-2
|
||||||
|
--report-directory=_installed-tests-report/failed/
|
||||||
|
--log-directory=_installed-tests-report/logs/
|
||||||
|
--parallel=0
|
||||||
|
artifacts:
|
||||||
|
expose_as: 'GNOME Tests Runner logs'
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- _build_dir/meson-logs
|
||||||
|
- _installed-tests-report
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
|
||||||
|
test_scan_build:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- meson setup _build -Ddrivers=all
|
||||||
|
# Wrapper to add --status-bugs and disable malloc checker
|
||||||
|
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build
|
||||||
|
ninja -C _build scan-build
|
||||||
|
artifacts:
|
||||||
|
when: on_failure
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
test_indent:
|
||||||
|
stage: check-source
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
script:
|
||||||
|
- scripts/uncrustify.sh
|
||||||
|
- git diff
|
||||||
|
- git diff-index --name-only --exit-code HEAD
|
||||||
|
rules:
|
||||||
|
- changes:
|
||||||
|
compare_to: 'refs/heads/master'
|
||||||
|
paths:
|
||||||
|
- '**/*.c'
|
||||||
|
- '**/*.h'
|
||||||
|
|
||||||
|
test_unsupported_list:
|
||||||
|
stage: check-source
|
||||||
|
extends:
|
||||||
|
- .standard_job
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- tests/hwdb-check-unsupported.py
|
||||||
|
|
||||||
|
flatpak:
|
||||||
|
stage: flatpak
|
||||||
|
extends: .flatpak@x86_64
|
||||||
|
variables:
|
||||||
|
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||||
|
FLATPAK_MODULE: "libfprint"
|
||||||
|
APP_ID: "org.freedesktop.libfprint.Demo"
|
||||||
|
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||||
|
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
|
||||||
|
# Build with any builder
|
||||||
|
tags: []
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
when: never
|
||||||
|
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||||
|
allow_failure: true
|
||||||
|
when: always
|
||||||
|
- if: '$CI_COMMIT_TAG'
|
||||||
|
allow_failure: true
|
||||||
|
when: always
|
||||||
|
# For any other (commit), allow manual run.
|
||||||
|
# This excludes MRs which would create a duplicate pipeline
|
||||||
|
- if: '$CI_COMMIT_BRANCH'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: '$CI_MERGE_REQUEST_ID'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
# CONTAINERS creation stage
|
||||||
|
.container_fedora_build_base:
|
||||||
|
extends: .fdo.container-build@fedora
|
||||||
|
stage: image-build
|
||||||
|
variables:
|
||||||
|
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
||||||
|
# a list of packages to install
|
||||||
|
FDO_DISTRIBUTION_PACKAGES:
|
||||||
|
$LIBFPRINT_DEPENDENCIES
|
||||||
|
vala
|
||||||
|
libpcap-devel
|
||||||
|
libudev-devel
|
||||||
|
FDO_DISTRIBUTION_EXEC: |
|
||||||
|
$LIBFPRINT_EXEC
|
||||||
|
rules:
|
||||||
|
- when: never
|
||||||
|
|
||||||
|
.container_fedora_build_forced:
|
||||||
|
variables:
|
||||||
|
FDO_FORCE_REBUILD: 1
|
||||||
|
|
||||||
|
container_fedora_build_schedule:
|
||||||
|
extends:
|
||||||
|
- .container_fedora_build_base
|
||||||
|
- .container_fedora_build_forced
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||||
|
when: always
|
||||||
|
|
||||||
|
container_fedora_build_manual:
|
||||||
|
extends:
|
||||||
|
- .container_fedora_build_base
|
||||||
|
- .container_fedora_build_forced
|
||||||
|
rules:
|
||||||
|
- if: $LIBFPRINT_CI_ACTION == "build-image"
|
||||||
|
when: always
|
||||||
|
|
||||||
|
container_fedora_build_on_deps_changed:
|
||||||
|
extends: .container_fedora_build_base
|
||||||
|
rules:
|
||||||
|
- if: $CI_PROJECT_NAMESPACE == "libfprint" && $CI_PIPELINE_SOURCE != "schedule"
|
||||||
|
changes:
|
||||||
|
compare_to: 'refs/heads/master'
|
||||||
|
paths:
|
||||||
|
- '.gitlab-ci/libfprint-image-variables.yaml'
|
||||||
|
- '.gitlab-ci/libfprint-templates.yaml'
|
||||||
|
|
||||||
|
pages:
|
||||||
|
image: alpine:latest
|
||||||
|
stage: deploy
|
||||||
|
needs:
|
||||||
|
- job: test
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- mkdir public
|
||||||
|
- mv _build/meson-logs/coveragereport public/coverage
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"
|
||||||
2
.gitlab-ci/libfprint-image-variables.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
variables:
|
||||||
|
LIBFPRINT_IMAGE_TAG: v6
|
||||||
47
.gitlab-ci/libfprint-templates.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Bump image version on .gitlab-ci/libfprint-image-variables.yaml to trigger
|
||||||
|
# a rebuild on changes to this file
|
||||||
|
|
||||||
|
.libfprint_common_variables:
|
||||||
|
LIBFPRINT_DEPENDENCIES:
|
||||||
|
appstream
|
||||||
|
doxygen
|
||||||
|
dnf-plugins-core
|
||||||
|
flatpak-builder
|
||||||
|
gcc
|
||||||
|
gcc-c++
|
||||||
|
gcovr
|
||||||
|
git
|
||||||
|
glib2-devel
|
||||||
|
glibc-devel
|
||||||
|
gobject-introspection-devel
|
||||||
|
gnome-desktop-testing
|
||||||
|
gtk-doc
|
||||||
|
gtk3-devel
|
||||||
|
libabigail
|
||||||
|
libasan
|
||||||
|
libgusb-devel
|
||||||
|
libgudev-devel
|
||||||
|
libubsan
|
||||||
|
libX11-devel
|
||||||
|
libXv-devel
|
||||||
|
meson
|
||||||
|
openssl-devel
|
||||||
|
pixman-devel
|
||||||
|
python3-cairo
|
||||||
|
python3-gobject
|
||||||
|
systemd
|
||||||
|
umockdev
|
||||||
|
uncrustify
|
||||||
|
valgrind
|
||||||
|
clang-analyzer
|
||||||
|
diffutils
|
||||||
|
|
||||||
|
LIBFPRINT_EXEC: |
|
||||||
|
dnf -y install dnf-utils
|
||||||
|
debuginfo-install -y \
|
||||||
|
glib2 \
|
||||||
|
glibc \
|
||||||
|
libgusb \
|
||||||
|
libusb \
|
||||||
|
openssl \
|
||||||
|
pixman
|
||||||
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 --exclude "_build/meson-private" "$@"
|
||||||
96
HACKING
@@ -1,96 +0,0 @@
|
|||||||
Copyright notices
|
|
||||||
=================
|
|
||||||
|
|
||||||
If you make a contribution substantial enough to add or update a copyright
|
|
||||||
notice on a file, such notice must be mirrored in the AUTHORS file. This is
|
|
||||||
to make it easy for people to comply to section 6 of the LGPL, which states
|
|
||||||
that a "work that uses the Library" must include copyright notices from
|
|
||||||
this library. By providing them all in one place, hopefully we save such
|
|
||||||
users some time.
|
|
||||||
|
|
||||||
|
|
||||||
USB
|
|
||||||
===
|
|
||||||
|
|
||||||
At the time of development, there are no known consumer fingerprint readers
|
|
||||||
which do not operate over the USB bus. Therefore the library is designed around
|
|
||||||
the fact that each driver drivers USB devices, and each device is a USB device.
|
|
||||||
If we were to ever support a non-USB device, some rearchitecting would be
|
|
||||||
needed, but this would not be a substantial task.
|
|
||||||
|
|
||||||
|
|
||||||
GLib
|
|
||||||
====
|
|
||||||
|
|
||||||
Although the library uses GLib internally, libfprint is designed to provide
|
|
||||||
a completely neutral interface to it's application users. So, the public
|
|
||||||
APIs should never return GLib data types or anything like that.
|
|
||||||
|
|
||||||
|
|
||||||
Two-faced-ness
|
|
||||||
==============
|
|
||||||
|
|
||||||
Like any decent library, this one is designed to provide a stable and
|
|
||||||
documented API to it's users: applications. Clear distinction is made between
|
|
||||||
data available internally in the library, and data/functions available to
|
|
||||||
the applications.
|
|
||||||
|
|
||||||
This library is confused a little by the fact that there is another 'interface'
|
|
||||||
at hand: the internal interface provided to drivers. So, we effectively end
|
|
||||||
up with 2 APIs:
|
|
||||||
|
|
||||||
1. The external-facing API for applications
|
|
||||||
2. The internal API for fingerprint drivers
|
|
||||||
|
|
||||||
Non-static functions which are intended for internal use only are prepended
|
|
||||||
with the "fpi_" prefix.
|
|
||||||
|
|
||||||
|
|
||||||
API stability
|
|
||||||
=============
|
|
||||||
|
|
||||||
No API stability has been promised to anyone: go wild, there's no issue with
|
|
||||||
breaking APIs at this point in time.
|
|
||||||
|
|
||||||
|
|
||||||
Portability
|
|
||||||
===========
|
|
||||||
|
|
||||||
libfprint is primarily written for Linux. However, I'm interested in
|
|
||||||
supporting efforts to port this to other operating systems too.
|
|
||||||
|
|
||||||
You should ensure code is portable wherever possible. Try and use GLib rather
|
|
||||||
than OS-specific features.
|
|
||||||
|
|
||||||
Endianness must be considered in all code. libfprint must support both big-
|
|
||||||
and little-endian systems.
|
|
||||||
|
|
||||||
|
|
||||||
Coding Style
|
|
||||||
============
|
|
||||||
|
|
||||||
This project follows Linux kernel coding style but with a tab width of 4.
|
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
=============
|
|
||||||
|
|
||||||
All additions of public API functions must be accompanied with doxygen
|
|
||||||
comments.
|
|
||||||
|
|
||||||
All changes which potentially change the behaviour of the public API must
|
|
||||||
be reflected by updating the appropriate doxygen comments.
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
============
|
|
||||||
|
|
||||||
Patches should be sent to the fprint bugzilla:
|
|
||||||
https://bugs.freedesktop.org/enter_bug.cgi?product=libfprint
|
|
||||||
|
|
||||||
Information about libfprint development repositories can be found here:
|
|
||||||
http://www.freedesktop.org/wiki/Software/fprint/libfprint
|
|
||||||
|
|
||||||
If you're looking for ideas for things to work on, look at the TODO file or
|
|
||||||
grep the source code for FIXMEs.
|
|
||||||
|
|
||||||
73
HACKING.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Contributing to libfprint
|
||||||
|
|
||||||
|
## GLib
|
||||||
|
|
||||||
|
Although the library uses GLib internally, libfprint is designed to provide
|
||||||
|
a completely neutral interface to its application users. So, the public
|
||||||
|
APIs should never return GLib data types.
|
||||||
|
|
||||||
|
## License clarification
|
||||||
|
|
||||||
|
Although this library's license could allow for shims that hook up into
|
||||||
|
proprietary blobs to add driver support for some unsupported devices, the
|
||||||
|
intent of the original authors, and of current maintainers of the library,
|
||||||
|
was for this license to allow _integration into_ proprietary stacks, not
|
||||||
|
_integration of_ proprietary code in the library.
|
||||||
|
|
||||||
|
As such, no code to integrate proprietary drivers will be accepted in libfprint
|
||||||
|
upstream. Proprietary drivers would make it impossible to debug problems in
|
||||||
|
libfprint, as we wouldn't know what the proprietary driver does behind the
|
||||||
|
library's back. The closed source nature of drivers is usually used to hide
|
||||||
|
parts of the hardware setup, such as encryption keys, or protocols, in order
|
||||||
|
to protect the hardware's integrity. Unfortunately, this is only [security through
|
||||||
|
obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
|
||||||
|
|
||||||
|
We however encourage potential contributors to take advantage of libfprint's
|
||||||
|
source availability to create such shims to make it easier to reverse-engineer
|
||||||
|
proprietary drivers in order to create new free software drivers, to the extent
|
||||||
|
permitted by local laws.
|
||||||
|
|
||||||
|
## Two-faced-ness
|
||||||
|
|
||||||
|
Like any decent library, this one is designed to provide a stable and
|
||||||
|
documented API to its users: applications. Clear distinction is made between
|
||||||
|
data available internally in the library, and data/functions available to
|
||||||
|
the applications.
|
||||||
|
|
||||||
|
This library is confused a little by the fact that there is another 'interface'
|
||||||
|
at hand: the internal interface provided to drivers. So, we effectively end
|
||||||
|
up with 2 APIs:
|
||||||
|
|
||||||
|
1. The [external-facing API for applications](libfprint/fprint.h)
|
||||||
|
2. The [internal API for fingerprint drivers](libfprint/drivers_api.h)
|
||||||
|
|
||||||
|
Non-static functions which are intended for internal use only are prepended
|
||||||
|
with the "fpi_" prefix.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
All additions of public API functions must be accompanied with gtk-doc
|
||||||
|
comments.
|
||||||
|
|
||||||
|
All changes which potentially change the behaviour of the public API must
|
||||||
|
be reflected by updating the appropriate gtk-doc comments.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Patches should be sent as merge requests to the gitlab page:
|
||||||
|
https://gitlab.freedesktop.org/libfprint/libfprint/merge_requests
|
||||||
|
|
||||||
|
Drivers are not usually written by libfprint developers, but when they
|
||||||
|
are, we require:
|
||||||
|
- 3 stand-alone devices. Not in a laptop or another embedded device, as
|
||||||
|
space is scarce, unless the device has special integration with that
|
||||||
|
hardware.
|
||||||
|
- specifications of the protocol.
|
||||||
|
|
||||||
|
If you are an end-user, you can file a feature request with the "Driver Request"
|
||||||
|
tag on [libfprint's issue page](https://gitlab.freedesktop.org/libfprint/libfprint/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=Driver%20Request),
|
||||||
|
or subscribe to an existing feature request there.
|
||||||
|
|
||||||
|
If you are an enterprising hacker, please file a new merge request with
|
||||||
|
the driver patches integrated.
|
||||||
238
INSTALL
@@ -1,234 +1,6 @@
|
|||||||
Installation Instructions
|
libfprint uses the Meson build system. See
|
||||||
*************************
|
http://mesonbuild.com/Quick-guide.html for details on how to
|
||||||
|
compile libfprint.
|
||||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
|
||||||
2006 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This file is free documentation; the Free Software Foundation gives
|
|
||||||
unlimited permission to copy, distribute and modify it.
|
|
||||||
|
|
||||||
Basic Installation
|
|
||||||
==================
|
|
||||||
|
|
||||||
Briefly, the shell commands `./configure; make; make install' should
|
|
||||||
configure, build, and install this package. The following
|
|
||||||
more-detailed instructions are generic; see the `README' file for
|
|
||||||
instructions specific to this package.
|
|
||||||
|
|
||||||
The `configure' shell script attempts to guess correct values for
|
|
||||||
various system-dependent variables used during compilation. It uses
|
|
||||||
those values to create a `Makefile' in each directory of the package.
|
|
||||||
It may also create one or more `.h' files containing system-dependent
|
|
||||||
definitions. Finally, it creates a shell script `config.status' that
|
|
||||||
you can run in the future to recreate the current configuration, and a
|
|
||||||
file `config.log' containing compiler output (useful mainly for
|
|
||||||
debugging `configure').
|
|
||||||
|
|
||||||
It can also use an optional file (typically called `config.cache'
|
|
||||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
|
||||||
the results of its tests to speed up reconfiguring. Caching is
|
|
||||||
disabled by default to prevent problems with accidental use of stale
|
|
||||||
cache files.
|
|
||||||
|
|
||||||
If you need to do unusual things to compile the package, please try
|
|
||||||
to figure out how `configure' could check whether to do them, and mail
|
|
||||||
diffs or instructions to the address given in the `README' so they can
|
|
||||||
be considered for the next release. If you are using the cache, and at
|
|
||||||
some point `config.cache' contains results you don't want to keep, you
|
|
||||||
may remove or edit it.
|
|
||||||
|
|
||||||
The file `configure.ac' (or `configure.in') is used to create
|
|
||||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
|
||||||
you want to change it or regenerate `configure' using a newer version
|
|
||||||
of `autoconf'.
|
|
||||||
|
|
||||||
The simplest way to compile this package is:
|
|
||||||
|
|
||||||
1. `cd' to the directory containing the package's source code and type
|
|
||||||
`./configure' to configure the package for your system.
|
|
||||||
|
|
||||||
Running `configure' might take a while. While running, it prints
|
|
||||||
some messages telling which features it is checking for.
|
|
||||||
|
|
||||||
2. Type `make' to compile the package.
|
|
||||||
|
|
||||||
3. Optionally, type `make check' to run any self-tests that come with
|
|
||||||
the package.
|
|
||||||
|
|
||||||
4. Type `make install' to install the programs and any data files and
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
5. You can remove the program binaries and object files from the
|
|
||||||
source code directory by typing `make clean'. To also remove the
|
|
||||||
files that `configure' created (so you can compile the package for
|
|
||||||
a different kind of computer), type `make distclean'. There is
|
|
||||||
also a `make maintainer-clean' target, but that is intended mainly
|
|
||||||
for the package's developers. If you use it, you may have to get
|
|
||||||
all sorts of other programs in order to regenerate files that came
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
Compilers and Options
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Some systems require unusual options for compilation or linking that the
|
|
||||||
`configure' script does not know about. Run `./configure --help' for
|
|
||||||
details on some of the pertinent environment variables.
|
|
||||||
|
|
||||||
You can give `configure' initial values for configuration parameters
|
|
||||||
by setting variables in the command line or in the environment. Here
|
|
||||||
is an example:
|
|
||||||
|
|
||||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
|
||||||
|
|
||||||
*Note Defining Variables::, for more details.
|
|
||||||
|
|
||||||
Compiling For Multiple Architectures
|
|
||||||
====================================
|
|
||||||
|
|
||||||
You can compile the package for more than one kind of computer at the
|
|
||||||
same time, by placing the object files for each architecture in their
|
|
||||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
|
||||||
directory where you want the object files and executables to go and run
|
|
||||||
the `configure' script. `configure' automatically checks for the
|
|
||||||
source code in the directory that `configure' is in and in `..'.
|
|
||||||
|
|
||||||
With a non-GNU `make', it is safer to compile the package for one
|
|
||||||
architecture at a time in the source code directory. After you have
|
|
||||||
installed the package for one architecture, use `make distclean' before
|
|
||||||
reconfiguring for another architecture.
|
|
||||||
|
|
||||||
Installation Names
|
|
||||||
==================
|
|
||||||
|
|
||||||
By default, `make install' installs the package's commands under
|
|
||||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
|
||||||
can specify an installation prefix other than `/usr/local' by giving
|
|
||||||
`configure' the option `--prefix=PREFIX'.
|
|
||||||
|
|
||||||
You can specify separate installation prefixes for
|
|
||||||
architecture-specific files and architecture-independent files. If you
|
|
||||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
|
||||||
PREFIX as the prefix for installing programs and libraries.
|
|
||||||
Documentation and other data files still use the regular prefix.
|
|
||||||
|
|
||||||
In addition, if you use an unusual directory layout you can give
|
|
||||||
options like `--bindir=DIR' to specify different values for particular
|
|
||||||
kinds of files. Run `configure --help' for a list of the directories
|
|
||||||
you can set and what kinds of files go in them.
|
|
||||||
|
|
||||||
If the package supports it, you can cause programs to be installed
|
|
||||||
with an extra prefix or suffix on their names by giving `configure' the
|
|
||||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
|
||||||
|
|
||||||
Optional Features
|
|
||||||
=================
|
|
||||||
|
|
||||||
Some packages pay attention to `--enable-FEATURE' options to
|
|
||||||
`configure', where FEATURE indicates an optional part of the package.
|
|
||||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
|
||||||
is something like `gnu-as' or `x' (for the X Window System). The
|
|
||||||
`README' should mention any `--enable-' and `--with-' options that the
|
|
||||||
package recognizes.
|
|
||||||
|
|
||||||
For packages that use the X Window System, `configure' can usually
|
|
||||||
find the X include and library files automatically, but if it doesn't,
|
|
||||||
you can use the `configure' options `--x-includes=DIR' and
|
|
||||||
`--x-libraries=DIR' to specify their locations.
|
|
||||||
|
|
||||||
Specifying the System Type
|
|
||||||
==========================
|
|
||||||
|
|
||||||
There may be some features `configure' cannot figure out automatically,
|
|
||||||
but needs to determine by the type of machine the package will run on.
|
|
||||||
Usually, assuming the package is built to be run on the _same_
|
|
||||||
architectures, `configure' can figure that out, but if it prints a
|
|
||||||
message saying it cannot guess the machine type, give it the
|
|
||||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
|
||||||
type, such as `sun4', or a canonical name which has the form:
|
|
||||||
|
|
||||||
CPU-COMPANY-SYSTEM
|
|
||||||
|
|
||||||
where SYSTEM can have one of these forms:
|
|
||||||
|
|
||||||
OS KERNEL-OS
|
|
||||||
|
|
||||||
See the file `config.sub' for the possible values of each field. If
|
|
||||||
`config.sub' isn't included in this package, then this package doesn't
|
|
||||||
need to know the machine type.
|
|
||||||
|
|
||||||
If you are _building_ compiler tools for cross-compiling, you should
|
|
||||||
use the option `--target=TYPE' to select the type of system they will
|
|
||||||
produce code for.
|
|
||||||
|
|
||||||
If you want to _use_ a cross compiler, that generates code for a
|
|
||||||
platform different from the build platform, you should specify the
|
|
||||||
"host" platform (i.e., that on which the generated programs will
|
|
||||||
eventually be run) with `--host=TYPE'.
|
|
||||||
|
|
||||||
Sharing Defaults
|
|
||||||
================
|
|
||||||
|
|
||||||
If you want to set default values for `configure' scripts to share, you
|
|
||||||
can create a site shell script called `config.site' that gives default
|
|
||||||
values for variables like `CC', `cache_file', and `prefix'.
|
|
||||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
|
||||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
|
||||||
`CONFIG_SITE' environment variable to the location of the site script.
|
|
||||||
A warning: not all `configure' scripts look for a site script.
|
|
||||||
|
|
||||||
Defining Variables
|
|
||||||
==================
|
|
||||||
|
|
||||||
Variables not defined in a site shell script can be set in the
|
|
||||||
environment passed to `configure'. However, some packages may run
|
|
||||||
configure again during the build, and the customized values of these
|
|
||||||
variables may be lost. In order to avoid this problem, you should set
|
|
||||||
them in the `configure' command line, using `VAR=value'. For example:
|
|
||||||
|
|
||||||
./configure CC=/usr/local2/bin/gcc
|
|
||||||
|
|
||||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
|
||||||
overridden in the site shell script).
|
|
||||||
|
|
||||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
|
||||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
|
||||||
|
|
||||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
|
||||||
|
|
||||||
`configure' Invocation
|
|
||||||
======================
|
|
||||||
|
|
||||||
`configure' recognizes the following options to control how it operates.
|
|
||||||
|
|
||||||
`--help'
|
|
||||||
`-h'
|
|
||||||
Print a summary of the options to `configure', and exit.
|
|
||||||
|
|
||||||
`--version'
|
|
||||||
`-V'
|
|
||||||
Print the version of Autoconf used to generate the `configure'
|
|
||||||
script, and exit.
|
|
||||||
|
|
||||||
`--cache-file=FILE'
|
|
||||||
Enable the cache: use and save the results of the tests in FILE,
|
|
||||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
|
||||||
disable caching.
|
|
||||||
|
|
||||||
`--config-cache'
|
|
||||||
`-C'
|
|
||||||
Alias for `--cache-file=config.cache'.
|
|
||||||
|
|
||||||
`--quiet'
|
|
||||||
`--silent'
|
|
||||||
`-q'
|
|
||||||
Do not print messages saying which checks are being made. To
|
|
||||||
suppress all normal output, redirect it to `/dev/null' (any error
|
|
||||||
messages will still be shown).
|
|
||||||
|
|
||||||
`--srcdir=DIR'
|
|
||||||
Look for the package's source code in directory DIR. Usually
|
|
||||||
`configure' can determine that directory automatically.
|
|
||||||
|
|
||||||
`configure' also accepts some other, not widely useful, options. Run
|
|
||||||
`configure --help' for more details.
|
|
||||||
|
|
||||||
|
The "meson configure" command will give you a list of available
|
||||||
|
command-line options.
|
||||||
|
|||||||
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>
|
||||||
25
Makefile.am
@@ -1,25 +0,0 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
|
||||||
EXTRA_DIST = THANKS TODO HACKING libfprint.pc.in
|
|
||||||
DISTCLEANFILES = ChangeLog libfprint.pc
|
|
||||||
|
|
||||||
SUBDIRS = libfprint doc
|
|
||||||
|
|
||||||
if BUILD_EXAMPLES
|
|
||||||
SUBDIRS += examples
|
|
||||||
endif
|
|
||||||
|
|
||||||
DIST_SUBDIRS = libfprint doc examples
|
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --with-drivers=all --enable-examples-build --enable-x11-examples-build --with-udev-rules-dir='$${libdir}/udev/rules.d-distcheck'
|
|
||||||
|
|
||||||
pkgconfigdir=$(libdir)/pkgconfig
|
|
||||||
pkgconfig_DATA=libfprint.pc
|
|
||||||
|
|
||||||
.PHONY: ChangeLog dist-up
|
|
||||||
ChangeLog:
|
|
||||||
git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
|
|
||||||
|
|
||||||
dist-hook: ChangeLog
|
|
||||||
|
|
||||||
dist-up: dist
|
|
||||||
rsync $(distdir).tar.bz2 frs.sourceforge.net:uploads/
|
|
||||||
445
NEWS
@@ -1,6 +1,449 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
2025-02-20: v1.94.9 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* uru4000: Use OpenSSL to perform AES-ECB encryption, as per this libfprint
|
||||||
|
does not support on NSS, but on openssl (>= 3.0).
|
||||||
|
* goodixmoc: New PIDs 0x60C2, 0x689A
|
||||||
|
* synaptics: New PIDs 0x016C, 0x0174, 0x0107, 0x0108, 0x00C2, 0x00F0
|
||||||
|
* fpcmoc: New PID 0xC844
|
||||||
|
* focaltech_moc: New PIDs 0xA99A, 0xA57A, 0xA78A
|
||||||
|
* elanmoc: New PIDs 0x0C98, 0x0C9D, 0x0CA3
|
||||||
|
* elanspi: New PIDs 0x3128, 0x2766
|
||||||
|
* fp-device: Add FP_DEVICE_RETRY_TOO_FAST retry error
|
||||||
|
* data: AppStream meta info listing supported USB devices.
|
||||||
|
* fixed various memory issues in multiple devices
|
||||||
|
|
||||||
|
2024-09-03: v1.94.8 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* build: Support building in non-linux unix environments (tested in FreeBSD)
|
||||||
|
* egismoc: New PIDs 0x0583, 0x0586, 0x0587.
|
||||||
|
* elanmoc: New PID 0x0C9F.
|
||||||
|
* fpcmoc: New PIDs 0x9524, 0x9544.
|
||||||
|
* goodixmoc: New PIDs 0x609A, 0x650A, 0x650C, 0x6512.
|
||||||
|
* realtek: New PID 0x5816.
|
||||||
|
* synaptics: New PIDs 0x00C4, 0x019D, 0x00C6.
|
||||||
|
* fpcmoc: fix incorrect immobile handling during enrollment.
|
||||||
|
* fpcmoc: fixed jumping to wrong state at end of custom enroll.
|
||||||
|
* egismoc: various code cleanups.
|
||||||
|
|
||||||
|
2024-02-20: v1.94.7 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* synaptics: fix enroll identify problem after user reset database.
|
||||||
|
* synaptics: New PIDs 0x0173, 0x0106, 0x0124.
|
||||||
|
* goodixmoc: New PID 0x6582.
|
||||||
|
* build: Do not require bash to build, only posix sh.
|
||||||
|
* fp-image: Simplify minutiae detection tasks.
|
||||||
|
* GLib 2.68 is now required to build libfprint.
|
||||||
|
|
||||||
|
New drivers:
|
||||||
|
* realtek (PID 0x5813).
|
||||||
|
* focaltech_moc (PIDs 0x9E48, 0xD979, 0xA959).
|
||||||
|
* egismoc (PIDs 0x0582, 0x05a1).
|
||||||
|
|
||||||
|
2023-08-17: v1.94.6 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* goodixmoc: New PIDs 0x60A4, 0x60BC, 0x6092, 0x633C and 0x6304.
|
||||||
|
* goodixmoc: Fix missing "enroll create" state.
|
||||||
|
* elanmoc: New PID 0x0C99.
|
||||||
|
* upektc: Improve compatibility with sensors 147e:2016.
|
||||||
|
* aes4000: Actually support 08FF:5501 devices.
|
||||||
|
* virtual-device-listener: Fix failing tests with GLib 2.76
|
||||||
|
* tests: Add installed tests
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* #526 libfprint: fpcmoc: use after free if enrollment or identification is
|
||||||
|
cancelled (Vasily Khoruzhick)
|
||||||
|
|
||||||
|
2022-10-13: v1.94.5 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* New driver: fpcmoc, supporting various FPC MOC Fingerprint Sensors
|
||||||
|
* goodixmoc: New PIDs 0x6014, 0x6094, 0x631C, 0x634C, 0x6384, 0x659A.
|
||||||
|
* goodixmoc: Support resetting device on firmware failure due to corrupted DB.
|
||||||
|
* elanmoc: New PIDs 0x0c88, 0x0c8c, 0x0c8d.
|
||||||
|
* synaptics: New PID 0x0104.
|
||||||
|
* upektc: New PID 0x2017.
|
||||||
|
* Fixed various memory leaks
|
||||||
|
* More tests
|
||||||
|
|
||||||
|
2022-05-24: v1.94.4 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* synaptics: New PIDs 0x0168, 0x015f
|
||||||
|
* elan: New PID 0x0c4b
|
||||||
|
* elanspi: New PID 0x241f
|
||||||
|
* synaptics: Minor fix to interrupt transfer resubmission
|
||||||
|
* Avoid sysfs writes if value is already expected
|
||||||
|
* Improvements to the testing setup
|
||||||
|
* Fixes to the internal critical section API
|
||||||
|
|
||||||
|
2021-11-02: v1.94.3 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Ensure idle mainloop before completing enumeration (fprintd#119)
|
||||||
|
* It is now possible to extend already enrolled prints
|
||||||
|
* elanspi: Fix timeout error with some hardware (#438)
|
||||||
|
* elanspi: Fix cancellation issues
|
||||||
|
* goodixmoc: Return matching device print; fixes duplicate checking (#444)
|
||||||
|
* goodixmoc: Support clearing the storage (usually unused)
|
||||||
|
|
||||||
|
2021-11-02: v1.94.2 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* goodixmoc: Fix protocol error with certain username lengths
|
||||||
|
* elanmoc: New PID 0x0c7d
|
||||||
|
* goodixmoc: New PID 0x63cc
|
||||||
|
|
||||||
|
2021-09-24: v1.94.1 release
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
* Ship a simple script to create new CI tests using tshark
|
||||||
|
* Added CI tests for elan, uru4000, aes2501
|
||||||
|
* goodixmoc: Remove duplicate checking during enroll and let fprintd handle it
|
||||||
|
* uru4000: Fix USB transfer type
|
||||||
|
* synaptics: Support for new PIDs
|
||||||
|
* goodixmoc: Support for new PIDs
|
||||||
|
|
||||||
|
2021-08-20: 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
|
||||||
|
|
||||||
|
This release updates the core of the library to use GLib routines and Gio
|
||||||
|
style APIs. While the API both for library users remain similar in most
|
||||||
|
ways, there are some changes and all users will need to be ported.
|
||||||
|
|
||||||
|
A large motivation for the in-depth changes was the requirement to add
|
||||||
|
new API to support sensors that store the prints on the sensor. This
|
||||||
|
support is already used by the new synaptics driver, which will support
|
||||||
|
the current generation of the Prometheus MIS (match-in-sensor) chipset
|
||||||
|
by Synaptics (USB ID 06cb:00bd).
|
||||||
|
|
||||||
|
The current codebase is considered stable at this point. However, due to
|
||||||
|
the lack of wider testing it is only released as a 1.90.0 release which
|
||||||
|
can be considered a beta-release for 2.0.
|
||||||
|
|
||||||
|
With the rewrite, it is now also possible to support devices that are not
|
||||||
|
connected through USB (e.g. I2C). Another major improvement is that the
|
||||||
|
library has now a test suite, testing both the library core and allowing
|
||||||
|
tests of the drivers using umockdev.
|
||||||
|
|
||||||
|
2019-08-08: v1.0 release
|
||||||
|
* Library:
|
||||||
|
- Add guards to the public API and require GLib 2.50
|
||||||
|
- Deprecate print storage API
|
||||||
|
- Better documentation for fp_discover_devs()
|
||||||
|
- Remove unused internal fpi_timeout_cancel_for_dev()
|
||||||
|
- Remove state from fp_img_driver activate handler
|
||||||
|
- Bug fixes related to restarting a failed verification immediately
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- The Elan driver received a lot of bug fixes including a fix for a
|
||||||
|
hang when verifying prints with fprintd, quirks for some devices,
|
||||||
|
a memory leak fix and support for 04f3:0c42
|
||||||
|
- Fix a probable crash in all the AES drivers
|
||||||
|
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
|
||||||
|
- Prevent hang during enroll process in etes603 driver
|
||||||
|
- Fix possible integer overflow in uru4000
|
||||||
|
- Work-around SELinux AVC warnings when uru4000 driver starts
|
||||||
|
- Remove long-unmaintained and broken fdu2000 driver
|
||||||
|
|
||||||
|
* Tools/Examples:
|
||||||
|
- Fix examples not working due to an overly strict check
|
||||||
|
- Fix crash in GTK demo when there's no supported devices
|
||||||
|
- Disable GTK demo until we have a USB Flatpak portal
|
||||||
|
- Remove sleep() in enroll example which caused a crash in some drivers
|
||||||
|
- Add a simple storage implementation example
|
||||||
|
|
||||||
|
2018-12-14: v0.99.0 release
|
||||||
|
* Library:
|
||||||
|
- All the internal API for device driver writers is now covered by the
|
||||||
|
documentation and has been enhanced to make it easier to write drivers
|
||||||
|
- Update internal NBIS fingerprint data processing library to one that's
|
||||||
|
nearly 10 years newer
|
||||||
|
- Re-add accessor for minutia coordinates which was used in the very
|
||||||
|
old fprint_demo program, but also by our new GTK+ test program (see below)
|
||||||
|
- Fix a crash when too many minutiae were detected in a capture
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- Support more devices in the Elan driver, stability improvements
|
||||||
|
|
||||||
|
* Tools:
|
||||||
|
- Add a test GTK+ application that will eventually be used for testing
|
||||||
|
drivers without modifying the OS installed version. Note that this
|
||||||
|
application currently requires manually changing permissions of USB
|
||||||
|
devices, this will be fixed when the infrastructure exists to access
|
||||||
|
those devices without additional permissions, as a normal user.
|
||||||
|
|
||||||
|
2018-07-15: v0.8.2 release
|
||||||
|
* Drivers:
|
||||||
|
- Add USB ID for TNP Nano USB Fingerprint Reader
|
||||||
|
- Fix UPEKTS enrollment never finishing on some devices
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Fix fp_get_pollfds() retval type, a small ABI change
|
||||||
|
- Downgrade fatal errors to run-time warnings, as a number of drivers
|
||||||
|
used to throw silent errors and we made them fatal. Those will now
|
||||||
|
be visible warnings, hopefully helping with fixing them.
|
||||||
|
|
||||||
|
2018-06-12: v0.8.1 release
|
||||||
|
- Brown paperbag release to install the udev rules file in the correct
|
||||||
|
directory if the udev pkg-config file doesn't have a trailing slash
|
||||||
|
|
||||||
|
2018-06-12: v0.8.0 release
|
||||||
|
- Port to meson as the build system
|
||||||
|
- Port documentation to gtk-doc
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- Add Elan driver
|
||||||
|
- Increase threshold to detect encryption on URU4000 devices
|
||||||
|
- Remove already replaced UPEKE2 driver
|
||||||
|
- Fix possible crash caused by vfs5011 when no lines were captured
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Fix a number of memory and file descriptor leaks and warnings
|
||||||
|
- Make NSS (and URU4000) driver optional
|
||||||
|
- Fix assembling of frames for non-reverse and non reverse stripes
|
||||||
|
- Split internal private header to clarify drivers API
|
||||||
|
- Simplify logging system, now all the builds can be used to output
|
||||||
|
debug information
|
||||||
|
- Mark fp_dscv_print functions as deprecated
|
||||||
|
|
||||||
|
* Udev rules:
|
||||||
|
- Add some unsupported devices to the allowlist
|
||||||
|
|
||||||
|
2017-05-14: v0.7.0 release
|
||||||
|
* Drivers:
|
||||||
|
- Add VFS0050 driver
|
||||||
|
- Fix possible crash in AES3500 and AES4000
|
||||||
|
- Fix broken enrollment in VFS101
|
||||||
|
- Better verification with small sensor scanners
|
||||||
|
- Plenty of fixes in VFS5011
|
||||||
|
- Fix memory corruption in AES1610
|
||||||
|
- Improve calibration settings for AES1610
|
||||||
|
- Improve image assembling in upeksonly driver
|
||||||
|
- Autodetect whether image is encrypted in uru4k
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- NBIS: Remove false minutia at the edge of partial image
|
||||||
|
- Introduce routines to assemble image from lines (used in VFS5011 and upeksonly)
|
||||||
|
- Fix a bug that can cause driver state machine to enter into endless loop.
|
||||||
|
|
||||||
|
* Udev rules:
|
||||||
|
- Add driver name to the USB properties
|
||||||
|
|
||||||
|
* Plenty of build fixes
|
||||||
|
|
||||||
|
2015-02-03: v0.6.0 release
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- Reduce duplication between AES3500 and AES4000 drivers and
|
||||||
|
add support for AES3500 device
|
||||||
|
- Add support for UPEK 147e:2020 and Upek Eikon 2 devices
|
||||||
|
- Add EgisTec ES603 driver
|
||||||
|
- Add VFS5011 driver
|
||||||
|
- Always perform 5 scans for image enrollment
|
||||||
|
- Better verification with AES1660 driver
|
||||||
|
- Better verification for a number of AES drivers
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Always use Pixman for image manipulation, gdk-pixbuf and ImageMagick
|
||||||
|
are not supported any more.
|
||||||
|
|
||||||
|
* Udev rules:
|
||||||
|
- Fix warning when USB hub or system does not support power management
|
||||||
|
|
||||||
2013-08-11: v0.5.1 release
|
2013-08-11: v0.5.1 release
|
||||||
|
|
||||||
* Drivers
|
* Drivers
|
||||||
@@ -8,7 +451,7 @@ changes, see ChangeLog.
|
|||||||
- Fix possible race condition, and cancellation in uru4000 driver
|
- Fix possible race condition, and cancellation in uru4000 driver
|
||||||
|
|
||||||
* Udev rules:
|
* Udev rules:
|
||||||
- Add Microsoft keyboard to the suspend blacklist
|
- Add Microsoft keyboard to the suspend denylist
|
||||||
|
|
||||||
* Plenty of build fixes
|
* Plenty of build fixes
|
||||||
|
|
||||||
|
|||||||
41
README
@@ -1,41 +0,0 @@
|
|||||||
libfprint
|
|
||||||
=========
|
|
||||||
|
|
||||||
libfprint is part of the fprint project:
|
|
||||||
http://www.reactivated.net/fprint
|
|
||||||
|
|
||||||
libfprint was originally developed as part of an academic project at the
|
|
||||||
University of Manchester with the aim of hiding differences between different
|
|
||||||
consumer fingerprint scanners and providing a single uniform API to application
|
|
||||||
developers. The ultimate goal of the fprint project is to make fingerprint
|
|
||||||
scanners widely and easily usable under common Linux environments.
|
|
||||||
|
|
||||||
The academic university project runs off a codebase maintained separately
|
|
||||||
from this one, although I try to keep them as similar as possible (I'm not
|
|
||||||
hiding anything in the academic branch, it's just the open source release
|
|
||||||
contains some commits excluded from the academic project).
|
|
||||||
|
|
||||||
THE UNIVERSITY OF MANCHESTER DOES NOT ENDORSE THIS THIS SOFTWARE RELEASE AND
|
|
||||||
IS IN NO WAY RESPONSIBLE FOR THE CODE CONTAINED WITHIN, OR ANY DAMAGES CAUSED
|
|
||||||
BY USING OR DISTRIBUTING THE SOFTWARE. Development does not happen on
|
|
||||||
university computers and the project is not hosted at the university either.
|
|
||||||
|
|
||||||
For more information on libfprint, supported devices, API documentation, etc.,
|
|
||||||
see the homepage:
|
|
||||||
http://www.reactivated.net/fprint/Libfprint
|
|
||||||
|
|
||||||
libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file
|
|
||||||
for the license text.
|
|
||||||
|
|
||||||
Section 6 of the license states that for compiled works that use this
|
|
||||||
library, such works must include libfprint copyright notices alongside the
|
|
||||||
copyright notices for the other parts of the work. We have attempted to
|
|
||||||
make this process slightly easier for you by grouping these all in one place:
|
|
||||||
the AUTHORS file.
|
|
||||||
|
|
||||||
libfprint includes code from NIST's NBIS software distribution:
|
|
||||||
http://fingerprint.nist.gov/NBIS/index.html
|
|
||||||
We include bozorth3 from the US export controlled distribution. We have
|
|
||||||
determined that it is fine to ship bozorth3 in an open source project,
|
|
||||||
see http://reactivated.net/fprint/wiki/US_export_control
|
|
||||||
|
|
||||||
95
README.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
# LibFPrint
|
||||||
|
|
||||||
|
*LibFPrint is part of the **[FPrint][Website]** project.*
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
[![Button Website]][Website]
|
||||||
|
[![Button Documentation]][Documentation]
|
||||||
|
|
||||||
|
[![Button Supported]][Supported]
|
||||||
|
[![Button Unsupported]][Unsupported]
|
||||||
|
|
||||||
|
[![Button Contribute]][Contribute]
|
||||||
|
[![Button Contributors]][Contributors]
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## History
|
||||||
|
|
||||||
|
**LibFPrint** was originally developed as part of an
|
||||||
|
academic project at the **[University Of Manchester]**.
|
||||||
|
|
||||||
|
It aimed to hide the differences between consumer
|
||||||
|
fingerprint scanners and provide a single uniform
|
||||||
|
API to application developers.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
The ultimate goal of the **FPrint** project is to make
|
||||||
|
fingerprint scanners widely and easily usable under
|
||||||
|
common Linux environments.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
`Section 6` of the license states that for compiled works that use
|
||||||
|
this library, such works must include **LibFPrint** copyright notices
|
||||||
|
alongside the copyright notices for the other parts of the work.
|
||||||
|
|
||||||
|
**LibFPrint** includes code from **NIST's** **[NBIS]** software distribution.
|
||||||
|
|
||||||
|
We include **Bozorth3** from the **[US Export Controlled]**
|
||||||
|
distribution, which we have determined to be fine
|
||||||
|
being shipped in an open source project.
|
||||||
|
|
||||||
|
## Get in *touch*
|
||||||
|
|
||||||
|
- [IRC] - `#fprint` @ `irc.oftc.net`
|
||||||
|
- [Matrix] - `#fprint:matrix.org` bridged to the IRC channel
|
||||||
|
- [MailingList] - low traffic, not much used these days
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div align="right">
|
||||||
|
|
||||||
|
[![Badge License]][License]
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!----------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
[Documentation]: https://fprint.freedesktop.org/libfprint-dev/
|
||||||
|
[Contributors]: https://gitlab.freedesktop.org/libfprint/libfprint/-/graphs/master
|
||||||
|
[Unsupported]: https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices
|
||||||
|
[Supported]: https://fprint.freedesktop.org/supported-devices.html
|
||||||
|
[Website]: https://fprint.freedesktop.org/
|
||||||
|
[MailingList]: https://lists.freedesktop.org/mailman/listinfo/fprint
|
||||||
|
[IRC]: ircs://irc.oftc.net:6697/#fprint
|
||||||
|
[Matrix]: https://matrix.to/#/#fprint:matrix.org
|
||||||
|
|
||||||
|
[Contribute]: ./HACKING.md
|
||||||
|
[License]: ./COPYING
|
||||||
|
|
||||||
|
[University Of Manchester]: https://www.manchester.ac.uk/
|
||||||
|
[US Export Controlled]: https://fprint.freedesktop.org/us-export-control.html
|
||||||
|
[NBIS]: http://fingerprint.nist.gov/NBIS/index.html
|
||||||
|
|
||||||
|
|
||||||
|
<!---------------------------------[ Badges ]---------------------------------->
|
||||||
|
|
||||||
|
[Badge License]: https://img.shields.io/badge/License-LGPL2.1-015d93.svg?style=for-the-badge&labelColor=blue
|
||||||
|
|
||||||
|
|
||||||
|
<!---------------------------------[ Buttons ]--------------------------------->
|
||||||
|
|
||||||
|
[Button Documentation]: https://img.shields.io/badge/Documentation-04ACE6?style=for-the-badge&logoColor=white&logo=BookStack
|
||||||
|
[Button Contributors]: https://img.shields.io/badge/Contributors-FF4F8B?style=for-the-badge&logoColor=white&logo=ActiGraph
|
||||||
|
[Button Unsupported]: https://img.shields.io/badge/Unsupported_Devices-EF2D5E?style=for-the-badge&logoColor=white&logo=AdBlock
|
||||||
|
[Button Contribute]: https://img.shields.io/badge/Contribute-66459B?style=for-the-badge&logoColor=white&logo=Git
|
||||||
|
[Button Supported]: https://img.shields.io/badge/Supported_Devices-428813?style=for-the-badge&logoColor=white&logo=AdGuard
|
||||||
|
[Button Website]: https://img.shields.io/badge/Homepage-3B80AE?style=for-the-badge&logoColor=white&logo=freedesktopDotOrg
|
||||||
30
TODO
@@ -1,30 +0,0 @@
|
|||||||
LIBRARY
|
|
||||||
=======
|
|
||||||
test suite against NFIQ compliance set
|
|
||||||
make library optionally asynchronous and maybe thread-safe
|
|
||||||
nbis cleanups
|
|
||||||
API function to determine if img device supports uncond. capture
|
|
||||||
race-free way of saying "save this print but don't overwrite"
|
|
||||||
|
|
||||||
NEW DRIVERS
|
|
||||||
===========
|
|
||||||
Sunplus 895 driver
|
|
||||||
AES3400/3500 driver
|
|
||||||
ID Mouse driver
|
|
||||||
Support for 2nd generation MS devices
|
|
||||||
Support for 2nd generation UPEK devices
|
|
||||||
|
|
||||||
IMAGING
|
|
||||||
=======
|
|
||||||
ignore first frame or two with aes2501
|
|
||||||
aes2501: increase threshold "sum" for end-of-image detection
|
|
||||||
aes2501 gain calibration
|
|
||||||
aes4000 gain calibration
|
|
||||||
aes4000 resampling
|
|
||||||
PPMM parameter to get_minutiae seems to have no effect
|
|
||||||
nbis minutiae should be stored in endian-independent format
|
|
||||||
|
|
||||||
PORTABILITY
|
|
||||||
===========
|
|
||||||
OpenBSD can't do -Wshadow or visibility
|
|
||||||
OpenBSD: add compat codes for ENOTSUP ENODATA and EPROTO
|
|
||||||
10
autogen.sh
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
libtoolize --copy --force || exit 1
|
|
||||||
aclocal || exit 1
|
|
||||||
autoheader || exit 1
|
|
||||||
autoconf || exit 1
|
|
||||||
automake -a -c || exit 1
|
|
||||||
if test -z "$NOCONFIGURE"; then
|
|
||||||
exec ./configure --enable-maintainer-mode --enable-examples-build \
|
|
||||||
--enable-x11-examples-build --enable-debug-log $*
|
|
||||||
fi
|
|
||||||
3
code-of-conduct.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
This project and its community follow the [Freedesktop.org code of conduct]
|
||||||
|
|
||||||
|
[Freedesktop.org code of conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/
|
||||||
372
configure.ac
@@ -1,372 +0,0 @@
|
|||||||
AC_INIT([libfprint], [0.5.1])
|
|
||||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz check-news])
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
AC_CONFIG_SRCDIR([libfprint/core.c])
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
|
||||||
|
|
||||||
# Enable silent build when available (Automake 1.11)
|
|
||||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
|
||||||
|
|
||||||
AC_PREREQ([2.50])
|
|
||||||
AC_PROG_CC
|
|
||||||
AC_PROG_LIBTOOL
|
|
||||||
AC_C_INLINE
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
AC_PROG_CXX
|
|
||||||
AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
|
|
||||||
|
|
||||||
# Library versioning
|
|
||||||
lt_major="0"
|
|
||||||
lt_revision="0"
|
|
||||||
lt_age="0"
|
|
||||||
AC_SUBST(lt_major)
|
|
||||||
AC_SUBST(lt_revision)
|
|
||||||
AC_SUBST(lt_age)
|
|
||||||
|
|
||||||
all_drivers="upeke2 upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes4000 vfs101 vfs301"
|
|
||||||
|
|
||||||
require_imaging='no'
|
|
||||||
require_aeslib='no'
|
|
||||||
require_aesX660='no'
|
|
||||||
enable_upeke2='no'
|
|
||||||
enable_upekts='no'
|
|
||||||
enable_upektc='no'
|
|
||||||
enable_upeksonly='no'
|
|
||||||
enable_vcom5s='no'
|
|
||||||
enable_uru4000='no'
|
|
||||||
enable_fdu2000='no'
|
|
||||||
enable_aes1610='no'
|
|
||||||
enable_aes1660='no'
|
|
||||||
enable_aes2501='no'
|
|
||||||
enable_aes2550='no'
|
|
||||||
enable_aes2660='no'
|
|
||||||
enable_aes4000='no'
|
|
||||||
enable_vfs101='no'
|
|
||||||
enable_vfs301='no'
|
|
||||||
|
|
||||||
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
|
|
||||||
[List of drivers to enable])],
|
|
||||||
[drivers="$withval"],
|
|
||||||
[drivers="$all_drivers"])
|
|
||||||
|
|
||||||
if test "x$drivers" = "xall" ; then
|
|
||||||
drivers=$all_drivers
|
|
||||||
fi
|
|
||||||
|
|
||||||
for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
|
|
||||||
case ${driver} in
|
|
||||||
upekts)
|
|
||||||
AC_DEFINE([ENABLE_UPEKTS], [], [Build UPEK TouchStrip driver])
|
|
||||||
enable_upekts="yes"
|
|
||||||
;;
|
|
||||||
upeke2)
|
|
||||||
AC_DEFINE([ENABLE_UPEKE2], [], [Build UPEK Eikon 2])
|
|
||||||
enable_upeke2="yes"
|
|
||||||
;;
|
|
||||||
upektc)
|
|
||||||
AC_DEFINE([ENABLE_UPEKTC], [], [Build UPEK TouchChip driver])
|
|
||||||
enable_upektc="yes"
|
|
||||||
;;
|
|
||||||
upeksonly)
|
|
||||||
AC_DEFINE([ENABLE_UPEKSONLY], [], [Build UPEK TouchStrip sensor-only driver])
|
|
||||||
enable_upeksonly="yes"
|
|
||||||
;;
|
|
||||||
uru4000)
|
|
||||||
AC_DEFINE([ENABLE_URU4000], [], [Build Digital Persona U.are.U 4000 driver])
|
|
||||||
enable_uru4000="yes"
|
|
||||||
;;
|
|
||||||
fdu2000)
|
|
||||||
AC_DEFINE([ENABLE_FDU2000], [], [Build Secugen FDU 2000 driver])
|
|
||||||
enable_fdu2000="no"
|
|
||||||
# Driver not ported
|
|
||||||
;;
|
|
||||||
vcom5s)
|
|
||||||
AC_DEFINE([ENABLE_VCOM5S], [], [Build Veridicom 5thSense driver])
|
|
||||||
enable_vcom5s="yes"
|
|
||||||
;;
|
|
||||||
aes2501)
|
|
||||||
AC_DEFINE([ENABLE_AES2501], [], [Build AuthenTec AES2501 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes2501="yes"
|
|
||||||
;;
|
|
||||||
aes2550)
|
|
||||||
AC_DEFINE([ENABLE_AES2550], [], [Build AuthenTec AES2550/AES2810 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes2550="yes"
|
|
||||||
;;
|
|
||||||
aes1610)
|
|
||||||
AC_DEFINE([ENABLE_AES1610], [], [Build AuthenTec AES1610 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes1610="yes"
|
|
||||||
;;
|
|
||||||
aes1660)
|
|
||||||
AC_DEFINE([ENABLE_AES1660], [], [Build AuthenTec AES1660 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_aesX660="yes"
|
|
||||||
enable_aes1660="yes"
|
|
||||||
;;
|
|
||||||
aes2660)
|
|
||||||
AC_DEFINE([ENABLE_AES2660], [], [Build AuthenTec AES1660 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_aesX660="yes"
|
|
||||||
enable_aes2660="yes"
|
|
||||||
;;
|
|
||||||
aes4000)
|
|
||||||
AC_DEFINE([ENABLE_AES4000], [], [Build AuthenTec AES4000 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_imaging="yes"
|
|
||||||
enable_aes4000="yes"
|
|
||||||
;;
|
|
||||||
vfs101)
|
|
||||||
AC_DEFINE([ENABLE_VFS101], [], [Build Validity VFS101 driver])
|
|
||||||
enable_vfs101="yes"
|
|
||||||
;;
|
|
||||||
vfs301)
|
|
||||||
AC_DEFINE([ENABLE_VFS301], [], [Build Validity VFS301/VFS300 driver])
|
|
||||||
enable_vfs301="yes"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKTS], [test "$enable_upekts" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKE2], [test "$enable_upeke2" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKTC], [test "$enable_upektc" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKSONLY], [test "$enable_upeksonly" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VCOM5S], [test "$enable_vcom5s" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_URU4000], [test "$enable_uru4000" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_FDU2000], [test "$enable_fdu2000" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES1610], [test "$enable_aes1610" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES1660], [test "$enable_aes1660" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2660], [test "$enable_aes2660" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"])
|
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1])
|
|
||||||
AC_SUBST(LIBUSB_CFLAGS)
|
|
||||||
AC_SUBST(LIBUSB_LIBS)
|
|
||||||
|
|
||||||
# check for OpenSSL's libcrypto
|
|
||||||
PKG_CHECK_MODULES(CRYPTO, nss)
|
|
||||||
AC_SUBST(CRYPTO_CFLAGS)
|
|
||||||
AC_SUBST(CRYPTO_LIBS)
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28])
|
|
||||||
AC_SUBST(GLIB_CFLAGS)
|
|
||||||
AC_SUBST(GLIB_LIBS)
|
|
||||||
|
|
||||||
imagemagick_found=no
|
|
||||||
gdkpixbuf_found=no
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(udev-rules,
|
|
||||||
AC_HELP_STRING([--enable-udev-rules],[Update the udev rules]),
|
|
||||||
[case "${enableval}" in
|
|
||||||
yes) ENABLE_UDEV_RULES=yes ;;
|
|
||||||
no) ENABLE_UDEV_RULES=no ;;
|
|
||||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-udev-rules) ;;
|
|
||||||
esac],
|
|
||||||
[ENABLE_UDEV_RULES=yes]) dnl Default value
|
|
||||||
AM_CONDITIONAL(ENABLE_UDEV_RULES, test x$ENABLE_UDEV_RULES = "xyes")
|
|
||||||
|
|
||||||
if test $ENABLE_UDEV_RULES = no && test -d .git/ ; then
|
|
||||||
AC_MSG_ERROR(--disable-udev-rules can only be used when building from tarballs)
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_ARG_WITH(udev-rules-dir,
|
|
||||||
AS_HELP_STRING([--with-udev-rules-dir=DIR],[Installation path for udev rules @<:@auto@:>@]),
|
|
||||||
[ac_with_udev_rules_dir=$withval],
|
|
||||||
[ac_with_udev_rules_dir=""])
|
|
||||||
|
|
||||||
if test "${ac_with_udev_rules_dir}" = ""; then
|
|
||||||
ac_with_udev_rules_dir=`$PKG_CONFIG --variable=udevdir udev`/rules.d
|
|
||||||
fi
|
|
||||||
AC_MSG_NOTICE([installing udev rules in ${ac_with_udev_rules_dir}])
|
|
||||||
AC_SUBST([udev_rulesdir],[${ac_with_udev_rules_dir}])
|
|
||||||
|
|
||||||
if test "$require_imaging" = "yes"; then
|
|
||||||
PKG_CHECK_MODULES(IMAGING, gthread-2.0 gdk-pixbuf-2.0, [gdkpixbuf_found=yes], [gdkpixbuf_found=no])
|
|
||||||
if test "$gdkpixbuf_found" != "yes"; then
|
|
||||||
PKG_CHECK_MODULES(IMAGING, ImageMagick, [imagemagick_found=yes], [imagemagick_found=no])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$require_imaging" = "yes"; then
|
|
||||||
if test "$gdkpixbuf_found" != "yes" && test "$imagemagick_found" != "yes"; then
|
|
||||||
AC_MSG_ERROR([gdk-pixbuf or ImageMagick is required for imaging support])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL([REQUIRE_GDKPIXBUF], [test "$gdkpixbuf_found" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_IMAGEMAGICK], [test "$imagemagick_found" = "yes"])
|
|
||||||
AC_SUBST(IMAGING_CFLAGS)
|
|
||||||
AC_SUBST(IMAGING_LIBS)
|
|
||||||
|
|
||||||
# Examples build
|
|
||||||
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
|
|
||||||
[build example applications (default n)])],
|
|
||||||
[build_examples=$enableval],
|
|
||||||
[build_examples='no'])
|
|
||||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
|
|
||||||
|
|
||||||
# Examples build
|
|
||||||
AC_ARG_ENABLE([x11-examples-build], [AS_HELP_STRING([--enable-x11-examples-build],
|
|
||||||
[build X11 example applications (default n)])],
|
|
||||||
[build_x11_examples=$enableval],
|
|
||||||
[build_x11_examples='no'])
|
|
||||||
AM_CONDITIONAL([BUILD_X11_EXAMPLES], [test "x$build_x11_examples" != "xno"])
|
|
||||||
|
|
||||||
|
|
||||||
if test "x$build_x11_examples" != "xno"; then
|
|
||||||
# check for Xv extensions
|
|
||||||
# imported from Coriander
|
|
||||||
AC_DEFUN([AC_CHECK_XV],[
|
|
||||||
AC_SUBST(XV_CFLAGS)
|
|
||||||
AC_SUBST(XV_LIBS)
|
|
||||||
AC_MSG_CHECKING(for Xv extensions)
|
|
||||||
AC_TRY_COMPILE([
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/extensions/Xvlib.h>],[
|
|
||||||
int main(void) { (void) XvGetPortAttribute(0, 0, 0, 0); return 0; }
|
|
||||||
],xv=yes,xv=no);
|
|
||||||
AC_MSG_RESULT($xv)
|
|
||||||
if test x$xv = xyes; then
|
|
||||||
XV_LIBS="-lXv -lXext"
|
|
||||||
XV_CFLAGS=""
|
|
||||||
AC_DEFINE(HAVE_XV,1,[defined if XV video overlay is available])
|
|
||||||
else
|
|
||||||
AC_MSG_ERROR([XV is required for X11 examples])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
AC_CHECK_XV
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Message logging
|
|
||||||
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
|
|
||||||
[log_enabled=$enableval],
|
|
||||||
[log_enabled='yes'])
|
|
||||||
if test "x$log_enabled" != "xno"; then
|
|
||||||
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
|
|
||||||
[enable debug logging (default n)])],
|
|
||||||
[debug_log_enabled=$enableval],
|
|
||||||
[debug_log_enabled='no'])
|
|
||||||
if test "x$debug_log_enabled" != "xno"; then
|
|
||||||
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging])
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore gnu89 inline semantics on gcc 4.3 and newer
|
|
||||||
saved_cflags="$CFLAGS"
|
|
||||||
CFLAGS="$CFLAGS -fgnu89-inline"
|
|
||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[]])], inline_cflags="-fgnu89-inline", inline_cflags="")
|
|
||||||
CFLAGS="$saved_cflags"
|
|
||||||
|
|
||||||
AC_DEFINE([API_EXPORTED], [__attribute__((visibility("default")))], [Default visibility])
|
|
||||||
AM_CFLAGS="-std=gnu99 $inline_cflags -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration -Wno-pointer-sign -Wshadow"
|
|
||||||
AC_SUBST(AM_CFLAGS)
|
|
||||||
|
|
||||||
if test "$require_imaging" = "yes"; then
|
|
||||||
if test x$gdkpixbuf_found != no; then
|
|
||||||
AC_MSG_NOTICE([** Using gdk-pixbuf for imaging])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([** Using ImageMagick for imaging])
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ Imaging support disabled])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test x$enable_upekts != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upekts driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upekts driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upeke2 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upeke2 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upeke2 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upektc != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upektc driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upektc driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upeksonly != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upeksonly driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upeksonly driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vcom5s != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vcom5s driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vcom5s driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_uru4000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** uru4000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ uru4000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_fdu2000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** fdu2000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ fdu2000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes1610 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes1610 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes1610 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes1660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes1660 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes1660 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2501 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2501 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2501 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2550 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2550/aes2810 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2550/aes2810 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2660 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2660 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes4000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes4000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes4000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vfs101 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vfs101 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vfs101 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vfs301 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vfs301 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vfs301 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$require_aeslib != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aeslib helper functions enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aeslib helper functions disabled])
|
|
||||||
fi
|
|
||||||
if test x$require_aesX660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aesX660 common routines enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aesX660 common routines disabled])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile])
|
|
||||||
AC_OUTPUT
|
|
||||||
|
|
||||||
477
data/autosuspend.hwdb
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
# 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:v08FFp5501*
|
||||||
|
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 egismoc
|
||||||
|
usb:v1C7Ap0582*
|
||||||
|
usb:v1C7Ap0583*
|
||||||
|
usb:v1C7Ap0586*
|
||||||
|
usb:v1C7Ap0587*
|
||||||
|
usb:v1C7Ap05A1*
|
||||||
|
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:v04F3p0C4B*
|
||||||
|
usb:v04F3p0C4D*
|
||||||
|
usb:v04F3p0C4F*
|
||||||
|
usb:v04F3p0C63*
|
||||||
|
usb:v04F3p0C6E*
|
||||||
|
usb:v04F3p0C58*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver elanmoc
|
||||||
|
usb:v04F3p0C7D*
|
||||||
|
usb:v04F3p0C7E*
|
||||||
|
usb:v04F3p0C82*
|
||||||
|
usb:v04F3p0C88*
|
||||||
|
usb:v04F3p0C8C*
|
||||||
|
usb:v04F3p0C8D*
|
||||||
|
usb:v04F3p0C98*
|
||||||
|
usb:v04F3p0C99*
|
||||||
|
usb:v04F3p0C9D*
|
||||||
|
usb:v04F3p0C9F*
|
||||||
|
usb:v04F3p0CA3*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver etes603
|
||||||
|
usb:v1C7Ap0603*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver focaltech_moc
|
||||||
|
usb:v2808p9E48*
|
||||||
|
usb:v2808pD979*
|
||||||
|
usb:v2808pA959*
|
||||||
|
usb:v2808pA99A*
|
||||||
|
usb:v2808pA57A*
|
||||||
|
usb:v2808pA78A*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver fpcmoc
|
||||||
|
usb:v10A5pFFE0*
|
||||||
|
usb:v10A5pA305*
|
||||||
|
usb:v10A5pA306*
|
||||||
|
usb:v10A5pDA04*
|
||||||
|
usb:v10A5pD805*
|
||||||
|
usb:v10A5pD205*
|
||||||
|
usb:v10A5p9524*
|
||||||
|
usb:v10A5p9544*
|
||||||
|
usb:v10A5pC844*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver goodixmoc
|
||||||
|
usb:v27C6p5840*
|
||||||
|
usb:v27C6p6014*
|
||||||
|
usb:v27C6p6092*
|
||||||
|
usb:v27C6p6094*
|
||||||
|
usb:v27C6p609A*
|
||||||
|
usb:v27C6p609C*
|
||||||
|
usb:v27C6p60A2*
|
||||||
|
usb:v27C6p60A4*
|
||||||
|
usb:v27C6p60BC*
|
||||||
|
usb:v27C6p60C2*
|
||||||
|
usb:v27C6p6304*
|
||||||
|
usb:v27C6p631C*
|
||||||
|
usb:v27C6p633C*
|
||||||
|
usb:v27C6p634C*
|
||||||
|
usb:v27C6p6384*
|
||||||
|
usb:v27C6p639C*
|
||||||
|
usb:v27C6p63AC*
|
||||||
|
usb:v27C6p63BC*
|
||||||
|
usb:v27C6p63CC*
|
||||||
|
usb:v27C6p6496*
|
||||||
|
usb:v27C6p650A*
|
||||||
|
usb:v27C6p650C*
|
||||||
|
usb:v27C6p6582*
|
||||||
|
usb:v27C6p6584*
|
||||||
|
usb:v27C6p658C*
|
||||||
|
usb:v27C6p6592*
|
||||||
|
usb:v27C6p6594*
|
||||||
|
usb:v27C6p659A*
|
||||||
|
usb:v27C6p659C*
|
||||||
|
usb:v27C6p6A94*
|
||||||
|
usb:v27C6p6512*
|
||||||
|
usb:v27C6p689A*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver nb1010
|
||||||
|
usb:v298Dp1010*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver realtek
|
||||||
|
usb:v0BDAp5813*
|
||||||
|
usb:v0BDAp5816*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
|
|
||||||
|
# Supported by libfprint driver synaptics
|
||||||
|
usb:v06CBp00BD*
|
||||||
|
usb:v06CBp00C2*
|
||||||
|
usb:v06CBp00C4*
|
||||||
|
usb:v06CBp00C6*
|
||||||
|
usb:v06CBp00DF*
|
||||||
|
usb:v06CBp00F0*
|
||||||
|
usb:v06CBp00F9*
|
||||||
|
usb:v06CBp00FC*
|
||||||
|
usb:v06CBp0100*
|
||||||
|
usb:v06CBp0103*
|
||||||
|
usb:v06CBp0104*
|
||||||
|
usb:v06CBp0106*
|
||||||
|
usb:v06CBp0107*
|
||||||
|
usb:v06CBp0108*
|
||||||
|
usb:v06CBp0109*
|
||||||
|
usb:v06CBp010A*
|
||||||
|
usb:v06CBp0123*
|
||||||
|
usb:v06CBp0124*
|
||||||
|
usb:v06CBp0126*
|
||||||
|
usb:v06CBp0129*
|
||||||
|
usb:v06CBp015F*
|
||||||
|
usb:v06CBp0168*
|
||||||
|
usb:v06CBp016C*
|
||||||
|
usb:v06CBp0173*
|
||||||
|
usb:v06CBp0174*
|
||||||
|
usb:v06CBp019D*
|
||||||
|
usb:v06CBp019F*
|
||||||
|
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:v0483p2017*
|
||||||
|
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:v0A5Cp5802*
|
||||||
|
usb:v047Dp00F2*
|
||||||
|
usb:v047Dp8054*
|
||||||
|
usb:v047Dp8055*
|
||||||
|
usb:v04E8p730B*
|
||||||
|
usb:v04F3p036B*
|
||||||
|
usb:v04F3p0C00*
|
||||||
|
usb:v04F3p0C4C*
|
||||||
|
usb:v04F3p0C57*
|
||||||
|
usb:v04F3p0C5E*
|
||||||
|
usb:v04F3p0C5A*
|
||||||
|
usb:v04F3p0C60*
|
||||||
|
usb:v04F3p0C6C*
|
||||||
|
usb:v04F3p0C70*
|
||||||
|
usb:v04F3p0C72*
|
||||||
|
usb:v04F3p0C77*
|
||||||
|
usb:v04F3p0C7C*
|
||||||
|
usb:v04F3p0C7F*
|
||||||
|
usb:v04F3p0C80*
|
||||||
|
usb:v04F3p0C85*
|
||||||
|
usb:v04F3p0C90*
|
||||||
|
usb:v04F3p2706*
|
||||||
|
usb:v04F3p3032*
|
||||||
|
usb:v04F3p3057*
|
||||||
|
usb:v04F3p3104*
|
||||||
|
usb:v04F3p310D*
|
||||||
|
usb:v04F3p3128*
|
||||||
|
usb:v04F3p0C8A*
|
||||||
|
usb:v05BAp000E*
|
||||||
|
usb:v06CBp0051*
|
||||||
|
usb:v06CBp0081*
|
||||||
|
usb:v06CBp0088*
|
||||||
|
usb:v06CBp008A*
|
||||||
|
usb:v06CBp009A*
|
||||||
|
usb:v06CBp009B*
|
||||||
|
usb:v06CBp00A2*
|
||||||
|
usb:v06CBp00A8*
|
||||||
|
usb:v06CBp00B7*
|
||||||
|
usb:v06CBp00BB*
|
||||||
|
usb:v06CBp00BE*
|
||||||
|
usb:v06CBp00CB*
|
||||||
|
usb:v06CBp00C9*
|
||||||
|
usb:v06CBp00D8*
|
||||||
|
usb:v06CBp00DA*
|
||||||
|
usb:v06CBp00DC*
|
||||||
|
usb:v06CBp00E4*
|
||||||
|
usb:v06CBp00E7*
|
||||||
|
usb:v06CBp00E9*
|
||||||
|
usb:v06CBp00FD*
|
||||||
|
usb:v06CBp00FF*
|
||||||
|
usb:v0A5Cp5801*
|
||||||
|
usb:v0A5Cp5805*
|
||||||
|
usb:v0A5Cp5834*
|
||||||
|
usb:v0A5Cp5840*
|
||||||
|
usb:v0A5Cp5841*
|
||||||
|
usb:v0A5Cp5842*
|
||||||
|
usb:v0A5Cp5843*
|
||||||
|
usb:v0A5Cp5844*
|
||||||
|
usb:v0A5Cp5845*
|
||||||
|
usb:v0A5Cp5860*
|
||||||
|
usb:v0A5Cp5863*
|
||||||
|
usb:v0A5Cp5864*
|
||||||
|
usb:v0A5Cp5865*
|
||||||
|
usb:v0A5Cp5866*
|
||||||
|
usb:v0A5Cp5867*
|
||||||
|
usb:v0BDAp5812*
|
||||||
|
usb:v10A5p0007*
|
||||||
|
usb:v10A5p9200*
|
||||||
|
usb:v10A5p9800*
|
||||||
|
usb:v10A5pA120*
|
||||||
|
usb:v10A5pA900*
|
||||||
|
usb:v10A5pE340*
|
||||||
|
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:v138Ap00A6*
|
||||||
|
usb:v147Ep1002*
|
||||||
|
usb:v1491p0088*
|
||||||
|
usb:v16D1p1027*
|
||||||
|
usb:v1C7Ap0300*
|
||||||
|
usb:v1C7Ap0575*
|
||||||
|
usb:v1C7Ap0576*
|
||||||
|
usb:v1C7Ap0584*
|
||||||
|
usb:v1C7Ap0577*
|
||||||
|
usb:v1C7Ap057E*
|
||||||
|
usb:v2541p0236*
|
||||||
|
usb:v2541p9711*
|
||||||
|
usb:v27C6p5042*
|
||||||
|
usb:v27C6p5110*
|
||||||
|
usb:v27C6p5117*
|
||||||
|
usb:v27C6p5120*
|
||||||
|
usb:v27C6p5125*
|
||||||
|
usb:v27C6p5201*
|
||||||
|
usb:v27C6p521D*
|
||||||
|
usb:v27C6p5301*
|
||||||
|
usb:v27C6p530C*
|
||||||
|
usb:v27C6p532D*
|
||||||
|
usb:v27C6p5335*
|
||||||
|
usb:v27C6p533C*
|
||||||
|
usb:v27C6p5381*
|
||||||
|
usb:v27C6p5385*
|
||||||
|
usb:v27C6p538C*
|
||||||
|
usb:v27C6p538D*
|
||||||
|
usb:v27C6p5395*
|
||||||
|
usb:v27C6p5503*
|
||||||
|
usb:v27C6p550A*
|
||||||
|
usb:v27C6p550C*
|
||||||
|
usb:v27C6p5584*
|
||||||
|
usb:v27C6p55A2*
|
||||||
|
usb:v27C6p55A4*
|
||||||
|
usb:v27C6p55B4*
|
||||||
|
usb:v27C6p5740*
|
||||||
|
usb:v27C6p5E0A*
|
||||||
|
usb:v27C6p581A*
|
||||||
|
usb:v27C6p589A*
|
||||||
|
usb:v27C6p5F10*
|
||||||
|
usb:v27C6p6382*
|
||||||
|
usb:v2808p9338*
|
||||||
|
usb:v2808p9348*
|
||||||
|
usb:v2808p93A9*
|
||||||
|
usb:v2808pA658*
|
||||||
|
usb:v2808pC652*
|
||||||
|
usb:v298Dp2020*
|
||||||
|
usb:v298Dp2033*
|
||||||
|
usb:v2DF0p0003*
|
||||||
|
usb:v3274p8012*
|
||||||
|
usb:v3538p0930*
|
||||||
|
ID_AUTOSUSPEND=1
|
||||||
|
ID_PERSIST=0
|
||||||
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
|
||||||
570
demo/gtk-libfprint-test.c
Normal file
@@ -0,0 +1,570 @@
|
|||||||
|
/*
|
||||||
|
* Example libfprint GTK+ image capture program
|
||||||
|
* Copyright (C) 2018 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
struct _LibfprintDemo
|
||||||
|
{
|
||||||
|
GtkApplication parent;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication)
|
||||||
|
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IMAGE_DISPLAY_NONE = 0,
|
||||||
|
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
|
||||||
|
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||||
|
} ImageDisplayFlags;
|
||||||
|
|
||||||
|
struct _LibfprintDemoWindow
|
||||||
|
{
|
||||||
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
|
GtkWidget *header_bar;
|
||||||
|
GtkWidget *mode_stack;
|
||||||
|
GtkWidget *capture_button;
|
||||||
|
GtkWidget *cancel_button;
|
||||||
|
GtkWidget *capture_image;
|
||||||
|
GtkWidget *spinner;
|
||||||
|
GtkWidget *instructions;
|
||||||
|
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
gboolean opened;
|
||||||
|
FpDevice *dev;
|
||||||
|
|
||||||
|
FpImage *img;
|
||||||
|
ImageDisplayFlags img_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (LibfprintDemoWindow, libfprint_demo_window, FP, DEMO_WINDOW, GtkApplicationWindow)
|
||||||
|
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMPTY_MODE,
|
||||||
|
NOIMAGING_MODE,
|
||||||
|
CAPTURE_MODE,
|
||||||
|
SPINNER_MODE,
|
||||||
|
ERROR_MODE,
|
||||||
|
RETRY_MODE
|
||||||
|
} LibfprintDemoMode;
|
||||||
|
|
||||||
|
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
|
LibfprintDemoMode mode);
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
img_to_rgbdata (const guint8 *imgdata,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int size = width * height;
|
||||||
|
guint8 *rgbdata = g_malloc (size * 3);
|
||||||
|
size_t i;
|
||||||
|
size_t rgb_offset = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
guint8 pixel = imgdata[i];
|
||||||
|
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgbdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
plot_minutiae (unsigned char *rgbdata,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
GPtrArray *minutiae)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#define write_pixel(num) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
rgbdata[((num) * 3)] = 0xff; \
|
||||||
|
rgbdata[((num) * 3) + 1] = 0; \
|
||||||
|
rgbdata[((num) * 3) + 2] = 0; \
|
||||||
|
} \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
for (i = 0; i < minutiae->len; i++)
|
||||||
|
{
|
||||||
|
struct fp_minutia *min = g_ptr_array_index (minutiae, i);
|
||||||
|
int x, y;
|
||||||
|
size_t pixel_offset;
|
||||||
|
|
||||||
|
fp_minutia_get_coords (min, &x, &y);
|
||||||
|
pixel_offset = (y * width) + x;
|
||||||
|
write_pixel (pixel_offset - 2);
|
||||||
|
write_pixel (pixel_offset - 1);
|
||||||
|
write_pixel (pixel_offset);
|
||||||
|
write_pixel (pixel_offset + 1);
|
||||||
|
write_pixel (pixel_offset + 2);
|
||||||
|
|
||||||
|
write_pixel (pixel_offset - (width * 2));
|
||||||
|
write_pixel (pixel_offset - (width * 1) - 1);
|
||||||
|
write_pixel (pixel_offset - (width * 1));
|
||||||
|
write_pixel (pixel_offset - (width * 1) + 1);
|
||||||
|
write_pixel (pixel_offset + (width * 1) - 1);
|
||||||
|
write_pixel (pixel_offset + (width * 1));
|
||||||
|
write_pixel (pixel_offset + (width * 1) + 1);
|
||||||
|
write_pixel (pixel_offset + (width * 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf *
|
||||||
|
img_to_pixbuf (FpImage *img,
|
||||||
|
ImageDisplayFlags flags)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
const guint8 *data;
|
||||||
|
unsigned char *rgbdata;
|
||||||
|
|
||||||
|
width = fp_image_get_width (img);
|
||||||
|
height = fp_image_get_height (img);
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_BINARY)
|
||||||
|
data = fp_image_get_binarized (img, NULL);
|
||||||
|
else
|
||||||
|
data = fp_image_get_data (img, NULL);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rgbdata = img_to_rgbdata (data, width, height);
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_MINUTIAE)
|
||||||
|
{
|
||||||
|
GPtrArray *minutiae;
|
||||||
|
|
||||||
|
minutiae = fp_image_get_minutiae (img);
|
||||||
|
plot_minutiae (rgbdata, width, height, minutiae);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||||
|
FALSE, 8, width, height,
|
||||||
|
width * 3, (GdkPixbufDestroyNotify) g_free,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_image (LibfprintDemoWindow *win)
|
||||||
|
{
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
|
if (win->img == NULL)
|
||||||
|
{
|
||||||
|
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug ("Updating image, minutiae %s, binary mode %s",
|
||||||
|
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
|
||||||
|
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
|
||||||
|
pixbuf = img_to_pixbuf (win->img, win->img_flags);
|
||||||
|
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
|
||||||
|
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
|
||||||
|
g_free (label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||||
|
{
|
||||||
|
FpScanType scan_type;
|
||||||
|
const char *message;
|
||||||
|
|
||||||
|
scan_type = fp_device_get_scan_type (win->dev);
|
||||||
|
|
||||||
|
switch (scan_type)
|
||||||
|
{
|
||||||
|
case FP_SCAN_TYPE_PRESS:
|
||||||
|
message = "Place your finger on the fingerprint reader";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_SCAN_TYPE_SWIPE:
|
||||||
|
message = "Swipe your finger across the fingerprint reader";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_spinner_label (win, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_capture_start_cb (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
FpImage *image = NULL;
|
||||||
|
|
||||||
|
g_clear_object (&win->cancellable);
|
||||||
|
|
||||||
|
image = fp_device_capture_finish (dev, res, &error);
|
||||||
|
if (!image)
|
||||||
|
{
|
||||||
|
g_warning ("Error capturing data: %s", error->message);
|
||||||
|
if (error->domain == FP_DEVICE_RETRY ||
|
||||||
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
libfprint_demo_set_mode (win, RETRY_MODE);
|
||||||
|
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
||||||
|
libfprint_demo_set_mode (win, NOIMAGING_MODE);
|
||||||
|
else
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&win->img);
|
||||||
|
win->img = image;
|
||||||
|
update_image (win);
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_start_capture (LibfprintDemoWindow *win)
|
||||||
|
{
|
||||||
|
libfprint_demo_set_capture_label (win);
|
||||||
|
|
||||||
|
fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
if (!fp_device_open_finish (dev, res, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to open device: %s", error->message);
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_start_capture (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_capture (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||||
|
g_clear_pointer (&win->img, g_object_unref);
|
||||||
|
|
||||||
|
g_clear_object (&win->cancellable);
|
||||||
|
win->cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
|
if (win->opened)
|
||||||
|
{
|
||||||
|
dev_start_capture (win);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||||
|
|
||||||
|
win->opened = TRUE;
|
||||||
|
fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cancel_capture (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
|
||||||
|
g_debug ("cancelling %p", win->cancellable);
|
||||||
|
|
||||||
|
if (win->cancellable)
|
||||||
|
g_cancellable_cancel (win->cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_quit (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkApplication *app = user_data;
|
||||||
|
GtkWidget *win;
|
||||||
|
GList *list, *next;
|
||||||
|
|
||||||
|
list = gtk_application_get_windows (app);
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
win = list->data;
|
||||||
|
next = list->next;
|
||||||
|
|
||||||
|
gtk_widget_destroy (GTK_WIDGET (win));
|
||||||
|
|
||||||
|
list = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_show_minutiae (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
GVariant *state;
|
||||||
|
gboolean new_state;
|
||||||
|
|
||||||
|
state = g_action_get_state (G_ACTION (action));
|
||||||
|
new_state = !g_variant_get_boolean (state);
|
||||||
|
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||||
|
g_variant_unref (state);
|
||||||
|
|
||||||
|
if (new_state)
|
||||||
|
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
|
||||||
|
else
|
||||||
|
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
|
||||||
|
|
||||||
|
update_image (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_show_binary (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
GVariant *state;
|
||||||
|
gboolean new_state;
|
||||||
|
|
||||||
|
state = g_action_get_state (G_ACTION (action));
|
||||||
|
new_state = !g_variant_get_boolean (state);
|
||||||
|
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||||
|
g_variant_unref (state);
|
||||||
|
|
||||||
|
if (new_state)
|
||||||
|
win->img_flags |= IMAGE_DISPLAY_BINARY;
|
||||||
|
else
|
||||||
|
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
|
||||||
|
|
||||||
|
update_image (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
change_show_minutiae_state (GSimpleAction *action,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_simple_action_set_state (action, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
change_show_binary_state (GSimpleAction *action,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_simple_action_set_state (action, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GActionEntry app_entries[] = {
|
||||||
|
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static GActionEntry win_entries[] = {
|
||||||
|
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||||
|
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||||
|
{ "capture", activate_capture, NULL, NULL, NULL },
|
||||||
|
{ "cancel", cancel_capture, NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate (GApplication *app)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *window;
|
||||||
|
|
||||||
|
window = g_object_new (libfprint_demo_window_get_type (),
|
||||||
|
"application", app,
|
||||||
|
NULL);
|
||||||
|
gtk_widget_show (GTK_WIDGET (window));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
|
LibfprintDemoMode mode)
|
||||||
|
{
|
||||||
|
char *title;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case EMPTY_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOIMAGING_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAPTURE_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||||
|
|
||||||
|
title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev));
|
||||||
|
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||||
|
g_free (title);
|
||||||
|
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPINNER_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, TRUE);
|
||||||
|
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RETRY_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||||
|
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_init (LibfprintDemo *app)
|
||||||
|
{
|
||||||
|
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||||
|
app_entries, G_N_ELEMENTS (app_entries),
|
||||||
|
app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_class_init (LibfprintDemoClass *class)
|
||||||
|
{
|
||||||
|
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
||||||
|
|
||||||
|
app_class->activate = activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||||
|
{
|
||||||
|
FpContext *ctx;
|
||||||
|
GPtrArray *devices;
|
||||||
|
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (window));
|
||||||
|
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||||
|
|
||||||
|
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||||
|
win_entries, G_N_ELEMENTS (win_entries),
|
||||||
|
window);
|
||||||
|
|
||||||
|
ctx = fp_context_new ();
|
||||||
|
|
||||||
|
devices = fp_context_get_devices (ctx);
|
||||||
|
if (!devices)
|
||||||
|
{
|
||||||
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty list? */
|
||||||
|
if (devices->len == 0)
|
||||||
|
{
|
||||||
|
libfprint_demo_set_mode (window, EMPTY_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
|
||||||
|
{
|
||||||
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->dev = g_object_ref (g_ptr_array_index (devices, 0));
|
||||||
|
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
|
||||||
|
{
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||||
|
|
||||||
|
//FIXME setup dispose
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
GtkApplication *app;
|
||||||
|
|
||||||
|
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
|
||||||
|
"application-id", "org.freedesktop.libfprint.Demo",
|
||||||
|
"flags", G_APPLICATION_FLAGS_NONE,
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||||
|
}
|
||||||
6
demo/gtk-libfprint-test.gresource.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/libfprint_demo">
|
||||||
|
<file>gtk-libfprint-test.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
||||||
427
demo/gtk-libfprint-test.ui
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.0 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="default_width">500</property>
|
||||||
|
<property name="default_height">400</property>
|
||||||
|
<property name="show_menubar">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStack" id="mode_stack">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="spinner-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinner" id="spinner">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="instructions">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">Please press finger on reader</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">spinner-mode</property>
|
||||||
|
<property name="title">spinner-mode</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAspectFrame" id="capture-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<property name="ratio">1.2999999523162842</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="capture_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">capture-mode</property>
|
||||||
|
<property name="title">capture-mode</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="retry-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
<property name="icon_name">dialog-warning-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">Device reported a recoverable error. Please retry!</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">retry-mode</property>
|
||||||
|
<property name="title">retry-mode</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="noimaging-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
<property name="icon_name">scanner-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">Fingerprint reader does not support capturing images</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">noimaging-mode</property>
|
||||||
|
<property name="title">noimaging-mode</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="error-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
<property name="icon_name">dialog-warning-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">error-mode</property>
|
||||||
|
<property name="title">error-mode</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="empty-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">No fingerprint readers found</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">empty-mode</property>
|
||||||
|
<property name="title">empty-mode</property>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="titlebar">
|
||||||
|
<object class="GtkHeaderBar" id="header_bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title">Fingerprint Reader Test</property>
|
||||||
|
<property name="subtitle">Capture test</property>
|
||||||
|
<property name="show_close_button">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuButton" id="option-menu-button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="menu-model">options-menu</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">open-menu-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="cancel_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="action_name">win.cancel</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="cancel_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Cancel</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="text-button"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="capture_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="action_name">win.capture</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="capture_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_Capture</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="text-button"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<menu id="options-menu">
|
||||||
|
<section>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Show Minutiae</attribute>
|
||||||
|
<attribute name="action">win.show-minutiae</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Show Binary</attribute>
|
||||||
|
<attribute name="action">win.show-binary</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
</menu>
|
||||||
|
</interface>
|
||||||
30
demo/meson.build
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
gtk_test_resources = gnome.compile_resources('gtk-test-resources',
|
||||||
|
'gtk-libfprint-test.gresource.xml',
|
||||||
|
source_dir : '.',
|
||||||
|
c_name : 'gtk_test')
|
||||||
|
|
||||||
|
prefix = get_option('prefix')
|
||||||
|
bindir = join_paths(prefix, get_option('bindir'))
|
||||||
|
datadir = join_paths(prefix, get_option('datadir'))
|
||||||
|
|
||||||
|
executable('gtk-libfprint-test',
|
||||||
|
[ 'gtk-libfprint-test.c', gtk_test_resources ],
|
||||||
|
dependencies: [
|
||||||
|
gtk_dep,
|
||||||
|
libfprint_dep,
|
||||||
|
],
|
||||||
|
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
|
||||||
|
install: true,
|
||||||
|
install_dir: bindir)
|
||||||
|
|
||||||
|
appdata = 'org.freedesktop.libfprint.Demo.appdata.xml'
|
||||||
|
install_data(appdata,
|
||||||
|
install_dir: join_paths(datadir, 'metainfo'))
|
||||||
|
|
||||||
|
desktop = 'org.freedesktop.libfprint.Demo.desktop'
|
||||||
|
install_data(desktop,
|
||||||
|
install_dir: join_paths(datadir, 'applications'))
|
||||||
|
|
||||||
|
icon = 'org.freedesktop.libfprint.Demo.png'
|
||||||
|
install_data(icon,
|
||||||
|
install_dir: join_paths(datadir, 'icons'))
|
||||||
28
demo/org.freedesktop.libfprint.Demo.appdata.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop">
|
||||||
|
<id>org.freedesktop.libfprint.Demo.desktop</id>
|
||||||
|
<name>Fingerprint Reader Demo</name>
|
||||||
|
<summary>Test fingerprint readers</summary>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>LGPL-2.1+</project_license>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Fingerprint Reader Demo is a test application for the libfprint
|
||||||
|
fingerprint reader library. Its purpose is to test drivers, new and old,
|
||||||
|
in a sandbox, to make sure that the drivers and associated functions
|
||||||
|
work correctly.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Fingerprint Reader Demo does not modify the system, or replace integration
|
||||||
|
in desktop environments.
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
<url type="homepage">https://fprint.freedesktop.org</url>
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default" width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-main.png</screenshot>
|
||||||
|
<screenshot width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-music-playlist.png</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
<updatecontact>hadess@hadess.net</updatecontact>
|
||||||
|
<!-- Incorrect, but appstream-util won't validate without it -->
|
||||||
|
<translation type="gettext">libfprint</translation>
|
||||||
|
</component>
|
||||||
10
demo/org.freedesktop.libfprint.Demo.desktop
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=Fingerprint Reader Demo
|
||||||
|
Comment=Test fingerprint readers
|
||||||
|
Keywords=finger;print;fingerprint;fprint;demo;driver;reader;
|
||||||
|
Exec=gtk-libfprint-test
|
||||||
|
Icon=org.freedesktop.libfprint.Demo
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=GTK;GNOME;Development;System;
|
||||||
|
StartupNotify=true
|
||||||
74
demo/org.freedesktop.libfprint.Demo.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
|
"runtime": "org.gnome.Platform",
|
||||||
|
"runtime-version": "master",
|
||||||
|
"sdk": "org.gnome.Sdk",
|
||||||
|
"command": "gtk-libfprint-test",
|
||||||
|
"finish-args": [
|
||||||
|
/* X11 + XShm access */
|
||||||
|
"--share=ipc", "--socket=fallback-x11",
|
||||||
|
/* Wayland access */
|
||||||
|
"--socket=wayland",
|
||||||
|
/* OpenGL access */
|
||||||
|
"--device=dri",
|
||||||
|
/* USB access */
|
||||||
|
"--device=all"
|
||||||
|
],
|
||||||
|
"cleanup": [ "/include", "/lib/pkgconfig/" ],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "libusb",
|
||||||
|
"config-opts": [ "--disable-static" ],
|
||||||
|
"cleanup": [
|
||||||
|
"/lib/*.la",
|
||||||
|
"/lib/pkgconfig",
|
||||||
|
"/include"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/libusb/libusb/releases/download/v1.0.26/libusb-1.0.26.tar.bz2",
|
||||||
|
"sha256": "12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"post-install": [
|
||||||
|
"install -Dm644 COPYING /app/share/licenses/libusb/COPYING"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "libgusb",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/hughsie/libgusb/releases/download/0.4.6/libgusb-0.4.6.tar.xz",
|
||||||
|
"sha256": "1b0422bdcd72183272ac42eec9398c5a0bc48a02f618fa3242c468cbbd003049"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gudev",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled", "-Dvapi=disabled" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://download.gnome.org/sources/libgudev/238/libgudev-238.tar.xz",
|
||||||
|
"sha256": "61266ab1afc9d73dbc60a8b2af73e99d2fdff47d99544d085760e4fa667b5dd1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "libfprint",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
@@ -1,10 +0,0 @@
|
|||||||
EXTRA_DIST = doxygen.cfg
|
|
||||||
|
|
||||||
docs: doxygen.cfg
|
|
||||||
doxygen $^
|
|
||||||
|
|
||||||
docs-upload: docs
|
|
||||||
ln -s html api
|
|
||||||
ncftpput -f ~/.ncftp/reactivated -m -R httpdocs/fprint api/
|
|
||||||
rm -f api
|
|
||||||
|
|
||||||
113
doc/advanced-topics.xml
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="advanced-topics" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Advanced Topics</title>
|
||||||
|
|
||||||
|
<refsect2 id="compatibility">
|
||||||
|
<title>Device and print compatibility</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Moving off generic conceptual ideas and onto libfprint-specific
|
||||||
|
implementation details, here are some introductory notes regarding how
|
||||||
|
libfprint copes with compatibility of fingerprints.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint deals with a whole variety of different fingerprint readers and
|
||||||
|
the design includes considerations of compatibility and interoperability
|
||||||
|
between multiple devices. Your application should also be prepared to
|
||||||
|
work with more than one type of fingerprint reader and should consider that
|
||||||
|
enrolled fingerprint X may not be compatible with the device the user has
|
||||||
|
plugged in today.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint implements the principle that fingerprints from different devices
|
||||||
|
are not necessarily compatible. For example, different devices may see
|
||||||
|
significantly different areas of fingerprint surface, and comparing images
|
||||||
|
between the devices would be unreliable. Also, devices can stretch and
|
||||||
|
distort images in different ways.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint also implements the principle that in some cases, fingerprints
|
||||||
|
<emphasis>are</emphasis> compatible between different devices. If you go and buy two
|
||||||
|
identical fingerprint readers, it seems logical that you should be able
|
||||||
|
to enroll on one and verify on another without problems.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint takes a fairly simplistic approach to these issues. Internally,
|
||||||
|
fingerprint hardware is driven by individual drivers. libfprint enforces
|
||||||
|
that a fingerprint that came from a device backed by driver X is never
|
||||||
|
compared to a fingerprint that came from a device backed by driver Y.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Additionally, libfprint is designed for the situation where a single driver
|
||||||
|
may support a range of devices which differ in imaging or scanning
|
||||||
|
properties. For example, a driver may support two ranges of devices which
|
||||||
|
even though are programmed over the same interface, one device sees
|
||||||
|
substantially less of the finger flesh, therefore images from the two
|
||||||
|
device types should be incompatible despite being from the same driver. To
|
||||||
|
implement this, each driver assigns a <emphasis>device type</emphasis> to each device
|
||||||
|
that it detects based on its imaging characteristics. libfprint ensures that
|
||||||
|
two prints being compared have the same device type.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In summary, libfprint represents fingerprints in several internal structures
|
||||||
|
and each representation will offer you a way of determining the
|
||||||
|
<ulink url="#driver">driver</ulink> and <ulink url="#device-id">device ID</ulink> of the print in
|
||||||
|
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
||||||
|
match. libfprint does offer you some "is this print compatible?" helper
|
||||||
|
functions, so you don't have to worry about these details too much.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="driver">
|
||||||
|
<title>Driver</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each driver is assigned a unique string identifier by the project maintainer.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The only reason you may be interested in retrieving the driver ID for a
|
||||||
|
driver is for the purpose of checking if some print data is compatible
|
||||||
|
with a device. libfprint uses the driver ID as one way of checking that
|
||||||
|
the print you are trying to verify is compatible with the device in
|
||||||
|
question - it ensures that enrollment data from one driver is never fed to
|
||||||
|
another. Note that libfprint does provide you with helper functions to
|
||||||
|
determine whether a print is compatible with a device, so under most
|
||||||
|
circumstances, you don't have to worry about driver IDs at all.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="device-id">
|
||||||
|
<title>Device ID</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Internally, the behind a device assigns a string identifier to the device
|
||||||
|
This cannot be used as a unique ID for a specific device as many devices
|
||||||
|
under the same range may share the same devtype. The device ID may even
|
||||||
|
be the same string in all cases. It is guaranteed to have a non-zero length
|
||||||
|
and be a valid file name. It defaults to "0".
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The only reason you may be interested in retrieving the device ID for a
|
||||||
|
device is for the purpose of checking if some print data is compatible
|
||||||
|
with a device. libfprint uses the device ID as one way of checking that the
|
||||||
|
print you are verifying is compatible with the device in question - the
|
||||||
|
device ID must be equal. This effectively allows drivers to support more
|
||||||
|
than one type of device where the data from each one is not compatible with
|
||||||
|
the other. Note that libfprint does provide you with helper functions to
|
||||||
|
determine whether a print is compatible with a device, so under most
|
||||||
|
circumstances, you don't have to worry about devtypes at all.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
1294
doc/doxygen.cfg
30
doc/getting-started.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="getting-started" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Getting Started</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint includes several simple functional examples under the <computeroutput>examples/</computeroutput>
|
||||||
|
directory in the libfprint source distribution. Those are good starting
|
||||||
|
points.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Usually the first thing you want to do is determine which fingerprint
|
||||||
|
devices are present. This is done using the <ulink url="fp-context.html">FpContext</ulink> object.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Once you have found a device you would like to operate, you should open it.
|
||||||
|
Refer to <ulink url="fp-context.html">device operations</ulink>. This section also details enrollment,
|
||||||
|
image capture, and verification.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
That should be enough to get you started, but do remember there are
|
||||||
|
documentation pages on other aspects of libfprint's API (see the modules
|
||||||
|
page).
|
||||||
|
</para>
|
||||||
|
</chapter>
|
||||||
106
doc/intro.xml
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="intro" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Introduction</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint is an open source library to provide access to fingerprint
|
||||||
|
scanning devices. For more info, see the
|
||||||
|
<ulink url="https://fprint.freedesktop.org/">libfprint project homepage</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This documentation is aimed at application developers who wish to integrate
|
||||||
|
fingerprint-related functionality into their software. libfprint has been
|
||||||
|
designed so that you only have to do this once – by integrating your
|
||||||
|
software with libfprint, you'll be supporting all the fingerprint readers
|
||||||
|
that we have got our hands on. As such, the API is rather general (and
|
||||||
|
therefore hopefully easy to comprehend!), and does its best to hide the
|
||||||
|
technical details that required to operate the hardware.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This documentation is not aimed at developers wishing to develop and
|
||||||
|
contribute fingerprint device drivers to libfprint.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Feedback on this API and its associated documentation is appreciated. Was
|
||||||
|
anything unclear? Does anything seem unreasonably complicated? Is anything
|
||||||
|
missing? Let us know on the
|
||||||
|
<ulink url="https://lists.freedesktop.org/mailman/listinfo/fprint">mailing list</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<refsect2 id="enrollment">
|
||||||
|
<title>Enrollment</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Before you dive into the API, it's worth introducing a couple of concepts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The process of enrolling a finger is where you effectively scan your
|
||||||
|
finger for the purposes of teaching the system what your finger looks like.
|
||||||
|
This means that you scan your fingerprint, then the system processes it and
|
||||||
|
stores some data about your fingerprint to refer to later.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="verification">
|
||||||
|
<title>Verification</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Verification is what most people think of when they think about fingerprint
|
||||||
|
scanning. The process of verification is effectively performing a fresh
|
||||||
|
fingerprint scan, and then comparing that scan to a finger that was
|
||||||
|
previously enrolled.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As an example scenario, verification can be used to implement what people
|
||||||
|
would picture as fingerprint login (i.e. fingerprint replaces password).
|
||||||
|
For example:
|
||||||
|
</para>
|
||||||
|
<itemizedlist mark='dot'>
|
||||||
|
<listitem>
|
||||||
|
I enroll my fingerprint through some software that trusts I am who I say
|
||||||
|
I am. This is a prerequisite before I can perform fingerprint-based
|
||||||
|
login for my account.
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
Some time later, I want to login to my computer. I enter my username,
|
||||||
|
but instead of prompting me for a password, it asks me to scan my finger.
|
||||||
|
I scan my finger.
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
The system compares the finger I just scanned to the one that was
|
||||||
|
enrolled earlier. If the system decides that the fingerprints match,
|
||||||
|
I am successfully logged in. Otherwise, the system informs me that I am
|
||||||
|
not authorised to login as that user.
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="identification">
|
||||||
|
<title>Identification</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Identification is the process of comparing a freshly scanned fingerprint
|
||||||
|
to a <emphasis>collection</emphasis> of previously enrolled fingerprints. For example,
|
||||||
|
imagine there are 100 people in an organisation, and they all have enrolled
|
||||||
|
their fingerprints. One user walks up to a fingerprint scanner and scans
|
||||||
|
their finger. With <emphasis>no other knowledge</emphasis> of who that user might be,
|
||||||
|
the system examines their fingerprint, looks in the database, and determines
|
||||||
|
that the user is user number #61.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In other words, verification might be seen as a one-to-one fingerprint
|
||||||
|
comparison where you know the identity of the user that you wish to
|
||||||
|
authenticate, whereas identification is a one-to-many comparison where you
|
||||||
|
do not know the identity of the user that you wish to authenticate.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</chapter>
|
||||||
312
doc/libfprint-2-sections.txt
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
<SECTION>
|
||||||
|
<FILE>drivers_api</FILE>
|
||||||
|
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-context</FILE>
|
||||||
|
<TITLE>FpContext</TITLE>
|
||||||
|
FP_TYPE_CONTEXT
|
||||||
|
FpContextClass
|
||||||
|
fp_context_new
|
||||||
|
fp_context_enumerate
|
||||||
|
fp_context_get_devices
|
||||||
|
FpContext
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-device</FILE>
|
||||||
|
FP_TYPE_DEVICE
|
||||||
|
FP_DEVICE_RETRY
|
||||||
|
FP_DEVICE_ERROR
|
||||||
|
FpDeviceType
|
||||||
|
FpDeviceFeature
|
||||||
|
FpScanType
|
||||||
|
FpDeviceRetry
|
||||||
|
FpDeviceError
|
||||||
|
FpFingerStatusFlags
|
||||||
|
fp_device_retry_quark
|
||||||
|
fp_device_error_quark
|
||||||
|
FpEnrollProgress
|
||||||
|
FpMatchCb
|
||||||
|
fp_device_get_driver
|
||||||
|
fp_device_get_device_id
|
||||||
|
fp_device_get_name
|
||||||
|
fp_device_get_scan_type
|
||||||
|
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_supports_identify
|
||||||
|
fp_device_supports_capture
|
||||||
|
fp_device_get_persistent_data
|
||||||
|
fp_device_set_persistent_data
|
||||||
|
fp_device_is_open
|
||||||
|
fp_device_open
|
||||||
|
fp_device_close
|
||||||
|
fp_device_enroll
|
||||||
|
fp_device_verify
|
||||||
|
fp_device_identify
|
||||||
|
fp_device_capture
|
||||||
|
fp_device_delete_print
|
||||||
|
fp_device_list_prints
|
||||||
|
fp_device_clear_storage
|
||||||
|
fp_device_suspend
|
||||||
|
fp_device_resume
|
||||||
|
fp_device_open_finish
|
||||||
|
fp_device_close_finish
|
||||||
|
fp_device_enroll_finish
|
||||||
|
fp_device_verify_finish
|
||||||
|
fp_device_identify_finish
|
||||||
|
fp_device_capture_finish
|
||||||
|
fp_device_delete_print_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_close_sync
|
||||||
|
fp_device_enroll_sync
|
||||||
|
fp_device_verify_sync
|
||||||
|
fp_device_identify_sync
|
||||||
|
fp_device_capture_sync
|
||||||
|
fp_device_delete_print_sync
|
||||||
|
fp_device_list_prints_sync
|
||||||
|
fp_device_clear_storage_sync
|
||||||
|
fp_device_suspend_sync
|
||||||
|
fp_device_resume_sync
|
||||||
|
FpDevice
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-image</FILE>
|
||||||
|
FP_TYPE_IMAGE
|
||||||
|
FpMinutia
|
||||||
|
fp_image_new
|
||||||
|
fp_image_get_width
|
||||||
|
fp_image_get_height
|
||||||
|
fp_image_get_ppmm
|
||||||
|
fp_image_get_minutiae
|
||||||
|
fp_image_detect_minutiae
|
||||||
|
fp_image_detect_minutiae_finish
|
||||||
|
fp_image_get_data
|
||||||
|
fp_image_get_binarized
|
||||||
|
fp_minutia_get_coords
|
||||||
|
FpImage
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-image-device</FILE>
|
||||||
|
FP_TYPE_IMAGE_DEVICE
|
||||||
|
FpImageDevice
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fp-print</FILE>
|
||||||
|
FP_TYPE_PRINT
|
||||||
|
FpFinger
|
||||||
|
FpPrint
|
||||||
|
fp_print_new
|
||||||
|
fp_print_get_driver
|
||||||
|
fp_print_get_device_id
|
||||||
|
fp_print_get_device_stored
|
||||||
|
fp_print_get_image
|
||||||
|
fp_print_get_finger
|
||||||
|
fp_print_get_username
|
||||||
|
fp_print_get_description
|
||||||
|
fp_print_get_enroll_date
|
||||||
|
fp_print_set_finger
|
||||||
|
fp_print_set_username
|
||||||
|
fp_print_set_description
|
||||||
|
fp_print_set_enroll_date
|
||||||
|
fp_print_compatible
|
||||||
|
fp_print_equal
|
||||||
|
fp_print_serialize
|
||||||
|
fp_print_deserialize
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-assembling</FILE>
|
||||||
|
fpi_frame
|
||||||
|
fpi_frame_asmbl_ctx
|
||||||
|
fpi_do_movement_estimation
|
||||||
|
fpi_assemble_frames
|
||||||
|
fpi_line_asmbl_ctx
|
||||||
|
fpi_assemble_lines
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-context</FILE>
|
||||||
|
fpi_get_driver_types
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-device</FILE>
|
||||||
|
FpDeviceClass
|
||||||
|
FpTimeoutFunc
|
||||||
|
FpiDeviceAction
|
||||||
|
FpIdEntry
|
||||||
|
FpiDeviceUdevSubtypeFlags
|
||||||
|
fpi_device_get_usb_device
|
||||||
|
fpi_device_get_udev_data
|
||||||
|
fpi_device_get_virtual_env
|
||||||
|
fpi_device_get_current_action
|
||||||
|
fpi_device_retry_new
|
||||||
|
fpi_device_error_new
|
||||||
|
fpi_device_retry_new_msg
|
||||||
|
fpi_device_error_new_msg
|
||||||
|
fpi_device_get_driver_data
|
||||||
|
fpi_device_get_enroll_data
|
||||||
|
fpi_device_get_capture_data
|
||||||
|
fpi_device_get_verify_data
|
||||||
|
fpi_device_get_identify_data
|
||||||
|
fpi_device_get_delete_data
|
||||||
|
fpi_device_get_cancellable
|
||||||
|
fpi_device_action_is_cancelled
|
||||||
|
fpi_device_add_timeout
|
||||||
|
fpi_device_set_nr_enroll_stages
|
||||||
|
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_probe_complete
|
||||||
|
fpi_device_open_complete
|
||||||
|
fpi_device_close_complete
|
||||||
|
fpi_device_enroll_complete
|
||||||
|
fpi_device_verify_complete
|
||||||
|
fpi_device_identify_complete
|
||||||
|
fpi_device_capture_complete
|
||||||
|
fpi_device_clear_storage_complete
|
||||||
|
fpi_device_delete_complete
|
||||||
|
fpi_device_list_complete
|
||||||
|
fpi_device_suspend_complete
|
||||||
|
fpi_device_resume_complete
|
||||||
|
fpi_device_enroll_progress
|
||||||
|
fpi_device_verify_report
|
||||||
|
fpi_device_identify_report
|
||||||
|
fpi_device_class_auto_initialize_features
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-image</FILE>
|
||||||
|
FpiImageFlags
|
||||||
|
FpImage
|
||||||
|
fpi_std_sq_dev
|
||||||
|
fpi_mean_sq_diff_norm
|
||||||
|
fpi_image_resize
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-image-device</FILE>
|
||||||
|
<TITLE>Internal FpImageDevice</TITLE>
|
||||||
|
FpiImageDeviceState
|
||||||
|
FpImageDeviceClass
|
||||||
|
fpi_image_device_session_error
|
||||||
|
fpi_image_device_open_complete
|
||||||
|
fpi_image_device_close_complete
|
||||||
|
fpi_image_device_activate_complete
|
||||||
|
fpi_image_device_deactivate_complete
|
||||||
|
fpi_image_device_report_finger_status
|
||||||
|
fpi_image_device_image_captured
|
||||||
|
fpi_image_device_retry_scan
|
||||||
|
fpi_image_device_set_bz3_threshold
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-log</FILE>
|
||||||
|
fp_dbg
|
||||||
|
fp_info
|
||||||
|
fp_warn
|
||||||
|
fp_err
|
||||||
|
BUG_ON
|
||||||
|
BUG
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-print</FILE>
|
||||||
|
FpiPrintType
|
||||||
|
FpiMatchResult
|
||||||
|
fpi_print_add_print
|
||||||
|
fpi_print_set_type
|
||||||
|
fpi_print_set_device_stored
|
||||||
|
fpi_print_add_from_image
|
||||||
|
fpi_print_bz3_match
|
||||||
|
fpi_print_generate_user_id
|
||||||
|
fpi_print_fill_from_user_id
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-ssm</FILE>
|
||||||
|
FpiSsmCompletedCallback
|
||||||
|
FpiSsmHandlerCallback
|
||||||
|
fpi_ssm_new
|
||||||
|
fpi_ssm_new_full
|
||||||
|
fpi_ssm_free
|
||||||
|
fpi_ssm_start
|
||||||
|
fpi_ssm_start_subsm
|
||||||
|
fpi_ssm_next_state
|
||||||
|
fpi_ssm_next_state_delayed
|
||||||
|
fpi_ssm_jump_to_state
|
||||||
|
fpi_ssm_jump_to_state_delayed
|
||||||
|
fpi_ssm_cancel_delayed_state_change
|
||||||
|
fpi_ssm_mark_completed
|
||||||
|
fpi_ssm_mark_failed
|
||||||
|
fpi_ssm_set_data
|
||||||
|
fpi_ssm_get_data
|
||||||
|
fpi_ssm_get_device
|
||||||
|
fpi_ssm_get_error
|
||||||
|
fpi_ssm_dup_error
|
||||||
|
fpi_ssm_get_cur_state
|
||||||
|
fpi_ssm_silence_debug
|
||||||
|
fpi_ssm_spi_transfer_cb
|
||||||
|
fpi_ssm_spi_transfer_with_weak_pointer_cb
|
||||||
|
fpi_ssm_usb_transfer_cb
|
||||||
|
fpi_ssm_usb_transfer_with_weak_pointer_cb
|
||||||
|
FpiSsm
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-usb-transfer</FILE>
|
||||||
|
FPI_USB_ENDPOINT_IN
|
||||||
|
FPI_USB_ENDPOINT_OUT
|
||||||
|
FpiUsbTransferCallback
|
||||||
|
FpiTransferType
|
||||||
|
FpiUsbTransfer
|
||||||
|
fpi_usb_transfer_new
|
||||||
|
fpi_usb_transfer_ref
|
||||||
|
fpi_usb_transfer_unref
|
||||||
|
fpi_usb_transfer_set_short_error
|
||||||
|
fpi_usb_transfer_fill_bulk
|
||||||
|
fpi_usb_transfer_fill_bulk_full
|
||||||
|
fpi_usb_transfer_fill_control
|
||||||
|
fpi_usb_transfer_fill_interrupt
|
||||||
|
fpi_usb_transfer_fill_interrupt_full
|
||||||
|
fpi_usb_transfer_submit
|
||||||
|
fpi_usb_transfer_submit_sync
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
FPI_TYPE_USB_TRANSFER
|
||||||
|
fpi_usb_transfer_get_type
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-spi-transfer</FILE>
|
||||||
|
FpiSpiTransferCallback
|
||||||
|
FpiSpiTransfer
|
||||||
|
fpi_spi_transfer_new
|
||||||
|
fpi_spi_transfer_ref
|
||||||
|
fpi_spi_transfer_unref
|
||||||
|
fpi_spi_transfer_write
|
||||||
|
fpi_spi_transfer_write_full
|
||||||
|
fpi_spi_transfer_read
|
||||||
|
fpi_spi_transfer_read_full
|
||||||
|
fpi_spi_transfer_submit
|
||||||
|
fpi_spi_transfer_submit_sync
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
FPI_TYPE_SPI_TRANSFER
|
||||||
|
fpi_spi_transfer_get_type
|
||||||
|
</SECTION>
|
||||||
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
|
||||||
76
doc/libfprint-docs.xml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
||||||
|
[
|
||||||
|
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||||
|
]>
|
||||||
|
<book id="index">
|
||||||
|
<bookinfo>
|
||||||
|
<title>libfprint Reference Manual</title>
|
||||||
|
<releaseinfo>
|
||||||
|
<para>This document is the API reference for the libfprint library.</para>
|
||||||
|
<para>
|
||||||
|
The latest version of libfprint, as well as the latest version of
|
||||||
|
this API reference, is <ulink role="online-location" url="https://fprint.freedesktop.org/libfprint-dev/">available online</ulink>.
|
||||||
|
</para>
|
||||||
|
</releaseinfo>
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>Library Overview</title>
|
||||||
|
<xi:include href="intro.xml"/>
|
||||||
|
<xi:include href="advanced-topics.xml"/>
|
||||||
|
<xi:include href="getting-started.xml"/>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>Library API Documentation</title>
|
||||||
|
<xi:include href="xml/fp-context.xml"/>
|
||||||
|
<xi:include href="xml/fp-device.xml"/>
|
||||||
|
<xi:include href="xml/fp-image-device.xml"/>
|
||||||
|
<xi:include href="xml/fp-print.xml"/>
|
||||||
|
<xi:include href="xml/fp-image.xml"/>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>Writing Drivers</title>
|
||||||
|
<chapter id="driver-dev">
|
||||||
|
<title>Device methods for drivers</title>
|
||||||
|
<xi:include href="xml/fpi-device.xml"/>
|
||||||
|
<xi:include href="xml/fpi-image-device.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-helpers">
|
||||||
|
<title>USB, SPI and State Machine helpers</title>
|
||||||
|
<xi:include href="xml/fpi-spi-transfer.xml"/>
|
||||||
|
<xi:include href="xml/fpi-usb-transfer.xml"/>
|
||||||
|
<xi:include href="xml/fpi-ssm.xml"/>
|
||||||
|
<xi:include href="xml/fpi-log.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-img">
|
||||||
|
<title>Image manipulation</title>
|
||||||
|
<xi:include href="xml/fpi-image.xml"/>
|
||||||
|
<xi:include href="xml/fpi-assembling.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-print">
|
||||||
|
<title>Print handling</title>
|
||||||
|
<xi:include href="xml/fpi-print.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-misc">
|
||||||
|
<title>Listing drivers</title>
|
||||||
|
<xi:include href="xml/fpi-context.xml"/>
|
||||||
|
</chapter>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<index id="api-index">
|
||||||
|
<title>API Index</title>
|
||||||
|
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||||
|
</index>
|
||||||
|
<index id="deprecated-api-index" role="deprecated">
|
||||||
|
<title>Index of deprecated API</title>
|
||||||
|
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||||
|
</index>
|
||||||
|
</book>
|
||||||
116
doc/libfprint-sections.txt-new-manual
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>context</FILE>
|
||||||
|
<TITLE>Device discovery and hotplugging</TITLE>
|
||||||
|
FP_TYPE_CONTEXT
|
||||||
|
FpContext
|
||||||
|
fp_context_new
|
||||||
|
fp_context_enumerate
|
||||||
|
fp_context_get_devices
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>device</FILE>
|
||||||
|
<TITLE>Device</TITLE>
|
||||||
|
FP_TYPE_DEVICE
|
||||||
|
FpDevice
|
||||||
|
FpDeviceType
|
||||||
|
FpScanType
|
||||||
|
FpDeviceRetry
|
||||||
|
FpDeviceError
|
||||||
|
FP_DEVICE_ERROR
|
||||||
|
FP_DEVICE_RETRY
|
||||||
|
fp_device_get_driver
|
||||||
|
fp_device_get_device_id
|
||||||
|
fp_device_get_name
|
||||||
|
fp_device_get_scan_type
|
||||||
|
|
||||||
|
fp_device_open
|
||||||
|
fp_device_open_finish
|
||||||
|
fp_device_open_sync
|
||||||
|
|
||||||
|
fp_device_close
|
||||||
|
fp_device_close_finish
|
||||||
|
fp_device_close_sync
|
||||||
|
|
||||||
|
fp_device_enroll
|
||||||
|
fp_device_enroll_finish
|
||||||
|
fp_device_enroll_sync
|
||||||
|
|
||||||
|
fp_device_identify
|
||||||
|
fp_device_identify_finish
|
||||||
|
fp_device_identify_sync
|
||||||
|
|
||||||
|
fp_device_capture
|
||||||
|
fp_device_capture_finish
|
||||||
|
fp_device_capture_sync
|
||||||
|
|
||||||
|
fp_device_verify
|
||||||
|
fp_device_verify_finish
|
||||||
|
fp_device_verify_sync
|
||||||
|
|
||||||
|
_fp_device_get_cancellable
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>print</FILE>
|
||||||
|
<TITLE>Fingerprint handling</TITLE>
|
||||||
|
FpPrint
|
||||||
|
fp_print_new
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>image</FILE>
|
||||||
|
<TITLE>Image handling</TITLE>
|
||||||
|
FP_TYPE_IMAGE
|
||||||
|
FpImage
|
||||||
|
fp_image_new
|
||||||
|
fp_image_detect_minutiae
|
||||||
|
fp_image_detect_minutiae_finish
|
||||||
|
fp_image_device_new
|
||||||
|
fp_image_get_binarized
|
||||||
|
fp_image_get_data
|
||||||
|
fp_image_get_height
|
||||||
|
fp_image_get_minutiae
|
||||||
|
fp_image_get_ppmm
|
||||||
|
fp_image_get_width
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>internal-image-device</FILE>
|
||||||
|
<INCLUDE>drivers_api.h</INCLUDE>
|
||||||
|
<TITLE>Base class for image devices</TITLE>
|
||||||
|
FpImageDevice
|
||||||
|
FpImageDeviceClass
|
||||||
|
FpiImageDeviceState
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>internal-usb-transfers</FILE>
|
||||||
|
<INCLUDE>drivers_api.h</INCLUDE>
|
||||||
|
<TITLE>USB Transfers</TITLE>
|
||||||
|
FpUsbTransfer
|
||||||
|
fp_usb_transfer_fill_bulk
|
||||||
|
fp_usb_transfer_fill_bulk_full
|
||||||
|
fp_usb_transfer_fill_control
|
||||||
|
fp_usb_transfer_fill_interrupt
|
||||||
|
fp_usb_transfer_fill_interrupt_full
|
||||||
|
fp_usb_transfer_get_type
|
||||||
|
fp_usb_transfer_new
|
||||||
|
fp_usb_transfer_ref
|
||||||
|
fp_usb_transfer_set_short_error
|
||||||
|
fp_usb_transfer_submit
|
||||||
|
fp_usb_transfer_submit_sync
|
||||||
|
fp_usb_transfer_unref
|
||||||
|
FpUsbTransferCallback
|
||||||
|
FP_USB_ENDPOINT_IN
|
||||||
|
FP_USB_ENDPOINT_OUT
|
||||||
|
</SECTION>
|
||||||
41
doc/meson.build
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
subdir('xml')
|
||||||
|
|
||||||
|
private_headers = [
|
||||||
|
'config.h',
|
||||||
|
'nbis-helpers.h',
|
||||||
|
'fprint.h',
|
||||||
|
|
||||||
|
# Subdirectories to ignore
|
||||||
|
'drivers',
|
||||||
|
'nbis',
|
||||||
|
]
|
||||||
|
|
||||||
|
html_images = [
|
||||||
|
]
|
||||||
|
|
||||||
|
content_files = [
|
||||||
|
'intro.xml'
|
||||||
|
]
|
||||||
|
|
||||||
|
expand_content_files = content_files
|
||||||
|
|
||||||
|
glib_prefix = dependency('glib-2.0').get_variable(pkgconfig: 'prefix')
|
||||||
|
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||||
|
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
|
|
||||||
|
gnome.gtkdoc(versioned_libname,
|
||||||
|
main_xml: 'libfprint-docs.xml',
|
||||||
|
src_dir: join_paths(meson.project_source_root(), 'libfprint'),
|
||||||
|
include_directories: include_directories('../libfprint'),
|
||||||
|
dependencies: libfprint_dep,
|
||||||
|
content_files: content_files,
|
||||||
|
expand_content_files: expand_content_files,
|
||||||
|
ignore_headers: private_headers,
|
||||||
|
gobject_typesfile: 'libfprint-2.types',
|
||||||
|
fixxref_args: [
|
||||||
|
'--html-dir=@0@'.format(docpath),
|
||||||
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
|
||||||
|
],
|
||||||
|
html_assets: html_images,
|
||||||
|
install: true)
|
||||||
8
doc/xml/gtkdocentities.ent.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!ENTITY package "@PACKAGE@">
|
||||||
|
<!ENTITY package_bugreport "@PACKAGE_BUGREPORT@">
|
||||||
|
<!ENTITY package_name "@PACKAGE_NAME@">
|
||||||
|
<!ENTITY package_string "@PACKAGE_STRING@">
|
||||||
|
<!ENTITY package_tarname "@PACKAGE_TARNAME@">
|
||||||
|
<!ENTITY package_url "@PACKAGE_URL@">
|
||||||
|
<!ENTITY package_version "@PACKAGE_VERSION@">
|
||||||
|
<!ENTITY package_api_version "@PACKAGE_API_VERSION@">
|
||||||
12
doc/xml/meson.build
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
ent_conf = configuration_data()
|
||||||
|
ent_conf.set('PACKAGE', versioned_libname)
|
||||||
|
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||||
|
ent_conf.set('PACKAGE_NAME', versioned_libname)
|
||||||
|
ent_conf.set('PACKAGE_STRING', versioned_libname)
|
||||||
|
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||||
|
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||||
|
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||||
|
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||||
|
configure_file(input: 'gtkdocentities.ent.in',
|
||||||
|
output: 'gtkdocentities.ent',
|
||||||
|
configuration: ent_conf)
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
AM_CFLAGS = -I$(top_srcdir)
|
|
||||||
noinst_PROGRAMS = verify_live enroll verify img_capture cpp-test
|
|
||||||
|
|
||||||
verify_live_SOURCES = verify_live.c
|
|
||||||
verify_live_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
enroll_SOURCES = enroll.c
|
|
||||||
enroll_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
verify_SOURCES = verify.c
|
|
||||||
verify_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
img_capture_SOURCES = img_capture.c
|
|
||||||
img_capture_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
cpp_test_SOURCES = cpp-test.cpp
|
|
||||||
cpp_test_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
if BUILD_X11_EXAMPLES
|
|
||||||
noinst_PROGRAMS += img_capture_continuous
|
|
||||||
|
|
||||||
img_capture_continuous_CFLAGS = $(X_CFLAGS) $(XV_CFLAGS)
|
|
||||||
img_capture_continuous_SOURCES = img_capture_continuous.c
|
|
||||||
img_capture_continuous_LDADD = ../libfprint/libfprint.la $(X_LIBS) $(X_PRE_LIBS) $(XV_LIBS) -lX11 $(X_EXTRA_LIBS);
|
|
||||||
endif
|
|
||||||
|
|
||||||
208
examples/clear-storage.c
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Example storage clearing program, which deletes all the
|
||||||
|
* fingers which have been previously enrolled to disk.
|
||||||
|
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
|
* Copyright (C) 2024 Abhinav Baid <abhinavbaid@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-clear-storage"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
typedef struct _ClearStorageData
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
unsigned int sigint_handler;
|
||||||
|
int ret_value;
|
||||||
|
} ClearStorageData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_storage_data_free (ClearStorageData *clear_storage_data)
|
||||||
|
{
|
||||||
|
g_clear_handle_id (&clear_storage_data->sigint_handler, g_source_remove);
|
||||||
|
g_clear_object (&clear_storage_data->cancellable);
|
||||||
|
g_main_loop_unref (clear_storage_data->loop);
|
||||||
|
g_free (clear_storage_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClearStorageData, clear_storage_data_free)
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
ClearStorageData *clear_storage_data = user_data;
|
||||||
|
|
||||||
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
g_warning ("Failed closing device %s", error->message);
|
||||||
|
|
||||||
|
g_main_loop_quit (clear_storage_data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_storage_quit (FpDevice *dev,
|
||||||
|
ClearStorageData *clear_storage_data)
|
||||||
|
{
|
||||||
|
if (!fp_device_is_open (dev))
|
||||||
|
{
|
||||||
|
g_main_loop_quit (clear_storage_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
clear_storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_clear_storage_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
ClearStorageData *clear_storage_data = user_data;
|
||||||
|
|
||||||
|
if (fp_device_clear_storage_finish (dev, res, &error))
|
||||||
|
{
|
||||||
|
if (!clear_saved_prints (dev, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Clear saved prints from local storage failed: %s",
|
||||||
|
error->message);
|
||||||
|
clear_storage_data->ret_value = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_print ("Clear storage successful!\n");
|
||||||
|
clear_storage_data->ret_value = EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_storage_quit (dev, clear_storage_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("Failed to clear storage: %s", error->message);
|
||||||
|
clear_storage_data->ret_value = EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
||||||
|
{
|
||||||
|
g_autoptr(GError) clear_error = NULL;
|
||||||
|
|
||||||
|
if (clear_saved_prints (dev, &clear_error))
|
||||||
|
clear_storage_data->ret_value = EXIT_SUCCESS;
|
||||||
|
else
|
||||||
|
g_warning ("Clear saved prints from local storage failed: %s",
|
||||||
|
clear_error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_storage_quit (dev, clear_storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_clear_storage (FpDevice *dev, ClearStorageData *clear_storage_data)
|
||||||
|
{
|
||||||
|
char buffer[20];
|
||||||
|
|
||||||
|
g_print ("Clear device storage? [Y/n]? ");
|
||||||
|
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||||
|
(buffer[0] == 'Y' || buffer[0] == 'y'))
|
||||||
|
{
|
||||||
|
fp_device_clear_storage (dev, clear_storage_data->cancellable,
|
||||||
|
(GAsyncReadyCallback) on_clear_storage_completed,
|
||||||
|
clear_storage_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_storage_quit (dev, clear_storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
ClearStorageData *clear_storage_data = user_data;
|
||||||
|
|
||||||
|
if (!fp_device_open_finish (dev, res, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to open device: %s", error->message);
|
||||||
|
clear_storage_quit (dev, clear_storage_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("Opened device. ");
|
||||||
|
|
||||||
|
start_clear_storage (dev, clear_storage_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
sigint_cb (void *user_data)
|
||||||
|
{
|
||||||
|
ClearStorageData *clear_storage_data = user_data;
|
||||||
|
|
||||||
|
g_cancellable_cancel (clear_storage_data->cancellable);
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FpContext) ctx = NULL;
|
||||||
|
g_autoptr(ClearStorageData) clear_storage_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_storage_data = g_new0 (ClearStorageData, 1);
|
||||||
|
clear_storage_data->ret_value = EXIT_FAILURE;
|
||||||
|
clear_storage_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
clear_storage_data->cancellable = g_cancellable_new ();
|
||||||
|
clear_storage_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
||||||
|
SIGINT,
|
||||||
|
sigint_cb,
|
||||||
|
clear_storage_data,
|
||||||
|
NULL);
|
||||||
|
fp_device_open (dev, clear_storage_data->cancellable,
|
||||||
|
(GAsyncReadyCallback) on_device_opened,
|
||||||
|
clear_storage_data);
|
||||||
|
|
||||||
|
g_main_loop_run (clear_storage_data->loop);
|
||||||
|
|
||||||
|
return clear_storage_data->ret_value;
|
||||||
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
fp_init ();
|
FpContext *ctx;
|
||||||
return 0;
|
|
||||||
|
ctx = fp_context_new ();
|
||||||
|
g_object_unref (ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Example fingerprint enrollment program
|
* Example fingerprint enrollment program
|
||||||
* Enrolls your right index 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>
|
||||||
*
|
*
|
||||||
* 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,139 +19,254 @@
|
|||||||
* 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 <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
#include "storage.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
typedef struct _EnrollData
|
||||||
{
|
{
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
GMainLoop *loop;
|
||||||
struct fp_driver *drv;
|
GCancellable *cancellable;
|
||||||
if (!ddev)
|
unsigned int sigint_handler;
|
||||||
return NULL;
|
FpFinger finger;
|
||||||
|
int ret_value;
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
gboolean update_fingerprint;
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
} EnrollData;
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *enroll(struct fp_dev *dev) {
|
static void
|
||||||
struct fp_print_data *enrolled_print = NULL;
|
enroll_data_free (EnrollData *enroll_data)
|
||||||
int r;
|
|
||||||
|
|
||||||
printf("You will need to successfully scan your finger %d times to "
|
|
||||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct fp_img *img = NULL;
|
|
||||||
|
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
|
||||||
|
|
||||||
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
|
||||||
if (img) {
|
|
||||||
fp_img_save_to_file(img, "enrolled.pgm");
|
|
||||||
printf("Wrote scanned image to enrolled.pgm\n");
|
|
||||||
fp_img_free(img);
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
printf("Enroll failed with error %d\n", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (r) {
|
|
||||||
case FP_ENROLL_COMPLETE:
|
|
||||||
printf("Enroll complete!\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_FAIL:
|
|
||||||
printf("Enroll failed, something wen't wrong :(\n");
|
|
||||||
return NULL;
|
|
||||||
case FP_ENROLL_PASS:
|
|
||||||
printf("Enroll stage passed. Yay!\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY:
|
|
||||||
printf("Didn't quite catch that. Please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
|
||||||
printf("Your swipe was too short, please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
|
||||||
printf("Didn't catch that, please center your finger on the "
|
|
||||||
"sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
|
||||||
printf("Scan failed, please remove your finger and then try "
|
|
||||||
"again.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (r != FP_ENROLL_COMPLETE);
|
|
||||||
|
|
||||||
if (!enrolled_print) {
|
|
||||||
fprintf(stderr, "Enroll complete but no print?\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Enrollment completed!\n\n");
|
|
||||||
return enrolled_print;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
{
|
||||||
int r = 1;
|
g_clear_handle_id (&enroll_data->sigint_handler, g_source_remove);
|
||||||
struct fp_dscv_dev *ddev;
|
g_clear_object (&enroll_data->cancellable);
|
||||||
struct fp_dscv_dev **discovered_devs;
|
g_main_loop_unref (enroll_data->loop);
|
||||||
struct fp_dev *dev;
|
g_free (enroll_data);
|
||||||
struct fp_print_data *data;
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free)
|
||||||
|
|
||||||
printf("This program will enroll your right index finger, "
|
static void
|
||||||
"unconditionally overwriting any right-index print that was enrolled "
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
"previously. If you want to continue, press enter, otherwise hit "
|
{
|
||||||
"Ctrl+C\n");
|
EnrollData *enroll_data = user_data;
|
||||||
getchar();
|
|
||||||
|
|
||||||
r = fp_init();
|
g_autoptr(GError) error = NULL;
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
fp_device_close_finish (dev, res, &error);
|
||||||
if (!discovered_devs) {
|
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
if (error)
|
||||||
if (!ddev) {
|
g_warning ("Failed closing device %s", error->message);
|
||||||
fprintf(stderr, "No devices detected.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = fp_dev_open(ddev);
|
g_main_loop_quit (enroll_data->loop);
|
||||||
fp_dscv_devs_free(discovered_devs);
|
|
||||||
if (!dev) {
|
|
||||||
fprintf(stderr, "Could not open device.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Opened device. It's now time to enroll your finger.\n\n");
|
|
||||||
data = enroll(dev);
|
|
||||||
if (!data)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
r = fp_print_data_save(data, RIGHT_INDEX);
|
|
||||||
if (r < 0)
|
|
||||||
fprintf(stderr, "Data save failed, code %d\n", r);
|
|
||||||
|
|
||||||
fp_print_data_free(data);
|
|
||||||
out_close:
|
|
||||||
fp_dev_close(dev);
|
|
||||||
out:
|
|
||||||
fp_exit();
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
EnrollData *enroll_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(FpPrint) print = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
print = fp_device_enroll_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
enroll_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
|
g_debug ("Device has storage, saving a print reference locally");
|
||||||
|
else
|
||||||
|
g_debug ("Device has not storage, saving print only locally");
|
||||||
|
|
||||||
|
/* Even if the device has storage, it may not be able to save all the
|
||||||
|
* metadata that the print contains, so we can always save a local copy
|
||||||
|
* containing the handle to the device print */
|
||||||
|
int r = print_data_save (print, enroll_data->finger,
|
||||||
|
enroll_data->update_fingerprint);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
g_warning ("Data save failed, code %d", r);
|
||||||
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Enroll failed with error %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
enroll_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_enroll_progress (FpDevice *device,
|
||||||
|
gint completed_stages,
|
||||||
|
FpPrint *print,
|
||||||
|
gpointer user_data,
|
||||||
|
GError *error)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Enroll stage %d of %d failed with error %s",
|
||||||
|
completed_stages,
|
||||||
|
fp_device_get_nr_enroll_stages (device),
|
||||||
|
error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print && fp_print_get_image (print) &&
|
||||||
|
print_image_save (print, "enrolled.pgm"))
|
||||||
|
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||||
|
|
||||||
|
printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages,
|
||||||
|
fp_device_get_nr_enroll_stages (device));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
should_update_fingerprint (void)
|
||||||
|
{
|
||||||
|
int update_choice;
|
||||||
|
gboolean update_fingerprint = FALSE;
|
||||||
|
|
||||||
|
printf ("Should an existing fingerprint be updated instead of being replaced (if present)? "
|
||||||
|
"Enter Y/y or N/n to make a choice.\n");
|
||||||
|
update_choice = getchar ();
|
||||||
|
if (update_choice == EOF)
|
||||||
|
{
|
||||||
|
g_warning ("EOF encountered while reading a character");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (update_choice)
|
||||||
|
{
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
update_fingerprint = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
update_fingerprint = FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_warning ("Invalid choice %c, should be Y/y or N/n.", update_choice);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return update_fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
EnrollData *enroll_data = user_data;
|
||||||
|
FpPrint *print_template;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
if (!fp_device_open_finish (dev, res, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to open device: %s", error->message);
|
||||||
|
g_main_loop_quit (enroll_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("Opened device.\n");
|
||||||
|
|
||||||
|
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_UPDATE_PRINT))
|
||||||
|
{
|
||||||
|
printf ("The device supports fingerprint updates.\n");
|
||||||
|
enroll_data->update_fingerprint = should_update_fingerprint ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf ("The device doesn't support fingerprint updates. Old prints will be erased.\n");
|
||||||
|
enroll_data->update_fingerprint = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("It's now time to enroll your finger.\n\n");
|
||||||
|
printf ("You will need to successfully scan your %s finger %d times to "
|
||||||
|
"complete the process.\n\n", finger_to_string (enroll_data->finger),
|
||||||
|
fp_device_get_nr_enroll_stages (dev));
|
||||||
|
printf ("Scan your finger now.\n");
|
||||||
|
|
||||||
|
print_template = print_create_template (dev, enroll_data->finger, enroll_data->update_fingerprint);
|
||||||
|
fp_device_enroll (dev, print_template, enroll_data->cancellable,
|
||||||
|
on_enroll_progress, NULL, NULL,
|
||||||
|
(GAsyncReadyCallback) on_enroll_completed,
|
||||||
|
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
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FpContext) ctx = NULL;
|
||||||
|
g_autoptr(EnrollData) enroll_data = NULL;
|
||||||
|
GPtrArray *devices;
|
||||||
|
FpDevice *dev;
|
||||||
|
FpFinger finger;
|
||||||
|
|
||||||
|
g_print ("This program will enroll the selected finger overwriting any print for the same"
|
||||||
|
" finger that was enrolled previously. Fingerprint updates without erasing old data"
|
||||||
|
" are possible on devices supporting that. Ctrl+C interrupts program execution.\n");
|
||||||
|
|
||||||
|
g_print ("Choose the finger to enroll:\n");
|
||||||
|
finger = finger_chooser ();
|
||||||
|
|
||||||
|
if (finger == FP_FINGER_UNKNOWN)
|
||||||
|
{
|
||||||
|
g_warning ("Unknown finger selected");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
enroll_data = g_new0 (EnrollData, 1);
|
||||||
|
enroll_data->finger = finger;
|
||||||
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
|
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, enroll_data->cancellable,
|
||||||
|
(GAsyncReadyCallback) on_device_opened,
|
||||||
|
enroll_data);
|
||||||
|
|
||||||
|
g_main_loop_run (enroll_data->loop);
|
||||||
|
|
||||||
|
return enroll_data->ret_value;
|
||||||
|
}
|
||||||
|
|||||||
321
examples/identify.c
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
const GDate *date;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
date = fp_print_get_enroll_date (matched_print);
|
||||||
|
if (date && g_date_valid (date))
|
||||||
|
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
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* Example libfprint image capture program
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
|
||||||
struct fp_driver *drv;
|
|
||||||
if (!ddev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int r = 1;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
struct fp_dscv_dev **discovered_devs;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_img *img = NULL;
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
|
||||||
if (!discovered_devs) {
|
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
|
||||||
if (!ddev) {
|
|
||||||
fprintf(stderr, "No devices detected.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = fp_dev_open(ddev);
|
|
||||||
fp_dscv_devs_free(discovered_devs);
|
|
||||||
if (!dev) {
|
|
||||||
fprintf(stderr, "Could not open device.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_dev_supports_imaging(dev)) {
|
|
||||||
fprintf(stderr, "this device does not have imaging capabilities.\n");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Opened device. It's now time to scan your finger.\n\n");
|
|
||||||
|
|
||||||
r = fp_dev_img_capture(dev, 0, &img);
|
|
||||||
if (r) {
|
|
||||||
fprintf(stderr, "image capture failed, code %d\n", r);
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fp_img_save_to_file(img, "finger.pgm");
|
|
||||||
if (r) {
|
|
||||||
fprintf(stderr, "img save failed, code %d\n", r);
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_img_standardize(img);
|
|
||||||
r = fp_img_save_to_file(img, "finger_standardized.pgm");
|
|
||||||
fp_img_free(img);
|
|
||||||
if (r) {
|
|
||||||
fprintf(stderr, "standardized img save failed, code %d\n", r);
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = 0;
|
|
||||||
out_close:
|
|
||||||
fp_dev_close(dev);
|
|
||||||
out:
|
|
||||||
fp_exit();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
/*
|
|
||||||
* Example libfprint continuous image capture program
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/extensions/Xvlib.h>
|
|
||||||
|
|
||||||
#define FORMAT 0x32595559
|
|
||||||
|
|
||||||
static int adaptor = -1;
|
|
||||||
static char *framebuffer = NULL;
|
|
||||||
|
|
||||||
static Display *display = NULL;
|
|
||||||
static Window window=(Window)NULL;
|
|
||||||
static XvImage *xv_image = NULL;
|
|
||||||
static XvAdaptorInfo *info;
|
|
||||||
static GC gc;
|
|
||||||
static int connection = -1;
|
|
||||||
|
|
||||||
/* based on macro by Bart Nabbe */
|
|
||||||
#define GREY2YUV(grey, y, u, v)\
|
|
||||||
y = (9798*grey + 19235*grey + 3736*grey) / 32768;\
|
|
||||||
u = (-4784*grey - 9437*grey + 14221*grey) / 32768 + 128;\
|
|
||||||
v = (20218*grey - 16941*grey - 3277*grey) / 32768 + 128;\
|
|
||||||
y = y < 0 ? 0 : y;\
|
|
||||||
u = u < 0 ? 0 : u;\
|
|
||||||
v = v < 0 ? 0 : v;\
|
|
||||||
y = y > 255 ? 255 : y;\
|
|
||||||
u = u > 255 ? 255 : u;\
|
|
||||||
v = v > 255 ? 255 : v
|
|
||||||
|
|
||||||
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
|
|
||||||
int i, j;
|
|
||||||
int y0, y1, u0, u1, v0, v1;
|
|
||||||
int gval;
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i < num; i += 2, j += 4)
|
|
||||||
{
|
|
||||||
gval = grey[i];
|
|
||||||
GREY2YUV (gval, y0, u0 , v0);
|
|
||||||
gval = grey[i + 1];
|
|
||||||
GREY2YUV (gval, y1, u1 , v1);
|
|
||||||
YUV[j + 0] = y0;
|
|
||||||
YUV[j + 1] = (u0+u1)/2;
|
|
||||||
YUV[j + 2] = y1;
|
|
||||||
YUV[j + 3] = (v0+v1)/2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_frame(struct fp_img *img)
|
|
||||||
{
|
|
||||||
int width = fp_img_get_width(img);
|
|
||||||
int height = fp_img_get_height(img);
|
|
||||||
unsigned char *data = fp_img_get_data(img);
|
|
||||||
|
|
||||||
if (adaptor < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
grey2yuy2(data, framebuffer, width * height);
|
|
||||||
xv_image = XvCreateImage(display, info[adaptor].base_id, FORMAT,
|
|
||||||
framebuffer, width, height);
|
|
||||||
XvPutImage(display, info[adaptor].base_id, window, gc, xv_image,
|
|
||||||
0, 0, width, height, 0, 0, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void QueryXv()
|
|
||||||
{
|
|
||||||
unsigned int num_adaptors;
|
|
||||||
int num_formats;
|
|
||||||
XvImageFormatValues *formats = NULL;
|
|
||||||
int i,j;
|
|
||||||
char xv_name[5];
|
|
||||||
|
|
||||||
XvQueryAdaptors(display, DefaultRootWindow(display), &num_adaptors,
|
|
||||||
&info);
|
|
||||||
|
|
||||||
for(i = 0; i < num_adaptors; i++) {
|
|
||||||
formats = XvListImageFormats(display, info[i].base_id,
|
|
||||||
&num_formats);
|
|
||||||
for(j = 0; j < num_formats; j++) {
|
|
||||||
xv_name[4] = 0;
|
|
||||||
memcpy(xv_name, &formats[j].id, 4);
|
|
||||||
if(formats[j].id == FORMAT) {
|
|
||||||
printf("using Xv format 0x%x %s %s\n",
|
|
||||||
formats[j].id, xv_name,
|
|
||||||
(formats[j].format==XvPacked)
|
|
||||||
? "packed" : "planar");
|
|
||||||
if (adaptor < 0)
|
|
||||||
adaptor = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XFree(formats);
|
|
||||||
if (adaptor < 0)
|
|
||||||
printf("No suitable Xv adaptor found\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
|
||||||
struct fp_driver *drv;
|
|
||||||
if (!ddev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int r = 1;
|
|
||||||
XEvent xev;
|
|
||||||
XGCValues xgcv;
|
|
||||||
long background=0x010203;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
struct fp_dscv_dev **discovered_devs;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
int img_width;
|
|
||||||
int img_height;
|
|
||||||
int standardize = 0;
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
|
||||||
if (!discovered_devs) {
|
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
|
||||||
if (!ddev) {
|
|
||||||
fprintf(stderr, "No devices detected.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = fp_dev_open(ddev);
|
|
||||||
fp_dscv_devs_free(discovered_devs);
|
|
||||||
if (!dev) {
|
|
||||||
fprintf(stderr, "Could not open device.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_dev_supports_imaging(dev)) {
|
|
||||||
fprintf(stderr, "this device does not have imaging capabilities.\n");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
img_width = fp_dev_get_img_width(dev);
|
|
||||||
img_height = fp_dev_get_img_height(dev);
|
|
||||||
if (img_width <= 0 || img_height <= 0) {
|
|
||||||
fprintf(stderr, "this device returns images with variable dimensions,"
|
|
||||||
" this example does not support that.\n");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
framebuffer = malloc(img_width * img_height * 2);
|
|
||||||
if (!framebuffer)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
/* make the window */
|
|
||||||
display = XOpenDisplay(getenv("DISPLAY"));
|
|
||||||
if(display == NULL) {
|
|
||||||
fprintf(stderr,"Could not open display \"%s\"\n",
|
|
||||||
getenv("DISPLAY"));
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryXv();
|
|
||||||
|
|
||||||
if (adaptor < 0)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
|
|
||||||
img_width, img_height, 0,
|
|
||||||
WhitePixel(display, DefaultScreen(display)), background);
|
|
||||||
|
|
||||||
XSelectInput(display, window, StructureNotifyMask | KeyPressMask);
|
|
||||||
XMapWindow(display, window);
|
|
||||||
connection = ConnectionNumber(display);
|
|
||||||
|
|
||||||
gc = XCreateGC(display, window, 0, &xgcv);
|
|
||||||
|
|
||||||
printf("Press S to toggle standardized mode, Q to quit\n");
|
|
||||||
|
|
||||||
while (1) { /* event loop */
|
|
||||||
struct fp_img *img;
|
|
||||||
|
|
||||||
r = fp_dev_img_capture(dev, 1, &img);
|
|
||||||
if (r) {
|
|
||||||
fprintf(stderr, "image capture failed, code %d\n", r);
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
if (standardize)
|
|
||||||
fp_img_standardize(img);
|
|
||||||
|
|
||||||
display_frame(img);
|
|
||||||
fp_img_free(img);
|
|
||||||
XFlush(display);
|
|
||||||
|
|
||||||
while (XPending(display) > 0) {
|
|
||||||
XNextEvent(display, &xev);
|
|
||||||
if (xev.type != KeyPress)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (XKeycodeToKeysym(display, xev.xkey.keycode, 0)) {
|
|
||||||
case XK_q:
|
|
||||||
case XK_Q:
|
|
||||||
r = 0;
|
|
||||||
goto out_close;
|
|
||||||
break;
|
|
||||||
case XK_s:
|
|
||||||
case XK_S:
|
|
||||||
standardize = !standardize;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} /* XPending */
|
|
||||||
}
|
|
||||||
|
|
||||||
r = 0;
|
|
||||||
out_close:
|
|
||||||
if (framebuffer)
|
|
||||||
free(framebuffer);
|
|
||||||
fp_dev_close(dev);
|
|
||||||
if ((void *) window != NULL)
|
|
||||||
XUnmapWindow(display, window);
|
|
||||||
if (display != NULL)
|
|
||||||
XFlush(display);
|
|
||||||
out:
|
|
||||||
fp_exit();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
283
examples/manage-prints.c
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* Example fingerprint device prints listing and deletion
|
||||||
|
* Enrolls your right index finger and saves the print to disk
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-mange-prints"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
typedef struct _ListData
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
int ret_value;
|
||||||
|
GList *to_delete;
|
||||||
|
gboolean any_failed;
|
||||||
|
} ListData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_data_free (ListData *list_data)
|
||||||
|
{
|
||||||
|
g_list_free_full (list_data->to_delete, g_object_unref);
|
||||||
|
g_main_loop_unref (list_data->loop);
|
||||||
|
g_free (list_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free)
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_closed (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ListData *list_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 (list_data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _DeleteData
|
||||||
|
{
|
||||||
|
ListData *list_data;
|
||||||
|
FpPrint *print;
|
||||||
|
} DeleteData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_data_free (DeleteData *delete_data)
|
||||||
|
{
|
||||||
|
g_object_unref (delete_data->print);
|
||||||
|
g_free (delete_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free);
|
||||||
|
|
||||||
|
static void on_print_deleted (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_next_print (FpDevice *dev,
|
||||||
|
ListData *list_data)
|
||||||
|
{
|
||||||
|
FpPrint *print;
|
||||||
|
|
||||||
|
g_assert_nonnull (list_data->to_delete);
|
||||||
|
print = list_data->to_delete->data;
|
||||||
|
|
||||||
|
g_debug ("Deleting print %s", fp_print_get_description (print));
|
||||||
|
fp_device_delete_print (dev, print, NULL,
|
||||||
|
(GAsyncReadyCallback) on_print_deleted, list_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_print_deleted (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ListData *list_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(FpPrint) print = NULL;
|
||||||
|
GList *deleted_link;
|
||||||
|
|
||||||
|
fp_device_delete_print_finish (dev, res, &error);
|
||||||
|
|
||||||
|
deleted_link = list_data->to_delete;
|
||||||
|
print = g_steal_pointer (&deleted_link->data);
|
||||||
|
list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to remove print %s: %s",
|
||||||
|
fp_print_get_description (print), error->message);
|
||||||
|
list_data->any_failed = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Deleted print %s from device", fp_print_get_description (print));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_data->to_delete != NULL)
|
||||||
|
{
|
||||||
|
delete_next_print (dev, list_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!list_data->any_failed)
|
||||||
|
list_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
list_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_list_completed (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ListData *list_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GPtrArray) prints = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
prints = fp_device_list_prints_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
g_print ("Device contains %u prints\n", prints->len);
|
||||||
|
|
||||||
|
for (i = 0; i < prints->len; ++i)
|
||||||
|
{
|
||||||
|
FpPrint * print = prints->pdata[i];
|
||||||
|
const GDate *date = fp_print_get_enroll_date (print);
|
||||||
|
|
||||||
|
g_print ("[%d] Print of %s finger for username %s", i + 1,
|
||||||
|
finger_to_string (fp_print_get_finger (print)),
|
||||||
|
fp_print_get_username (print));
|
||||||
|
|
||||||
|
if (date && g_date_valid (date))
|
||||||
|
{
|
||||||
|
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
|
||||||
|
g_print (", enrolled on %s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print (". Description: %s\n", fp_print_get_description (print));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prints->len)
|
||||||
|
{
|
||||||
|
gint64 idx = 0;
|
||||||
|
|
||||||
|
g_print ("Want to delete saved print? [<number>/A/n]\n> ");
|
||||||
|
if (fgets (buf, 3, stdin))
|
||||||
|
idx = g_ascii_strtoll (buf, NULL, 10);
|
||||||
|
|
||||||
|
if (idx > 0 && idx <= prints->len)
|
||||||
|
{
|
||||||
|
FpPrint *print = prints->pdata[idx - 1];
|
||||||
|
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
||||||
|
g_object_ref (print));
|
||||||
|
}
|
||||||
|
else if (buf[0] == 'A')
|
||||||
|
{
|
||||||
|
for (i = 0; i < prints->len; ++i)
|
||||||
|
{
|
||||||
|
FpPrint *print = prints->pdata[i];
|
||||||
|
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
||||||
|
g_object_ref (print));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (buf[0] == 'n' || buf[0] == 'N')
|
||||||
|
list_data->ret_value = EXIT_SUCCESS;
|
||||||
|
else
|
||||||
|
g_warning ("Invalid finger selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_data->to_delete)
|
||||||
|
delete_next_print (dev, list_data);
|
||||||
|
else
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
list_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Getting prints failed with error %s", error->message);
|
||||||
|
g_main_loop_quit (list_data->loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_opened (FpDevice *dev,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ListData *list_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);
|
||||||
|
g_main_loop_quit (list_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
||||||
|
{
|
||||||
|
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
||||||
|
g_main_loop_quit (list_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_device_list_prints (dev, NULL,
|
||||||
|
(GAsyncReadyCallback) on_list_completed, list_data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FpContext) ctx = NULL;
|
||||||
|
g_autoptr(ListData) list_data = NULL;
|
||||||
|
GPtrArray *devices;
|
||||||
|
FpDevice *dev;
|
||||||
|
|
||||||
|
g_print ("This program will report the prints saved in device\n");
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_data = g_new0 (ListData, 1);
|
||||||
|
list_data->ret_value = EXIT_FAILURE;
|
||||||
|
list_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data);
|
||||||
|
|
||||||
|
g_main_loop_run (list_data->loop);
|
||||||
|
|
||||||
|
return list_data->ret_value;
|
||||||
|
}
|
||||||
29
examples/meson.build
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
examples = [
|
||||||
|
'enroll',
|
||||||
|
'identify',
|
||||||
|
'img-capture',
|
||||||
|
'manage-prints',
|
||||||
|
'verify',
|
||||||
|
'clear-storage',
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach example: examples
|
||||||
|
executable(example,
|
||||||
|
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||||
|
dependencies: [
|
||||||
|
libfprint_dep,
|
||||||
|
glib_dep,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
executable('cpp-test',
|
||||||
|
'cpp-test.cpp',
|
||||||
|
dependencies: libfprint_dep,
|
||||||
|
)
|
||||||
|
|
||||||
|
if installed_tests
|
||||||
|
install_subdir('prints',
|
||||||
|
install_dir: installed_tests_testdir)
|
||||||
|
endif
|
||||||
3
examples/prints/README
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
These are example images from NIST and are in the public domain.
|
||||||
|
|
||||||
|
The PNG files have been generated by using the greyscale data as a mask.
|
||||||
BIN
examples/prints/arch.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
examples/prints/arch.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
examples/prints/loop-right.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
examples/prints/loop-right.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
examples/prints/tented_arch.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
examples/prints/tented_arch.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
examples/prints/whorl.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
examples/prints/whorl.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
111
examples/sendvirtimg.py
Executable file
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# This script can be used together with the virtual_imgdev to simulate an
|
||||||
|
# image based fingerprint reader.
|
||||||
|
#
|
||||||
|
# To use, set the FP_VIRTUAL_IMAGE environment variable for both the
|
||||||
|
# libfprint using program (e.g. fprintd) and this script.
|
||||||
|
#
|
||||||
|
# Usually this would work by adding it into the systemd unit file. The
|
||||||
|
# best way of doing so is to create
|
||||||
|
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
|
||||||
|
#
|
||||||
|
# [Service]
|
||||||
|
# RuntimeDirectory=fprint
|
||||||
|
# Environment=FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock
|
||||||
|
# Environment=G_MESSAGES_DEBUG=all
|
||||||
|
# ReadWritePaths=$RUNTIME_DIR
|
||||||
|
#
|
||||||
|
# After that run:
|
||||||
|
#
|
||||||
|
# systemctl daemon-reload
|
||||||
|
# systemctl restart fprintd.service
|
||||||
|
#
|
||||||
|
# You may also need to disable selinux.
|
||||||
|
#
|
||||||
|
# Then run this script with e.g.
|
||||||
|
# FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import cairo
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Just copied from the C file, we could also use the introspection data for
|
||||||
|
# this. Also, most of them do *not* make any sense.
|
||||||
|
commands = {
|
||||||
|
'retry' : struct.pack('ii', -1, 0),
|
||||||
|
'retry-too-short' : struct.pack('ii', -1, 1),
|
||||||
|
'retry-center-finger' : struct.pack('ii', -1, 2),
|
||||||
|
'retry-remove-finger' : struct.pack('ii', -1, 3),
|
||||||
|
|
||||||
|
'error' : struct.pack('ii', -2, 0),
|
||||||
|
'error-not-supported' : struct.pack('ii', -2, 1),
|
||||||
|
'error-not-open' : struct.pack('ii', -2, 2),
|
||||||
|
'error-already-open' : struct.pack('ii', -2, 3),
|
||||||
|
'error-busy' : struct.pack('ii', -2, 4),
|
||||||
|
'error-proto' : struct.pack('ii', -2, 5),
|
||||||
|
'error-data-invalid' : struct.pack('ii', -2, 6),
|
||||||
|
'error-data-not-found' : struct.pack('ii', -2, 7),
|
||||||
|
'error-data-full' : struct.pack('ii', -2, 8),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if sys.argv[1] in commands:
|
||||||
|
command = commands[sys.argv[1]]
|
||||||
|
else:
|
||||||
|
png = cairo.ImageSurface.create_from_png(sys.argv[1])
|
||||||
|
|
||||||
|
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
|
||||||
|
w = png.get_width()
|
||||||
|
h = png.get_height()
|
||||||
|
w = (w + 3) // 4 * 4
|
||||||
|
h = (h + 3) // 4 * 4
|
||||||
|
img = cairo.ImageSurface(cairo.Format.A8, w, h)
|
||||||
|
cr = cairo.Context(img)
|
||||||
|
|
||||||
|
cr.set_source_rgba(1, 1, 1, 1)
|
||||||
|
cr.paint()
|
||||||
|
|
||||||
|
cr.set_source_rgba(0, 0, 0, 0)
|
||||||
|
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||||
|
|
||||||
|
cr.set_source_surface(png)
|
||||||
|
cr.paint()
|
||||||
|
|
||||||
|
mem = img.get_data()
|
||||||
|
mem = mem.tobytes()
|
||||||
|
assert len(mem) == img.get_width() * img.get_height()
|
||||||
|
|
||||||
|
command = struct.pack('ii', img.get_width(), img.get_height())
|
||||||
|
command += mem
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def write_dbg_img():
|
||||||
|
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
|
||||||
|
dbg_cr = cairo.Context(dbg_img_rgb)
|
||||||
|
dbg_cr.set_source_rgb(0, 0, 0)
|
||||||
|
dbg_cr.paint()
|
||||||
|
dbg_cr.set_source_rgb(1, 1, 1)
|
||||||
|
dbg_cr.mask_surface(img, 0, 0)
|
||||||
|
|
||||||
|
dbg_img_rgb.write_to_png('/tmp/test.png')
|
||||||
|
|
||||||
|
#write_dbg_img()
|
||||||
|
|
||||||
|
# Send image through socket
|
||||||
|
sockaddr = os.environ['FP_VIRTUAL_IMAGE']
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.connect(sockaddr)
|
||||||
|
|
||||||
|
sock.sendall(command)
|
||||||
|
|
||||||
354
examples/storage.c
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* Trivial storage driver for example programs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
* Copyright (C) 2019-2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* 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-storage"
|
||||||
|
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
#include <libfprint/fpi-compat.h>
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define STORAGE_FILE "test-storage.variant"
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
|
||||||
|
{
|
||||||
|
const char *driver;
|
||||||
|
const char *dev_id;
|
||||||
|
|
||||||
|
if (print)
|
||||||
|
{
|
||||||
|
driver = fp_print_get_driver (print);
|
||||||
|
dev_id = fp_print_get_device_id (print);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
driver = fp_device_get_driver (dev);
|
||||||
|
dev_id = fp_device_get_device_id (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_strdup_printf ("%s/%s/%x",
|
||||||
|
driver,
|
||||||
|
dev_id,
|
||||||
|
finger);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_print_prefix_for_device (FpDevice *dev)
|
||||||
|
{
|
||||||
|
const char *driver;
|
||||||
|
const char *dev_id;
|
||||||
|
|
||||||
|
driver = fp_device_get_driver (dev);
|
||||||
|
dev_id = fp_device_get_device_id (dev);
|
||||||
|
|
||||||
|
return g_strdup_printf ("%s/%s/", driver, dev_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantDict *
|
||||||
|
load_data (void)
|
||||||
|
{
|
||||||
|
GVariantDict *res;
|
||||||
|
GVariant *var;
|
||||||
|
gchar *contents = NULL;
|
||||||
|
gsize length = 0;
|
||||||
|
|
||||||
|
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
|
||||||
|
{
|
||||||
|
g_warning ("Error loading storage, assuming it is empty");
|
||||||
|
return g_variant_dict_new (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT,
|
||||||
|
contents,
|
||||||
|
length,
|
||||||
|
FALSE,
|
||||||
|
g_free,
|
||||||
|
contents);
|
||||||
|
|
||||||
|
res = g_variant_dict_new (var);
|
||||||
|
g_variant_unref (var);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
save_data (GVariant *data)
|
||||||
|
{
|
||||||
|
const gchar *contents = NULL;
|
||||||
|
gsize length;
|
||||||
|
|
||||||
|
length = g_variant_get_size (data);
|
||||||
|
contents = (gchar *) g_variant_get_data (data);
|
||||||
|
|
||||||
|
if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL))
|
||||||
|
{
|
||||||
|
g_warning ("Error saving storage,!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_variant_ref_sink (data);
|
||||||
|
g_variant_unref (data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FpPrint *
|
||||||
|
load_print_from_data (GVariant *data)
|
||||||
|
{
|
||||||
|
const guchar *stored_data = NULL;
|
||||||
|
gsize stored_len;
|
||||||
|
FpPrint *print;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
stored_data = (const guchar *) g_variant_get_fixed_array (data, &stored_len, 1);
|
||||||
|
print = fp_print_deserialize (stored_data, stored_len, &error);
|
||||||
|
if (error)
|
||||||
|
g_warning ("Error deserializing data: %s", error->message);
|
||||||
|
return print;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
print_data_save (FpPrint *print, FpFinger finger, gboolean update_fingerprint)
|
||||||
|
{
|
||||||
|
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GVariantDict) dict = NULL;
|
||||||
|
g_autofree guchar *data = NULL;
|
||||||
|
GVariant *val;
|
||||||
|
gsize size;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
dict = load_data ();
|
||||||
|
|
||||||
|
fp_print_serialize (print, &data, &size, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Error serializing data: %s", error->message);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), data, size, 1);
|
||||||
|
g_variant_dict_insert_value (dict, descr, val);
|
||||||
|
|
||||||
|
res = save_data (g_variant_dict_end (dict));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FpPrint *
|
||||||
|
print_data_load (FpDevice *dev, FpFinger finger)
|
||||||
|
{
|
||||||
|
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
|
||||||
|
|
||||||
|
g_autoptr(GVariant) val = NULL;
|
||||||
|
g_autoptr(GVariantDict) dict = NULL;
|
||||||
|
|
||||||
|
dict = load_data ();
|
||||||
|
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
return load_print_from_data (val);
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
dev_prefix = get_print_prefix_for_device (dev);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
clear_saved_prints (FpDevice *dev,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GVariantDict) dict = NULL;
|
||||||
|
g_autoptr(GVariantDict) updated_dict = NULL;
|
||||||
|
g_autoptr(GVariant) dict_variant = NULL;
|
||||||
|
g_autofree char *dev_prefix = NULL;
|
||||||
|
GPtrArray *print_keys;
|
||||||
|
GVariantIter iter;
|
||||||
|
GVariant *value;
|
||||||
|
gchar *key;
|
||||||
|
|
||||||
|
print_keys = g_ptr_array_new_with_free_func (g_free);
|
||||||
|
dict = load_data ();
|
||||||
|
dict_variant = g_variant_dict_end (dict);
|
||||||
|
dev_prefix = get_print_prefix_for_device (dev);
|
||||||
|
|
||||||
|
g_variant_iter_init (&iter, dict_variant);
|
||||||
|
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
||||||
|
{
|
||||||
|
if (!g_str_has_prefix (key, dev_prefix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_ptr_array_add (print_keys, g_strdup (key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!print_keys->len)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
updated_dict = load_data ();
|
||||||
|
|
||||||
|
for (guint i = 0; i < print_keys->len; ++i)
|
||||||
|
{
|
||||||
|
key = g_ptr_array_index (print_keys, i);
|
||||||
|
if (!g_variant_dict_remove (updated_dict, key))
|
||||||
|
{
|
||||||
|
g_warning ("Print '%s' key not found!", key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug ("Dropping print '%s' from gallery", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
save_data (g_variant_dict_end (updated_dict));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FpPrint *
|
||||||
|
print_create_template (FpDevice *dev, FpFinger finger, gboolean load_existing)
|
||||||
|
{
|
||||||
|
g_autoptr(GVariantDict) dict = NULL;
|
||||||
|
g_autoptr(GDateTime) datetime = NULL;
|
||||||
|
g_autoptr(GDate) date = NULL;
|
||||||
|
g_autoptr(GVariant) existing_val = NULL;
|
||||||
|
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
|
||||||
|
FpPrint *template = NULL;
|
||||||
|
gint year, month, day;
|
||||||
|
|
||||||
|
if (load_existing)
|
||||||
|
{
|
||||||
|
dict = load_data ();
|
||||||
|
existing_val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
|
||||||
|
if (existing_val != NULL)
|
||||||
|
template = load_print_from_data (existing_val);
|
||||||
|
}
|
||||||
|
if (template == NULL)
|
||||||
|
{
|
||||||
|
template = fp_print_new (dev);
|
||||||
|
fp_print_set_finger (template, finger);
|
||||||
|
fp_print_set_username (template, g_get_user_name ());
|
||||||
|
}
|
||||||
|
|
||||||
|
datetime = g_date_time_new_now_local ();
|
||||||
|
g_date_time_get_ymd (datetime, &year, &month, &day);
|
||||||
|
date = g_date_new_dmy (day, month, year);
|
||||||
|
fp_print_set_enroll_date (template, date);
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
save_image_to_pgm (FpImage *img, const char *path)
|
||||||
|
{
|
||||||
|
FILE *fd = fopen (path, "w");
|
||||||
|
size_t write_size;
|
||||||
|
const guchar *data = fp_image_get_data (img, &write_size);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
g_warning ("could not open '%s' for writing: %d", path, errno);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fprintf (fd, "P5 %d %d 255\n",
|
||||||
|
fp_image_get_width (img), fp_image_get_height (img));
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
fclose (fd);
|
||||||
|
g_critical ("pgm header write failed, error %d", r);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fwrite (data, 1, write_size, fd);
|
||||||
|
if (r < write_size)
|
||||||
|
{
|
||||||
|
fclose (fd);
|
||||||
|
g_critical ("short write (%d)", r);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (fd);
|
||||||
|
g_debug ("written to '%s'", path);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
print_image_save (FpPrint *print, const char *path)
|
||||||
|
{
|
||||||
|
FpImage *img = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
|
||||||
|
g_return_val_if_fail (path != NULL, FALSE);
|
||||||
|
|
||||||
|
img = fp_print_get_image (print);
|
||||||
|
|
||||||
|
if (img)
|
||||||
|
return save_image_to_pgm (img, path);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
40
examples/storage.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Trivial storage driver for example programs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
int print_data_save (FpPrint *print,
|
||||||
|
FpFinger finger,
|
||||||
|
gboolean update_fingerprint);
|
||||||
|
FpPrint * print_data_load (FpDevice *dev,
|
||||||
|
FpFinger finger);
|
||||||
|
GPtrArray * gallery_data_load (FpDevice *dev);
|
||||||
|
gboolean clear_saved_prints (FpDevice *dev,
|
||||||
|
GError **error);
|
||||||
|
FpPrint * print_create_template (FpDevice *dev,
|
||||||
|
FpFinger finger,
|
||||||
|
const gboolean load_existing);
|
||||||
|
gboolean print_image_save (FpPrint *print,
|
||||||
|
const char *path);
|
||||||
|
gboolean save_image_to_pgm (FpImage *img,
|
||||||
|
const char *path);
|
||||||
128
examples/utilities.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Utilities for example programs
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-utilities"
|
||||||
|
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
FpDevice *
|
||||||
|
discover_device (GPtrArray * devices)
|
||||||
|
{
|
||||||
|
FpDevice *dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!devices->len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (devices->len == 1)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_print ("Multiple devices found, choose one\n");
|
||||||
|
|
||||||
|
for (i = 0; i < devices->len; ++i)
|
||||||
|
{
|
||||||
|
dev = g_ptr_array_index (devices, i);
|
||||||
|
g_print ("[%d] %s (%s) - driver %s\n", i,
|
||||||
|
fp_device_get_device_id (dev), fp_device_get_name (dev),
|
||||||
|
fp_device_get_driver (dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("> ");
|
||||||
|
if (!scanf ("%d%*c", &i))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (i < 0 || i >= devices->len)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = g_ptr_array_index (devices, i);
|
||||||
|
g_print ("Selected device %s (%s) claimed by %s driver\n",
|
||||||
|
fp_device_get_device_id (dev), fp_device_get_name (dev),
|
||||||
|
fp_device_get_driver (dev));
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
finger_to_string (FpFinger finger)
|
||||||
|
{
|
||||||
|
switch (finger)
|
||||||
|
{
|
||||||
|
case FP_FINGER_LEFT_THUMB:
|
||||||
|
return "left thumb";
|
||||||
|
|
||||||
|
case FP_FINGER_LEFT_INDEX:
|
||||||
|
return "left index";
|
||||||
|
|
||||||
|
case FP_FINGER_LEFT_MIDDLE:
|
||||||
|
return "left middle";
|
||||||
|
|
||||||
|
case FP_FINGER_LEFT_RING:
|
||||||
|
return "left ring";
|
||||||
|
|
||||||
|
case FP_FINGER_LEFT_LITTLE:
|
||||||
|
return "left little";
|
||||||
|
|
||||||
|
case FP_FINGER_RIGHT_THUMB:
|
||||||
|
return "right thumb";
|
||||||
|
|
||||||
|
case FP_FINGER_RIGHT_INDEX:
|
||||||
|
return "right index";
|
||||||
|
|
||||||
|
case FP_FINGER_RIGHT_MIDDLE:
|
||||||
|
return "right middle";
|
||||||
|
|
||||||
|
case FP_FINGER_RIGHT_RING:
|
||||||
|
return "right ring";
|
||||||
|
|
||||||
|
case FP_FINGER_RIGHT_LITTLE:
|
||||||
|
return "right little";
|
||||||
|
|
||||||
|
case FP_FINGER_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FpFinger
|
||||||
|
finger_chooser (void)
|
||||||
|
{
|
||||||
|
int i = FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
|
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i)
|
||||||
|
g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i));
|
||||||
|
|
||||||
|
g_print ("> ");
|
||||||
|
if (!scanf ("%d%*c", &i))
|
||||||
|
return FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
|
i += FP_FINGER_FIRST;
|
||||||
|
|
||||||
|
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
|
||||||
|
return FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
25
examples/utilities.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Trivial storage driver for example programs
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
FpDevice * discover_device (GPtrArray *devices);
|
||||||
|
FpFinger finger_chooser (void);
|
||||||
|
const char * finger_to_string (FpFinger finger);
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Example fingerprint verification program, which verifies the right index
|
* Example fingerprint verification program, which verifies the
|
||||||
* finger which has been previously enrolled to disk.
|
* finger which has been previously enrolled 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>
|
||||||
*
|
*
|
||||||
* 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,128 +19,344 @@
|
|||||||
* 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 <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
#include "storage.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
typedef struct _VerifyData
|
||||||
{
|
{
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
GMainLoop *loop;
|
||||||
struct fp_driver *drv;
|
GCancellable *cancellable;
|
||||||
if (!ddev)
|
unsigned int sigint_handler;
|
||||||
return NULL;
|
FpFinger finger;
|
||||||
|
int ret_value;
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
} VerifyData;
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
|
||||||
return ddev;
|
static void
|
||||||
|
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_free (verify_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
VerifyData *verify_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 (verify_data->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
static void
|
||||||
|
verify_quit (FpDevice *dev,
|
||||||
|
VerifyData *verify_data)
|
||||||
{
|
{
|
||||||
int r;
|
if (!fp_device_is_open (dev))
|
||||||
|
{
|
||||||
|
g_main_loop_quit (verify_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
|
||||||
struct fp_img *img = NULL;
|
|
||||||
|
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
|
||||||
r = fp_verify_finger_img(dev, data, &img);
|
|
||||||
if (img) {
|
|
||||||
fp_img_save_to_file(img, "verify.pgm");
|
|
||||||
printf("Wrote scanned image to verify.pgm\n");
|
|
||||||
fp_img_free(img);
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
printf("verification failed with error %d :(\n", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
switch (r) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
printf("NO MATCH!\n");
|
|
||||||
return 0;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
printf("MATCH!\n");
|
|
||||||
return 0;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
printf("Scan didn't quite work. Please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
printf("Swipe was too short, please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
printf("Please center your finger on the sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
printf("Please remove finger from the sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
static void start_verification (FpDevice *dev,
|
||||||
|
VerifyData *verify_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
{
|
{
|
||||||
int r = 1;
|
VerifyData *verify_data = user_data;
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
struct fp_dscv_dev **discovered_devs;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
|
|
||||||
r = fp_init();
|
g_autoptr(FpPrint) print = NULL;
|
||||||
if (r < 0) {
|
g_autoptr(GError) error = NULL;
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
char buffer[20];
|
||||||
exit(1);
|
gboolean match;
|
||||||
}
|
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
||||||
if (!discovered_devs) {
|
{
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
g_warning ("Failed to verify print: %s", error->message);
|
||||||
goto out;
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
if (error->domain != FP_DEVICE_RETRY)
|
||||||
if (!ddev) {
|
{
|
||||||
fprintf(stderr, "No devices detected.\n");
|
verify_quit (dev, verify_data);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dev = fp_dev_open(ddev);
|
g_print ("Verify again? [Y/n]? ");
|
||||||
fp_dscv_devs_free(discovered_devs);
|
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||||
if (!dev) {
|
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
||||||
fprintf(stderr, "Could not open device.\n");
|
{
|
||||||
goto out;
|
start_verification (dev, verify_data);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
printf("Opened device. Loading previously enrolled right index finger "
|
verify_quit (dev, verify_data);
|
||||||
"data...\n");
|
|
||||||
|
|
||||||
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
|
|
||||||
if (r != 0) {
|
|
||||||
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
|
|
||||||
fprintf(stderr, "Did you remember to enroll your right index finger "
|
|
||||||
"first?\n");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Print loaded. Time to verify!\n");
|
|
||||||
do {
|
|
||||||
char buffer[20];
|
|
||||||
|
|
||||||
verify(dev, data);
|
|
||||||
printf("Verify again? [Y/n]? ");
|
|
||||||
fgets(buffer, sizeof(buffer), stdin);
|
|
||||||
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
|
|
||||||
break;
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
fp_print_data_free(data);
|
|
||||||
out_close:
|
|
||||||
fp_dev_close(dev);
|
|
||||||
out:
|
|
||||||
fp_exit();
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const GDate *date = fp_print_get_enroll_date (match);
|
||||||
|
char date_str[128] = "<unknown>";
|
||||||
|
|
||||||
|
verify_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
if (date && g_date_valid (date))
|
||||||
|
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
|
||||||
|
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
|
{
|
||||||
|
VerifyData *verify_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GPtrArray) prints = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
prints = fp_device_list_prints_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
FpPrint *verify_print = NULL;
|
||||||
|
g_autoptr(FpPrint) stored_print = NULL;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (!prints->len)
|
||||||
|
{
|
||||||
|
g_warning ("No prints saved on device");
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stored_print = get_stored_print (dev, verify_data);
|
||||||
|
|
||||||
|
for (i = 0; i < prints->len; ++i)
|
||||||
|
{
|
||||||
|
FpPrint *print = prints->pdata[i];
|
||||||
|
|
||||||
|
if (stored_print && fp_print_equal (stored_print, print))
|
||||||
|
/* If the private print data matches, let's use the stored print
|
||||||
|
* as it contains more metadata to show */
|
||||||
|
print = stored_print;
|
||||||
|
|
||||||
|
if (fp_print_get_finger (print) == verify_data->finger &&
|
||||||
|
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
||||||
|
{
|
||||||
|
const GDate *verify_print_date = NULL;
|
||||||
|
const GDate *print_date = fp_print_get_enroll_date (print);
|
||||||
|
|
||||||
|
if (verify_print)
|
||||||
|
verify_print_date = fp_print_get_enroll_date (verify_print);
|
||||||
|
|
||||||
|
if (!verify_print || !print_date || !verify_print_date ||
|
||||||
|
g_date_compare (print_date, verify_print_date) >= 0)
|
||||||
|
verify_print = print;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verify_print)
|
||||||
|
{
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug ("Comparing print with %s",
|
||||||
|
fp_print_get_description (verify_print));
|
||||||
|
|
||||||
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||||
|
on_match_cb, verify_data, NULL,
|
||||||
|
(GAsyncReadyCallback) on_verify_completed,
|
||||||
|
verify_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Loading prints failed with error %s", error->message);
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||||
|
{
|
||||||
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
||||||
|
{
|
||||||
|
g_print ("Choose the finger to verify:\n");
|
||||||
|
verify_data->finger = finger_chooser ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
||||||
|
{
|
||||||
|
g_warning ("Unknown finger selected");
|
||||||
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
verify_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
|
||||||
|
|
||||||
|
if (!verify_print)
|
||||||
|
{
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||||
|
on_match_cb, verify_data, NULL,
|
||||||
|
(GAsyncReadyCallback) on_verify_completed,
|
||||||
|
verify_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
VerifyData *verify_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);
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("Opened device. ");
|
||||||
|
|
||||||
|
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
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FpContext) ctx = NULL;
|
||||||
|
g_autoptr(VerifyData) verify_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_data = g_new0 (VerifyData, 1);
|
||||||
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
|
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
verify_data->cancellable = g_cancellable_new ();
|
||||||
|
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);
|
||||||
|
|
||||||
|
g_main_loop_run (verify_data->loop);
|
||||||
|
|
||||||
|
return verify_data->ret_value;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
* Example fingerprint verification program
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
|
||||||
struct fp_driver *drv;
|
|
||||||
if (!ddev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *enroll(struct fp_dev *dev) {
|
|
||||||
struct fp_print_data *enrolled_print = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
printf("You will need to successfully scan your finger %d times to "
|
|
||||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
|
||||||
|
|
||||||
do {
|
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
|
||||||
r = fp_enroll_finger(dev, &enrolled_print);
|
|
||||||
if (r < 0) {
|
|
||||||
printf("Enroll failed with error %d\n", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
switch (r) {
|
|
||||||
case FP_ENROLL_COMPLETE:
|
|
||||||
printf("Enroll complete!\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_FAIL:
|
|
||||||
printf("Enroll failed, something wen't wrong :(\n");
|
|
||||||
return NULL;
|
|
||||||
case FP_ENROLL_PASS:
|
|
||||||
printf("Enroll stage passed. Yay!\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY:
|
|
||||||
printf("Didn't quite catch that. Please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
|
||||||
printf("Your swipe was too short, please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
|
||||||
printf("Didn't catch that, please center your finger on the "
|
|
||||||
"sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
|
||||||
printf("Scan failed, please remove your finger and then try "
|
|
||||||
"again.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (r != FP_ENROLL_COMPLETE);
|
|
||||||
|
|
||||||
if (!enrolled_print) {
|
|
||||||
fprintf(stderr, "Enroll complete but no print?\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Enrollment completed!\n\n");
|
|
||||||
return enrolled_print;
|
|
||||||
}
|
|
||||||
|
|
||||||
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
|
||||||
r = fp_verify_finger(dev, data);
|
|
||||||
if (r < 0) {
|
|
||||||
printf("verification failed with error %d :(\n", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
switch (r) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
printf("NO MATCH!\n");
|
|
||||||
return 0;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
printf("MATCH!\n");
|
|
||||||
return 0;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
printf("Scan didn't quite work. Please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
printf("Swipe was too short, please try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
printf("Please center your finger on the sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
printf("Please remove finger from the sensor and try again.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int r = 1;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
struct fp_dscv_dev **discovered_devs;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
|
||||||
if (!discovered_devs) {
|
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
|
||||||
if (!ddev) {
|
|
||||||
fprintf(stderr, "No devices detected.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = fp_dev_open(ddev);
|
|
||||||
fp_dscv_devs_free(discovered_devs);
|
|
||||||
if (!dev) {
|
|
||||||
fprintf(stderr, "Could not open device.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Opened device. It's now time to enroll your finger.\n\n");
|
|
||||||
data = enroll(dev);
|
|
||||||
if (!data)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
|
|
||||||
printf("Normally we'd save that print to disk, and recall it at some "
|
|
||||||
"point later when we want to authenticate the user who just "
|
|
||||||
"enrolled. In the interests of demonstration, we'll authenticate "
|
|
||||||
"that user immediately.\n");
|
|
||||||
|
|
||||||
do {
|
|
||||||
char buffer[20];
|
|
||||||
|
|
||||||
verify(dev, data);
|
|
||||||
printf("Verify again? [Y/n]? ");
|
|
||||||
fgets(buffer, sizeof(buffer), stdin);
|
|
||||||
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
|
|
||||||
break;
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
fp_print_data_free(data);
|
|
||||||
out_close:
|
|
||||||
fp_dev_close(dev);
|
|
||||||
out:
|
|
||||||
fp_exit();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: libfprint
|
|
||||||
Description: Generic C API for fingerprint reader access
|
|
||||||
Version: @VERSION@
|
|
||||||
Libs: -L${libdir} -lfprint
|
|
||||||
Cflags: -I${includedir}/libfprint
|
|
||||||
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
lib_LTLIBRARIES = libfprint.la
|
|
||||||
noinst_PROGRAMS = fprint-list-udev-rules
|
|
||||||
MOSTLYCLEANFILES = $(udev_rules_DATA)
|
|
||||||
|
|
||||||
UPEKE2_SRC = drivers/upeke2.c
|
|
||||||
UPEKTS_SRC = drivers/upekts.c
|
|
||||||
UPEKTC_SRC = drivers/upektc.c drivers/upektc.h
|
|
||||||
UPEKSONLY_SRC = drivers/upeksonly.c
|
|
||||||
URU4000_SRC = drivers/uru4000.c
|
|
||||||
AES1610_SRC = drivers/aes1610.c
|
|
||||||
AES1660_SRC = drivers/aes1660.c drivers/aes1660.h
|
|
||||||
AES2501_SRC = drivers/aes2501.c drivers/aes2501.h
|
|
||||||
AES2550_SRC = drivers/aes2550.c drivers/aes2550.h
|
|
||||||
AES2660_SRC = drivers/aes2660.c drivers/aes2660.h
|
|
||||||
AES4000_SRC = drivers/aes4000.c
|
|
||||||
FDU2000_SRC = drivers/fdu2000.c
|
|
||||||
VCOM5S_SRC = drivers/vcom5s.c
|
|
||||||
VFS101_SRC = drivers/vfs101.c
|
|
||||||
VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h drivers/vfs301_proto_fragments.h
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
$(UPEKE2_SRC) \
|
|
||||||
$(UPEKTS_SRC) \
|
|
||||||
$(UPEKTC_SRC) \
|
|
||||||
$(UPEKSONLY_SRC) \
|
|
||||||
$(URU4000_SRC) \
|
|
||||||
$(AES1610_SRC) \
|
|
||||||
$(AES1660_SRC) \
|
|
||||||
$(AES2501_SRC) \
|
|
||||||
$(AES2550_SRC) \
|
|
||||||
$(AES2660_SRC) \
|
|
||||||
$(AES4000_SRC) \
|
|
||||||
$(FDU2000_SRC) \
|
|
||||||
$(VCOM5S_SRC) \
|
|
||||||
$(VFS101_SRC) \
|
|
||||||
$(VFS301_SRC) \
|
|
||||||
drivers/aesx660.c \
|
|
||||||
drivers/aesx660.h \
|
|
||||||
drivers/driver_ids.h \
|
|
||||||
aeslib.c aeslib.h \
|
|
||||||
imagemagick.c \
|
|
||||||
gdkpixbuf.c \
|
|
||||||
60-fprint-autosuspend.rules
|
|
||||||
|
|
||||||
DRIVER_SRC =
|
|
||||||
OTHER_SRC =
|
|
||||||
|
|
||||||
NBIS_SRC = \
|
|
||||||
nbis/include/bozorth.h \
|
|
||||||
nbis/include/bz_array.h \
|
|
||||||
nbis/include/defs.h \
|
|
||||||
nbis/include/lfs.h \
|
|
||||||
nbis/include/log.h \
|
|
||||||
nbis/include/morph.h \
|
|
||||||
nbis/include/sunrast.h \
|
|
||||||
nbis/bozorth3/bozorth3.c \
|
|
||||||
nbis/bozorth3/bz_alloc.c \
|
|
||||||
nbis/bozorth3/bz_drvrs.c \
|
|
||||||
nbis/bozorth3/bz_gbls.c \
|
|
||||||
nbis/bozorth3/bz_io.c \
|
|
||||||
nbis/bozorth3/bz_sort.c \
|
|
||||||
nbis/mindtct/binar.c \
|
|
||||||
nbis/mindtct/block.c \
|
|
||||||
nbis/mindtct/contour.c \
|
|
||||||
nbis/mindtct/detect.c \
|
|
||||||
nbis/mindtct/dft.c \
|
|
||||||
nbis/mindtct/free.c \
|
|
||||||
nbis/mindtct/globals.c \
|
|
||||||
nbis/mindtct/imgutil.c \
|
|
||||||
nbis/mindtct/init.c \
|
|
||||||
nbis/mindtct/line.c \
|
|
||||||
nbis/mindtct/log.c \
|
|
||||||
nbis/mindtct/loop.c \
|
|
||||||
nbis/mindtct/maps.c \
|
|
||||||
nbis/mindtct/matchpat.c \
|
|
||||||
nbis/mindtct/minutia.c \
|
|
||||||
nbis/mindtct/morph.c \
|
|
||||||
nbis/mindtct/quality.c \
|
|
||||||
nbis/mindtct/remove.c \
|
|
||||||
nbis/mindtct/ridges.c \
|
|
||||||
nbis/mindtct/shape.c \
|
|
||||||
nbis/mindtct/sort.c \
|
|
||||||
nbis/mindtct/util.c
|
|
||||||
|
|
||||||
libfprint_la_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
|
||||||
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
|
||||||
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(CRYPTO_LIBS)
|
|
||||||
|
|
||||||
fprint_list_udev_rules_SOURCES = fprint-list-udev-rules.c
|
|
||||||
fprint_list_udev_rules_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(IMAGEMAGICK_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
|
||||||
fprint_list_udev_rules_LDADD = $(builddir)/libfprint.la $(GLIB_LIBS)
|
|
||||||
|
|
||||||
udev_rules_DATA = 60-fprint-autosuspend.rules
|
|
||||||
|
|
||||||
if ENABLE_UDEV_RULES
|
|
||||||
$(udev_rules_DATA): fprint-list-udev-rules
|
|
||||||
$(builddir)/fprint-list-udev-rules > $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKE2
|
|
||||||
DRIVER_SRC += $(UPEKE2_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKTS
|
|
||||||
DRIVER_SRC += $(UPEKTS_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKSONLY
|
|
||||||
DRIVER_SRC += $(UPEKSONLY_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKTC
|
|
||||||
DRIVER_SRC += $(UPEKTC_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_URU4000
|
|
||||||
DRIVER_SRC += $(URU4000_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VCOM5S
|
|
||||||
DRIVER_SRC += $(VCOM5S_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
#if ENABLE_FDU2000
|
|
||||||
#DRIVER_SRC += $(FDU2000_SRC)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ENABLE_AES1610
|
|
||||||
DRIVER_SRC += $(AES1610_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES1660
|
|
||||||
DRIVER_SRC += $(AES1660_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2501
|
|
||||||
DRIVER_SRC += $(AES2501_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2550
|
|
||||||
DRIVER_SRC += $(AES2550_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2660
|
|
||||||
DRIVER_SRC += $(AES2660_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES4000
|
|
||||||
DRIVER_SRC += $(AES4000_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VFS101
|
|
||||||
DRIVER_SRC += $(VFS101_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VFS301
|
|
||||||
DRIVER_SRC += $(VFS301_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_IMAGEMAGICK
|
|
||||||
OTHER_SRC += imagemagick.c
|
|
||||||
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
|
|
||||||
libfprint_la_LIBADD += $(IMAGING_LIBS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_GDKPIXBUF
|
|
||||||
OTHER_SRC += gdkpixbuf.c
|
|
||||||
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
|
|
||||||
libfprint_la_LIBADD += $(IMAGING_LIBS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_AESLIB
|
|
||||||
OTHER_SRC += aeslib.c aeslib.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_AESX660
|
|
||||||
OTHER_SRC += drivers/aesx660.c drivers/aesx660.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
libfprint_la_SOURCES = \
|
|
||||||
fp_internal.h \
|
|
||||||
async.c \
|
|
||||||
core.c \
|
|
||||||
data.c \
|
|
||||||
drv.c \
|
|
||||||
img.c \
|
|
||||||
imgdev.c \
|
|
||||||
poll.c \
|
|
||||||
sync.c \
|
|
||||||
$(DRIVER_SRC) \
|
|
||||||
$(OTHER_SRC) \
|
|
||||||
$(NBIS_SRC)
|
|
||||||
|
|
||||||
pkginclude_HEADERS = fprint.h
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* Shared functions between libfprint Authentec drivers
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 "aeslib"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "aeslib.h"
|
|
||||||
|
|
||||||
#define MAX_REGWRITES_PER_REQUEST 16
|
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
|
||||||
|
|
||||||
struct write_regv_data {
|
|
||||||
struct fp_img_dev *imgdev;
|
|
||||||
unsigned int num_regs;
|
|
||||||
const struct aes_regwrite *regs;
|
|
||||||
unsigned int offset;
|
|
||||||
aes_write_regv_cb callback;
|
|
||||||
void *user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void continue_write_regv(struct write_regv_data *wdata);
|
|
||||||
|
|
||||||
/* libusb bulk callback for regv write completion transfer. continues the
|
|
||||||
* transaction */
|
|
||||||
static void write_regv_trf_complete(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct write_regv_data *wdata = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
|
|
||||||
else if (transfer->length != transfer->actual_length)
|
|
||||||
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
|
|
||||||
else
|
|
||||||
continue_write_regv(wdata);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
|
||||||
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
|
|
||||||
{
|
|
||||||
unsigned int offset = wdata->offset;
|
|
||||||
unsigned int num = upper_bound - offset + 1;
|
|
||||||
size_t alloc_size = num * 2;
|
|
||||||
unsigned char *data = g_malloc(alloc_size);
|
|
||||||
unsigned int i;
|
|
||||||
size_t data_offset = 0;
|
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
g_free(data);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = offset; i < offset + num; i++) {
|
|
||||||
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
|
||||||
data[data_offset++] = regwrite->reg;
|
|
||||||
data[data_offset++] = regwrite->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
|
|
||||||
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write the next batch of registers to be written, or if there are no more,
|
|
||||||
* indicate completion to the caller */
|
|
||||||
static void continue_write_regv(struct write_regv_data *wdata)
|
|
||||||
{
|
|
||||||
unsigned int offset = wdata->offset;
|
|
||||||
unsigned int regs_remaining;
|
|
||||||
unsigned int limit;
|
|
||||||
unsigned int upper_bound;
|
|
||||||
int i;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* skip all zeros and ensure there is still work to do */
|
|
||||||
while (TRUE) {
|
|
||||||
if (offset >= wdata->num_regs) {
|
|
||||||
fp_dbg("all registers written");
|
|
||||||
wdata->callback(wdata->imgdev, 0, wdata->user_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (wdata->regs[offset].reg)
|
|
||||||
break;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
wdata->offset = offset;
|
|
||||||
regs_remaining = wdata->num_regs - offset;
|
|
||||||
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
|
||||||
upper_bound = offset + limit - 1;
|
|
||||||
|
|
||||||
/* determine if we can write the entire of the regs at once, or if there
|
|
||||||
* is a zero dividing things up */
|
|
||||||
for (i = offset; i <= upper_bound; i++)
|
|
||||||
if (!wdata->regs[i].reg) {
|
|
||||||
upper_bound = i - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = do_write_regv(wdata, upper_bound);
|
|
||||||
if (r < 0) {
|
|
||||||
wdata->callback(wdata->imgdev, r, wdata->user_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wdata->offset = upper_bound + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write a load of registers to the device, combining multiple writes in a
|
|
||||||
* single URB up to a limit. insert writes to non-existent register 0 to force
|
|
||||||
* specific groups of writes to be separated by different URBs. */
|
|
||||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
|
||||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
|
|
||||||
fp_dbg("write %d regs", num_regs);
|
|
||||||
wdata->imgdev = dev;
|
|
||||||
wdata->num_regs = num_regs;
|
|
||||||
wdata->regs = regs;
|
|
||||||
wdata->offset = 0;
|
|
||||||
wdata->callback = callback;
|
|
||||||
wdata->user_data = user_data;
|
|
||||||
continue_write_regv(wdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
void aes_assemble_image(unsigned char *input, size_t width, size_t height,
|
|
||||||
unsigned char *output)
|
|
||||||
{
|
|
||||||
size_t row, column;
|
|
||||||
|
|
||||||
for (column = 0; column < width; column++) {
|
|
||||||
for (row = 0; row < height; row += 2) {
|
|
||||||
output[width * row + column] = (*input & 0x0f) * 17;
|
|
||||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
|
||||||
input++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find overlapping parts of frames */
|
|
||||||
static unsigned int find_overlap(unsigned char *first_frame,
|
|
||||||
unsigned char *second_frame, unsigned int *min_error,
|
|
||||||
unsigned int frame_width, unsigned int frame_height)
|
|
||||||
{
|
|
||||||
unsigned int dy;
|
|
||||||
unsigned int not_overlapped_height = 0;
|
|
||||||
/* 255 is highest brightness value for an 8bpp image */
|
|
||||||
*min_error = 255 * frame_width * frame_height;
|
|
||||||
for (dy = 0; dy < frame_height; dy++) {
|
|
||||||
/* Calculating difference (error) between parts of frames */
|
|
||||||
unsigned int i;
|
|
||||||
unsigned int error = 0;
|
|
||||||
for (i = 0; i < frame_width * (frame_height - dy); i++) {
|
|
||||||
/* Using ? operator to avoid abs function */
|
|
||||||
error += first_frame[i] > second_frame[i] ?
|
|
||||||
(first_frame[i] - second_frame[i]) :
|
|
||||||
(second_frame[i] - first_frame[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Normalize error */
|
|
||||||
error *= 15;
|
|
||||||
error /= i;
|
|
||||||
if (error < *min_error) {
|
|
||||||
*min_error = error;
|
|
||||||
not_overlapped_height = dy;
|
|
||||||
}
|
|
||||||
first_frame += frame_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
return not_overlapped_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* assemble a series of frames into a single image */
|
|
||||||
static unsigned int assemble(GSList *list_entry, size_t num_stripes,
|
|
||||||
unsigned int frame_width, unsigned int frame_height,
|
|
||||||
unsigned char *output, gboolean reverse, unsigned int *errors_sum)
|
|
||||||
{
|
|
||||||
uint8_t *assembled = output;
|
|
||||||
int frame;
|
|
||||||
uint32_t image_height = frame_height;
|
|
||||||
unsigned int min_error, frame_size = frame_width * frame_height;
|
|
||||||
*errors_sum = 0;
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
output += (num_stripes - 1) * frame_size;
|
|
||||||
for (frame = 0; frame < num_stripes; frame++) {
|
|
||||||
aes_assemble_image(list_entry->data, frame_width, frame_height, output);
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
output -= frame_size;
|
|
||||||
else
|
|
||||||
output += frame_size;
|
|
||||||
list_entry = g_slist_next(list_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detecting where frames overlaped */
|
|
||||||
output = assembled;
|
|
||||||
for (frame = 1; frame < num_stripes; frame++) {
|
|
||||||
int not_overlapped;
|
|
||||||
|
|
||||||
output += frame_size;
|
|
||||||
not_overlapped = find_overlap(assembled, output, &min_error,
|
|
||||||
frame_width, frame_height);
|
|
||||||
*errors_sum += min_error;
|
|
||||||
image_height += not_overlapped;
|
|
||||||
assembled += frame_width * not_overlapped;
|
|
||||||
memcpy(assembled, output, frame_size);
|
|
||||||
}
|
|
||||||
return image_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
|
||||||
unsigned int frame_width, unsigned int frame_height)
|
|
||||||
{
|
|
||||||
size_t final_size;
|
|
||||||
struct fp_img *img;
|
|
||||||
unsigned int frame_size = frame_width * frame_height;
|
|
||||||
unsigned int errors_sum, r_errors_sum;
|
|
||||||
|
|
||||||
BUG_ON(stripes_len == 0);
|
|
||||||
|
|
||||||
/* create buffer big enough for max image */
|
|
||||||
img = fpi_img_new(stripes_len * frame_size);
|
|
||||||
|
|
||||||
img->flags = FP_IMG_COLORS_INVERTED;
|
|
||||||
img->height = assemble(stripes, stripes_len,
|
|
||||||
frame_width, frame_height,
|
|
||||||
img->data, FALSE, &errors_sum);
|
|
||||||
img->height = assemble(stripes, stripes_len,
|
|
||||||
frame_width, frame_height,
|
|
||||||
img->data, TRUE, &r_errors_sum);
|
|
||||||
|
|
||||||
if (r_errors_sum > errors_sum) {
|
|
||||||
img->height = assemble(stripes, stripes_len,
|
|
||||||
frame_width, frame_height,
|
|
||||||
img->data, FALSE, &errors_sum);
|
|
||||||
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
|
||||||
fp_dbg("normal scan direction");
|
|
||||||
} else {
|
|
||||||
fp_dbg("reversed scan direction");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now that overlap has been removed, resize output image buffer */
|
|
||||||
final_size = img->height * frame_width;
|
|
||||||
img = fpi_img_resize(img, final_size);
|
|
||||||
img->width = frame_width;
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
/*
|
|
||||||
* Asynchronous I/O functionality
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 "async"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
/* Drivers call this when device initialisation has completed */
|
|
||||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_INITIALIZING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
|
|
||||||
opened_devices = g_slist_prepend(opened_devices, dev);
|
|
||||||
if (dev->open_cb)
|
|
||||||
dev->open_cb(dev, status, dev->open_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = ddev->drv;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
libusb_device_handle *udevh;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
r = libusb_open(ddev->udev, &udevh);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("usb_open failed, error %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = g_malloc0(sizeof(*dev));
|
|
||||||
dev->drv = drv;
|
|
||||||
dev->udev = udevh;
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
dev->open_cb = cb;
|
|
||||||
dev->open_cb_data = user_data;
|
|
||||||
|
|
||||||
if (!drv->open) {
|
|
||||||
fpi_drvcb_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
r = drv->open(dev, ddev->driver_data);
|
|
||||||
if (r) {
|
|
||||||
fp_err("device initialisation failed, driver=%s", drv->name);
|
|
||||||
libusb_close(udevh);
|
|
||||||
g_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when device deinitialisation has completed */
|
|
||||||
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZED;
|
|
||||||
libusb_close(dev->udev);
|
|
||||||
if (dev->close_cb)
|
|
||||||
dev->close_cb(dev, dev->close_cb_data);
|
|
||||||
g_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
|
||||||
fp_dev_close_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
|
|
||||||
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
|
||||||
fp_err("device %p not in opened list!", dev);
|
|
||||||
opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
|
|
||||||
|
|
||||||
dev->close_cb = callback;
|
|
||||||
dev->close_cb_data = user_data;
|
|
||||||
|
|
||||||
if (!drv->close) {
|
|
||||||
fpi_drvcb_close_complete(dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZING;
|
|
||||||
drv->close(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when enrollment has started */
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->enroll_stage_cb)
|
|
||||||
dev->enroll_stage_cb(dev, status, NULL, NULL,
|
|
||||||
dev->enroll_stage_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_ENROLLING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
|
||||||
fp_enroll_stage_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
|
||||||
fp_err("driver %s has 0 enroll stages or no enroll func",
|
|
||||||
drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("starting enrollment");
|
|
||||||
dev->enroll_stage_cb = callback;
|
|
||||||
dev->enroll_stage_cb_data = user_data;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_ENROLL_STARTING;
|
|
||||||
r = drv->enroll_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->enroll_stage_cb = NULL;
|
|
||||||
fp_err("failed to start enrollment");
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when an enroll stage has completed */
|
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img)
|
|
||||||
{
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLLING);
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
if (!dev->enroll_stage_cb) {
|
|
||||||
fp_dbg("ignoring enroll result as no callback is subscribed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (result == FP_ENROLL_COMPLETE && !data) {
|
|
||||||
fp_err("BUG: complete but no data?");
|
|
||||||
result = FP_ENROLL_FAIL;
|
|
||||||
}
|
|
||||||
dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when enrollment has stopped */
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->enroll_stop_cb)
|
|
||||||
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
|
||||||
fp_enroll_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->enroll_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->enroll_stage_cb = NULL;
|
|
||||||
dev->enroll_stop_cb = callback;
|
|
||||||
dev->enroll_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_ENROLL_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->enroll_stop) {
|
|
||||||
fpi_drvcb_enroll_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->enroll_stop(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop enrollment");
|
|
||||||
dev->enroll_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data, fp_verify_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_VERIFY_STARTING;
|
|
||||||
dev->verify_cb = callback;
|
|
||||||
dev->verify_cb_data = user_data;
|
|
||||||
dev->verify_data = data;
|
|
||||||
|
|
||||||
r = drv->verify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
fp_err("failed to start verification, error %d", r);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when verification has started */
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->verify_cb)
|
|
||||||
dev->verify_cb(dev, status, NULL, dev->verify_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_VERIFYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this to report a verify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFYING);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH)
|
|
||||||
dev->state = DEV_STATE_VERIFY_DONE;
|
|
||||||
|
|
||||||
if (dev->verify_cb)
|
|
||||||
dev->verify_cb(dev, result, img, dev->verify_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when verification has stopped */
|
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->verify_stop_cb)
|
|
||||||
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
|
||||||
fp_verify_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
|
||||||
&& dev->state != DEV_STATE_VERIFYING
|
|
||||||
&& dev->state != DEV_STATE_VERIFY_DONE);
|
|
||||||
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
dev->verify_stop_cb = callback;
|
|
||||||
dev->verify_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_VERIFY_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->verify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_verify_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->verify_stop(dev, iterating);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop verification");
|
|
||||||
dev->verify_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
|
||||||
dev->identify_cb = callback;
|
|
||||||
dev->identify_cb_data = user_data;
|
|
||||||
dev->identify_gallery = gallery;
|
|
||||||
|
|
||||||
r = drv->identify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("identify_start failed with error %d", r);
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: identification has started, expect results soon */
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->identify_cb)
|
|
||||||
dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_IDENTIFYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers report an identify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_ERROR);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH)
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_DONE;
|
|
||||||
|
|
||||||
if (dev->identify_cb)
|
|
||||||
dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
|
||||||
fp_identify_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STOPPING;
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
dev->identify_stop_cb = callback;
|
|
||||||
dev->identify_stop_cb_data = user_data;
|
|
||||||
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->identify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_identify_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->identify_stop(dev, iterating);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop identification");
|
|
||||||
dev->identify_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when identification has stopped */
|
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->identify_stop_cb)
|
|
||||||
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
986
libfprint/core.c
@@ -1,986 +0,0 @@
|
|||||||
/*
|
|
||||||
* Core functions for libfprint
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
static int log_level = 0;
|
|
||||||
static int log_level_fixed = 0;
|
|
||||||
|
|
||||||
libusb_context *fpi_usb_ctx = NULL;
|
|
||||||
GSList *opened_devices = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \mainpage libfprint API Reference
|
|
||||||
* libfprint is an open source library to provide access to fingerprint
|
|
||||||
* scanning devices. For more info, see the
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Libfprint">libfprint project
|
|
||||||
* homepage</a>.
|
|
||||||
*
|
|
||||||
* This documentation is aimed at application developers who wish to integrate
|
|
||||||
* fingerprint-related functionality into their software. libfprint has been
|
|
||||||
* designed so that you only have to do this once - by integrating your
|
|
||||||
* software with libfprint, you'll be supporting all the fingerprint readers
|
|
||||||
* that we have got our hands on. As such, the API is rather general (and
|
|
||||||
* therefore hopefully easy to comprehend!), and does its best to hide the
|
|
||||||
* technical details that required to operate the hardware.
|
|
||||||
*
|
|
||||||
* This documentation is not aimed at developers wishing to develop and
|
|
||||||
* contribute fingerprint device drivers to libfprint.
|
|
||||||
*
|
|
||||||
* Feedback on this API and its associated documentation is appreciated. Was
|
|
||||||
* anything unclear? Does anything seem unreasonably complicated? Is anything
|
|
||||||
* missing? Let us know on the
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Mailing_list">mailing list</a>.
|
|
||||||
*
|
|
||||||
* \section enrollment Enrollment
|
|
||||||
*
|
|
||||||
* Before you dive into the API, it's worth introducing a couple of concepts.
|
|
||||||
*
|
|
||||||
* The process of enrolling a finger is where you effectively scan your
|
|
||||||
* finger for the purposes of teaching the system what your finger looks like.
|
|
||||||
* This means that you scan your fingerprint, then the system processes it and
|
|
||||||
* stores some data about your fingerprint to refer to later.
|
|
||||||
*
|
|
||||||
* \section verification Verification
|
|
||||||
*
|
|
||||||
* Verification is what most people think of when they think about fingerprint
|
|
||||||
* scanning. The process of verification is effectively performing a fresh
|
|
||||||
* fingerprint scan, and then comparing that scan to a finger that was
|
|
||||||
* previously enrolled.
|
|
||||||
*
|
|
||||||
* As an example scenario, verification can be used to implement what people
|
|
||||||
* would picture as fingerprint login (i.e. fingerprint replaces password).
|
|
||||||
* For example:
|
|
||||||
* - I enroll my fingerprint through some software that trusts I am who I say
|
|
||||||
* I am. This is a prerequisite before I can perform fingerprint-based
|
|
||||||
* login for my account.
|
|
||||||
* - Some time later, I want to login to my computer. I enter my username,
|
|
||||||
* but instead of prompting me for a password, it asks me to scan my finger.
|
|
||||||
* I scan my finger.
|
|
||||||
* - The system compares the finger I just scanned to the one that was
|
|
||||||
* enrolled earlier. If the system decides that the fingerprints match,
|
|
||||||
* I am successfully logged in. Otherwise, the system informs me that I am
|
|
||||||
* not authorised to login as that user.
|
|
||||||
*
|
|
||||||
* \section identification Identification
|
|
||||||
*
|
|
||||||
* Identification is the process of comparing a freshly scanned fingerprint
|
|
||||||
* to a <em>collection</em> of previously enrolled fingerprints. For example,
|
|
||||||
* imagine there are 100 people in an organisation, and they all have enrolled
|
|
||||||
* their fingerprints. One user walks up to a fingerprint scanner and scans
|
|
||||||
* their finger. With <em>no other knowledge</em> of who that user might be,
|
|
||||||
* the system examines their fingerprint, looks in the database, and determines
|
|
||||||
* that the user is user number #61.
|
|
||||||
*
|
|
||||||
* In other words, verification might be seen as a one-to-one fingerprint
|
|
||||||
* comparison where you know the identity of the user that you wish to
|
|
||||||
* authenticate, whereas identification is a one-to-many comparison where you
|
|
||||||
* do not know the identity of the user that you wish to authenticate.
|
|
||||||
*
|
|
||||||
* \section compat_general Device and print compatibility
|
|
||||||
* Moving off generic conceptual ideas and onto libfprint-specific
|
|
||||||
* implementation details, here are some introductory notes regarding how
|
|
||||||
* libfprint copes with compatibility of fingerprints.
|
|
||||||
*
|
|
||||||
* libfprint deals with a whole variety of different fingerprint readers and
|
|
||||||
* the design includes considerations of compatibility and interoperability
|
|
||||||
* between multiple devices. Your application should also be prepared to
|
|
||||||
* work with more than one type of fingerprint reader and should consider that
|
|
||||||
* enrolled fingerprint X may not be compatible with the device the user has
|
|
||||||
* plugged in today.
|
|
||||||
*
|
|
||||||
* libfprint implements the principle that fingerprints from different devices
|
|
||||||
* are not necessarily compatible. For example, different devices may see
|
|
||||||
* significantly different areas of fingerprint surface, and comparing images
|
|
||||||
* between the devices would be unreliable. Also, devices can stretch and
|
|
||||||
* distort images in different ways.
|
|
||||||
*
|
|
||||||
* libfprint also implements the principle that in some cases, fingerprints
|
|
||||||
* <em>are</em> compatible between different devices. If you go and buy two
|
|
||||||
* identical fingerprint readers, it seems logical that you should be able
|
|
||||||
* to enroll on one and verify on another without problems.
|
|
||||||
*
|
|
||||||
* libfprint takes a fairly simplistic approach to these issues. Internally,
|
|
||||||
* fingerprint hardware is driven by individual drivers. libfprint enforces
|
|
||||||
* that a fingerprint that came from a device backed by driver X is never
|
|
||||||
* compared to a fingerprint that came from a device backed by driver Y.
|
|
||||||
*
|
|
||||||
* Additionally, libfprint is designed for the situation where a single driver
|
|
||||||
* may support a range of devices which differ in imaging or scanning
|
|
||||||
* properties. For example, a driver may support two ranges of devices which
|
|
||||||
* even though are programmed over the same interface, one device sees
|
|
||||||
* substantially less of the finger flesh, therefore images from the two
|
|
||||||
* device types should be incompatible despite being from the same driver. To
|
|
||||||
* implement this, each driver assigns a <em>device type</em> to each device
|
|
||||||
* that it detects based on its imaging characteristics. libfprint ensures that
|
|
||||||
* two prints being compared have the same device type.
|
|
||||||
*
|
|
||||||
* In summary, libfprint represents fingerprints in several internal structures
|
|
||||||
* and each representation will offer you a way of determining the
|
|
||||||
* \ref driver_id "driver ID" and \ref devtype "devtype" of the print in
|
|
||||||
* question. Prints are only compatible if the driver ID <b>and</b> devtypes
|
|
||||||
* match. libfprint does offer you some "is this print compatible?" helper
|
|
||||||
* functions, so you don't have to worry about these details too much.
|
|
||||||
*
|
|
||||||
* \section sync Synchronity/asynchronity
|
|
||||||
*
|
|
||||||
* Currently, all data acquisition operations are synchronous and can
|
|
||||||
* potentially block for extended periods of time. For example, the enroll
|
|
||||||
* function will block for an unpredictable amount of time until the user
|
|
||||||
* scans their finger.
|
|
||||||
*
|
|
||||||
* Alternative asynchronous/non-blocking functionality will be offered in
|
|
||||||
* future but has not been implemented yet.
|
|
||||||
*
|
|
||||||
* \section getting_started Getting started
|
|
||||||
*
|
|
||||||
* libfprint includes several simple functional examples under the examples/
|
|
||||||
* directory in the libfprint source distribution. Those are good starting
|
|
||||||
* points.
|
|
||||||
*
|
|
||||||
* Usually the first thing you want to do is determine which fingerprint
|
|
||||||
* devices are present. This is done through \ref dscv_dev "device discovery".
|
|
||||||
*
|
|
||||||
* Once you have found a device you would like to operate, you should open it.
|
|
||||||
* Refer to \ref dev "device operations". This section also details enrollment,
|
|
||||||
* image capture, and verification.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* That should be enough to get you started, but do remember there are
|
|
||||||
* documentation pages on other aspects of libfprint's API (see the modules
|
|
||||||
* page).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup core Core library operations */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup dev Device operations
|
|
||||||
* In order to interact with fingerprint scanners, your software will
|
|
||||||
* interface primarily with libfprint's representation of devices, detailed
|
|
||||||
* on this page.
|
|
||||||
*
|
|
||||||
* \section enrolling Enrolling
|
|
||||||
* Enrolling is represented within libfprint as a multi-stage process. This
|
|
||||||
* slightly complicates things for application developers, but is required
|
|
||||||
* for a smooth process.
|
|
||||||
*
|
|
||||||
* Some devices require the user to scan their finger multiple times in
|
|
||||||
* order to complete the enrollment process. libfprint must return control
|
|
||||||
* to your application inbetween each scan in order for your application to
|
|
||||||
* instruct the user to swipe their finger again. Each scan is referred to
|
|
||||||
* as a stage, so a device that requires 3 scans for enrollment corresponds
|
|
||||||
* to you running 3 enrollment stages using libfprint.
|
|
||||||
*
|
|
||||||
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
|
|
||||||
* many enroll stages are needed.
|
|
||||||
*
|
|
||||||
* In order to complete an enroll stage, you call an enroll function such
|
|
||||||
* as fp_enroll_finger(). The return of this function does not necessarily
|
|
||||||
* indicate that a stage has completed though, as the user may not have
|
|
||||||
* produced a good enough scan. Each stage may have to be retried several
|
|
||||||
* times.
|
|
||||||
*
|
|
||||||
* The exact semantics of the enroll functions are described in the
|
|
||||||
* fp_enroll_finger() documentation. You should pay careful attention to the
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* \section imaging Imaging
|
|
||||||
* libfprint provides you with some ways to retrieve images of scanned
|
|
||||||
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
|
|
||||||
* function variants which provide images. You may wish to do something with
|
|
||||||
* such images in your application.
|
|
||||||
*
|
|
||||||
* However, you must be aware that not all hardware supported by libfprint
|
|
||||||
* operates like this. Most hardware does operate simply by sending
|
|
||||||
* fingerprint images to the host computer for further processing, but some
|
|
||||||
* devices do all fingerprint processing in hardware and do not present images
|
|
||||||
* to the host computer.
|
|
||||||
*
|
|
||||||
* You can use fp_dev_supports_imaging() to see if image capture is possible
|
|
||||||
* on a particular device. Your application must be able to cope with the
|
|
||||||
* fact that libfprint does support regular operations (e.g. enrolling and
|
|
||||||
* verification) on some devices which do not provide images.
|
|
||||||
*
|
|
||||||
* \section devtype Devtypes
|
|
||||||
* Internally, the \ref drv "driver" behind a device assigns a 32-bit
|
|
||||||
* <em>devtype</em> identifier to the device. This cannot be used as a unique
|
|
||||||
* ID for a specific device as many devices under the same range may share
|
|
||||||
* the same devtype. The devtype may even be 0 in all cases.
|
|
||||||
*
|
|
||||||
* The only reason you may be interested in retrieving the devtype for a
|
|
||||||
* device is for the purpose of checking if some print data is compatible
|
|
||||||
* with a device. libfprint uses the devtype as one way of checking that the
|
|
||||||
* print you are verifying is compatible with the device in question - the
|
|
||||||
* devtypes must be equal. This effectively allows drivers to support more
|
|
||||||
* than one type of device where the data from each one is not compatible with
|
|
||||||
* the other. Note that libfprint does provide you with helper functions to
|
|
||||||
* determine whether a print is compatible with a device, so under most
|
|
||||||
* circumstances, you don't have to worry about devtypes at all.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup dscv_dev Device discovery
|
|
||||||
* These functions allow you to scan the system for supported fingerprint
|
|
||||||
* scanning hardware. This is your starting point when integrating libfprint
|
|
||||||
* into your software.
|
|
||||||
*
|
|
||||||
* When you've identified a discovered device that you would like to control,
|
|
||||||
* you can open it with fp_dev_open(). Note that discovered devices may no
|
|
||||||
* longer be available at the time when you want to open them, for example
|
|
||||||
* the user may have unplugged the device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup drv Driver operations
|
|
||||||
* Internally, libfprint is abstracted into various drivers to communicate
|
|
||||||
* with the different types of supported fingerprint readers. libfprint works
|
|
||||||
* hard so that you don't have to care about these internal abstractions,
|
|
||||||
* however there are some situations where you may be interested in a little
|
|
||||||
* behind-the-scenes driver info.
|
|
||||||
*
|
|
||||||
* You can obtain the driver for a device using fp_dev_get_driver(), which
|
|
||||||
* you can pass to the functions documented on this page.
|
|
||||||
*
|
|
||||||
* \section driver_id Driver IDs
|
|
||||||
* Each driver is assigned a unique ID by the project maintainer. These
|
|
||||||
* assignments are
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Driver_ID_assignments">
|
|
||||||
* documented on the wiki</a> and will never change.
|
|
||||||
*
|
|
||||||
* The only reason you may be interested in retrieving the driver ID for a
|
|
||||||
* driver is for the purpose of checking if some print data is compatible
|
|
||||||
* with a device. libfprint uses the driver ID as one way of checking that
|
|
||||||
* the print you are trying to verify is compatible with the device in
|
|
||||||
* question - it ensures that enrollment data from one driver is never fed to
|
|
||||||
* another. Note that libfprint does provide you with helper functions to
|
|
||||||
* determine whether a print is compatible with a device, so under most
|
|
||||||
* circumstances, you don't have to worry about driver IDs at all.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GSList *registered_drivers = NULL;
|
|
||||||
|
|
||||||
void fpi_log(enum fpi_log_level level, const char *component,
|
|
||||||
const char *function, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
FILE *stream = stdout;
|
|
||||||
const char *prefix;
|
|
||||||
|
|
||||||
#ifndef ENABLE_DEBUG_LOGGING
|
|
||||||
if (!log_level)
|
|
||||||
return;
|
|
||||||
if (level == FPRINT_LOG_LEVEL_WARNING && log_level < 2)
|
|
||||||
return;
|
|
||||||
if (level == FPRINT_LOG_LEVEL_INFO && log_level < 3)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case FPRINT_LOG_LEVEL_INFO:
|
|
||||||
prefix = "info";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_WARNING:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "warning";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_ERROR:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "error";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_DEBUG:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "debug";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stream, "%s:%s [%s] ", component ? component : "fp", prefix,
|
|
||||||
function);
|
|
||||||
|
|
||||||
va_start (args, format);
|
|
||||||
vfprintf(stream, format, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
fprintf(stream, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_driver(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
if (drv->id == 0) {
|
|
||||||
fp_err("not registering driver %s: driver ID is 0", drv->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
|
|
||||||
fp_dbg("registered driver %s", drv->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_driver * const primitive_drivers[] = {
|
|
||||||
#ifdef ENABLE_UPEKTS
|
|
||||||
&upekts_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKE2
|
|
||||||
&upeke2_driver,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fp_img_driver * const img_drivers[] = {
|
|
||||||
#ifdef ENABLE_AES4000
|
|
||||||
&aes4000_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2501
|
|
||||||
&aes2501_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2550
|
|
||||||
&aes2550_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_URU4000
|
|
||||||
&uru4000_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VCOM5S
|
|
||||||
&vcom5s_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKSONLY
|
|
||||||
&upeksonly_driver,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_AES1610
|
|
||||||
&aes1610_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES1660
|
|
||||||
&aes1660_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2660
|
|
||||||
&aes2660_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS101
|
|
||||||
&vfs101_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS301
|
|
||||||
&vfs301_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKTC
|
|
||||||
&upektc_driver,
|
|
||||||
#endif
|
|
||||||
/*#ifdef ENABLE_FDU2000
|
|
||||||
&fdu2000_driver,
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
static void register_drivers(void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
register_driver(primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
|
|
||||||
struct fp_img_driver *imgdriver = img_drivers[i];
|
|
||||||
fpi_img_driver_setup(imgdriver);
|
|
||||||
register_driver(&imgdriver->driver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
|
|
||||||
{
|
|
||||||
GPtrArray *array;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
array = g_ptr_array_new ();
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
g_ptr_array_add (array, primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
|
|
||||||
g_ptr_array_add (array, &(img_drivers[i]->driver));
|
|
||||||
|
|
||||||
/* Add a null item terminating the array */
|
|
||||||
g_ptr_array_add (array, NULL);
|
|
||||||
|
|
||||||
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_driver *find_supporting_driver(libusb_device *udev,
|
|
||||||
const struct usb_id **usb_id, uint32_t *devtype)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
GSList *elem = registered_drivers;
|
|
||||||
struct libusb_device_descriptor dsc;
|
|
||||||
|
|
||||||
const struct usb_id *best_usb_id;
|
|
||||||
struct fp_driver *best_drv;
|
|
||||||
uint32_t best_devtype;
|
|
||||||
int drv_score = 0;
|
|
||||||
|
|
||||||
ret = libusb_get_device_descriptor(udev, &dsc);
|
|
||||||
if (ret < 0) {
|
|
||||||
fp_err("Failed to get device descriptor");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
best_drv = NULL;
|
|
||||||
best_devtype = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct fp_driver *drv = elem->data;
|
|
||||||
uint32_t type = 0;
|
|
||||||
const struct usb_id *id;
|
|
||||||
|
|
||||||
for (id = drv->id_table; id->vendor; id++) {
|
|
||||||
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
|
|
||||||
if (drv->discover) {
|
|
||||||
int r = drv->discover(&dsc, &type);
|
|
||||||
if (r < 0)
|
|
||||||
fp_err("%s discover failed, code %d", drv->name, r);
|
|
||||||
if (r <= 0)
|
|
||||||
continue;
|
|
||||||
/* Has a discover function, and matched our device */
|
|
||||||
drv_score = 100;
|
|
||||||
} else {
|
|
||||||
/* Already got a driver as good */
|
|
||||||
if (drv_score >= 50)
|
|
||||||
continue;
|
|
||||||
drv_score = 50;
|
|
||||||
}
|
|
||||||
fp_dbg("driver %s supports USB device %04x:%04x",
|
|
||||||
drv->name, id->vendor, id->product);
|
|
||||||
best_usb_id = id;
|
|
||||||
best_drv = drv;
|
|
||||||
best_devtype = type;
|
|
||||||
|
|
||||||
/* We found the best possible driver */
|
|
||||||
if (drv_score == 100)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
if (best_drv != NULL) {
|
|
||||||
fp_dbg("selected driver %s supports USB device %04x:%04x",
|
|
||||||
best_drv->name, dsc.idVendor, dsc.idProduct);
|
|
||||||
*devtype = best_devtype;
|
|
||||||
*usb_id = best_usb_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
|
|
||||||
{
|
|
||||||
const struct usb_id *usb_id;
|
|
||||||
struct fp_driver *drv;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
uint32_t devtype;
|
|
||||||
|
|
||||||
drv = find_supporting_driver(udev, &usb_id, &devtype);
|
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ddev = g_malloc0(sizeof(*ddev));
|
|
||||||
ddev->drv = drv;
|
|
||||||
ddev->udev = udev;
|
|
||||||
ddev->driver_data = usb_id->driver_data;
|
|
||||||
ddev->devtype = devtype;
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Scans the system and returns a list of discovered devices. This is your
|
|
||||||
* entry point into finding a fingerprint reader to operate.
|
|
||||||
* \returns a NULL-terminated list of discovered devices. Must be freed with
|
|
||||||
* fp_dscv_devs_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
|
||||||
{
|
|
||||||
GSList *tmplist = NULL;
|
|
||||||
struct fp_dscv_dev **list;
|
|
||||||
libusb_device *udev;
|
|
||||||
libusb_device **devs;
|
|
||||||
int dscv_count = 0;
|
|
||||||
int r;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (registered_drivers == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
r = libusb_get_device_list(fpi_usb_ctx, &devs);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("couldn't enumerate USB devices, error %d", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check each device against each driver, temporarily storing successfully
|
|
||||||
* discovered devices in a GSList.
|
|
||||||
*
|
|
||||||
* Quite inefficient but excusable as we'll only be dealing with small
|
|
||||||
* sets of drivers against small sets of USB devices */
|
|
||||||
while ((udev = devs[i++]) != NULL) {
|
|
||||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
|
||||||
if (!ddev)
|
|
||||||
continue;
|
|
||||||
tmplist = g_slist_prepend(tmplist, (gpointer) ddev);
|
|
||||||
dscv_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert our temporary GSList into a standard NULL-terminated pointer
|
|
||||||
* array. */
|
|
||||||
list = g_malloc(sizeof(*list) * (dscv_count + 1));
|
|
||||||
if (dscv_count > 0) {
|
|
||||||
GSList *elem = tmplist;
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
list[i++] = elem->data;
|
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
}
|
|
||||||
list[dscv_count] = NULL; /* NULL-terminate */
|
|
||||||
|
|
||||||
g_slist_free(tmplist);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Free a list of discovered devices. This function destroys the list and all
|
|
||||||
* discovered devices that it included, so make sure you have opened your
|
|
||||||
* discovered device <b>before</b> freeing the list.
|
|
||||||
* \param devs the list of discovered devices. If NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (!devs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; devs[i]; i++)
|
|
||||||
g_free(devs[i]);
|
|
||||||
g_free(devs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Gets the \ref drv "driver" for a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \returns the driver backing the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Gets the \ref devtype "devtype" for a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \returns the devtype of the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
switch (drv->type) {
|
|
||||||
case DRIVER_PRIMITIVE:
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
case DRIVER_IMAGING:
|
|
||||||
return PRINT_DATA_NBIS_MINUTIAE;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised drv type %d", drv->type);
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Determines if a specific \ref print_data "stored print" appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \param data the print for compatibility checking
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
|
||||||
data->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Determines if a specific \ref dscv_print "discovered print" appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \param data the discovered print for compatibility checking
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_dscv_print *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
|
|
||||||
data->driver_id, data->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a \ref print_data "stored print".
|
|
||||||
* \param devs a list of discovered devices
|
|
||||||
* \param data the print under inspection
|
|
||||||
* \returns the first discovered device that appears to support the print, or
|
|
||||||
* NULL if no apparently compatible devices could be found
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; (ddev = devs[i]); i++)
|
|
||||||
if (fp_dscv_dev_supports_print_data(ddev, data))
|
|
||||||
return ddev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a \ref dscv_print "discovered print".
|
|
||||||
* \param devs a list of discovered devices
|
|
||||||
* \param print the print under inspection
|
|
||||||
* \returns the first discovered device that appears to support the print, or
|
|
||||||
* NULL if no apparently compatible devices could be found
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
|
|
||||||
struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; (ddev = devs[i]); i++)
|
|
||||||
if (fp_dscv_dev_supports_dscv_print(ddev, print))
|
|
||||||
return ddev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Get the \ref drv "driver" for a fingerprint device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the driver controlling the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the number of \ref enrolling "enroll stages" required to enroll a
|
|
||||||
* fingerprint with the device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the number of enroll stages
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the \ref devtype "devtype" for a device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the devtype
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a stored print is compatible with a certain device.
|
|
||||||
* \param dev the device
|
|
||||||
* \param data the stored print
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 if not
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
|
||||||
data->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a \ref dscv_print "discovered print" appears to be compatible
|
|
||||||
* with a certain device.
|
|
||||||
* \param dev the device
|
|
||||||
* \param data the discovered print
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 if not
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
|
|
||||||
struct fp_dscv_print *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
0, data->driver_id, data->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the name of the driver. For example: "upekts"
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the driver name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the descriptive name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->full_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the driver ID code for a driver.
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the driver ID
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the scan type for the devices associated with the driver.
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the scan type
|
|
||||||
*/
|
|
||||||
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->scan_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
if (dev->drv->type != DRIVER_IMAGING)
|
|
||||||
return NULL;
|
|
||||||
return dev->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a device has imaging capabilities. If a device has imaging
|
|
||||||
* capabilities you are able to perform imaging operations such as retrieving
|
|
||||||
* scan images using fp_dev_img_capture(). However, not all devices are
|
|
||||||
* imaging devices - some do all processing in hardware. This function will
|
|
||||||
* indicate which class a device in question falls into.
|
|
||||||
* \param dev the fingerprint device
|
|
||||||
* \returns 1 if the device is an imaging device, 0 if the device does not
|
|
||||||
* provide images to the host computer
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv->type == DRIVER_IMAGING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a device is capable of \ref identification "identification"
|
|
||||||
* through fp_identify_finger() and similar. Not all devices support this
|
|
||||||
* functionality.
|
|
||||||
* \param dev the fingerprint device
|
|
||||||
* \returns 1 if the device is capable of identification, 0 otherwise.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv->identify_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Captures an \ref img "image" from a device. The returned image is the raw
|
|
||||||
* image provided by the device, you may wish to \ref img_std "standardize" it.
|
|
||||||
*
|
|
||||||
* If set, the <tt>unconditional</tt> flag indicates that the device should
|
|
||||||
* capture an image unconditionally, regardless of whether a finger is there
|
|
||||||
* or not. If unset, this function will block until a finger is detected on
|
|
||||||
* the sensor.
|
|
||||||
*
|
|
||||||
* \param dev the device
|
|
||||||
* \param unconditional whether to unconditionally capture an image, or to only capture when a finger is detected
|
|
||||||
* \param image a location to return the captured image. Must be freed with
|
|
||||||
* fp_img_free() after use.
|
|
||||||
* \return 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
|
||||||
* unconditional flag was set but the device does not support this, or that the
|
|
||||||
* device does not support imaging.
|
|
||||||
* \sa fp_dev_supports_imaging()
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
|
|
||||||
struct fp_img **image)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
|
||||||
if (!imgdev) {
|
|
||||||
fp_dbg("image capture on non-imaging device");
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
//return fpi_imgdev_capture(imgdev, unconditional, image);
|
|
||||||
/* FIXME reimplement async */
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the expected width of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* \ref imaging "imaging devices". If the width of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the expected image width, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
|
||||||
if (!imgdev) {
|
|
||||||
fp_dbg("get image width for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_width(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the expected height of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* \ref imaging "imaging devices". If the height of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the expected image height, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
|
||||||
if (!imgdev) {
|
|
||||||
fp_dbg("get image height for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_height(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Set message verbosity.
|
|
||||||
* - Level 0: no messages ever printed by the library (default)
|
|
||||||
* - Level 1: error messages are printed to stderr
|
|
||||||
* - Level 2: warning and error messages are printed to stderr
|
|
||||||
* - Level 3: informational messages are printed to stdout, warning and error
|
|
||||||
* messages are printed to stderr
|
|
||||||
*
|
|
||||||
* The default level is 0, which means no messages are ever printed. If you
|
|
||||||
* choose to increase the message verbosity level, ensure that your
|
|
||||||
* application does not close the stdout/stderr file descriptors.
|
|
||||||
*
|
|
||||||
* You are advised to set level 3. libfprint is conservative with its message
|
|
||||||
* logging and most of the time, will only log messages that explain error
|
|
||||||
* conditions and other oddities. This will help you debug your software.
|
|
||||||
*
|
|
||||||
* If the LIBFPRINT_DEBUG environment variable was set when libfprint was
|
|
||||||
* initialized, this function does nothing: the message verbosity is fixed
|
|
||||||
* to the value in the environment variable.
|
|
||||||
*
|
|
||||||
* If libfprint was compiled without any message logging, this function does
|
|
||||||
* nothing: you'll never get any messages.
|
|
||||||
*
|
|
||||||
* If libfprint was compiled with verbose debug message logging, this function
|
|
||||||
* does nothing: you'll always get messages from all levels.
|
|
||||||
*
|
|
||||||
* \param ctx the context to operate on, or NULL for the default context
|
|
||||||
* \param level debug level to set
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_set_debug(int level)
|
|
||||||
{
|
|
||||||
if (log_level_fixed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
log_level = level;
|
|
||||||
libusb_set_debug(fpi_usb_ctx, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Initialise libfprint. This function must be called before you attempt to
|
|
||||||
* use the library in any way.
|
|
||||||
* \return 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_init(void)
|
|
||||||
{
|
|
||||||
char *dbg = getenv("LIBFPRINT_DEBUG");
|
|
||||||
int r;
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
r = libusb_init(&fpi_usb_ctx);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (dbg) {
|
|
||||||
log_level = atoi(dbg);
|
|
||||||
if (log_level) {
|
|
||||||
log_level_fixed = 1;
|
|
||||||
libusb_set_debug(fpi_usb_ctx, log_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register_drivers();
|
|
||||||
fpi_poll_init();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Deinitialise libfprint. This function should be called during your program
|
|
||||||
* exit sequence. You must not use any libfprint functions after calling this
|
|
||||||
* function, unless you call fp_init() again.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_exit(void)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
if (opened_devices) {
|
|
||||||
GSList *copy = g_slist_copy(opened_devices);
|
|
||||||
GSList *elem = copy;
|
|
||||||
fp_dbg("naughty app left devices open on exit!");
|
|
||||||
|
|
||||||
do
|
|
||||||
fp_dev_close((struct fp_dev *) elem->data);
|
|
||||||
while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
g_slist_free(copy);
|
|
||||||
g_slist_free(opened_devices);
|
|
||||||
opened_devices = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_data_exit();
|
|
||||||
fpi_poll_exit();
|
|
||||||
g_slist_free(registered_drivers);
|
|
||||||
registered_drivers = NULL;
|
|
||||||
libusb_exit(fpi_usb_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
684
libfprint/data.c
@@ -1,684 +0,0 @@
|
|||||||
/*
|
|
||||||
* Fingerprint data handling and storage
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
#define DIR_PERMS 0700
|
|
||||||
|
|
||||||
/** @defgroup print_data Stored prints
|
|
||||||
* Stored prints are represented by a structure named <tt>fp_print_data</tt>.
|
|
||||||
* Stored prints are originally obtained from an enrollment function such as
|
|
||||||
* fp_enroll_finger().
|
|
||||||
*
|
|
||||||
* This page documents the various operations you can do with a stored print.
|
|
||||||
* Note that by default, "stored prints" are not actually stored anywhere
|
|
||||||
* except in RAM. For the simple scenarios, libfprint provides a simple API
|
|
||||||
* for you to save and load the stored prints referring to a single user in
|
|
||||||
* their home directory. For more advanced users, libfprint provides APIs for
|
|
||||||
* you to convert print data to a byte string, and to reconstruct stored prints
|
|
||||||
* from such data at a later point. You are welcome to store these byte strings
|
|
||||||
* in any fashion that suits you.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static char *base_store = NULL;
|
|
||||||
|
|
||||||
static void storage_setup(void)
|
|
||||||
{
|
|
||||||
const char *homedir;
|
|
||||||
|
|
||||||
homedir = g_getenv("HOME");
|
|
||||||
if (!homedir)
|
|
||||||
homedir = g_get_home_dir();
|
|
||||||
if (!homedir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
base_store = g_build_filename(homedir, ".fprint/prints", NULL);
|
|
||||||
g_mkdir_with_parents(base_store, DIR_PERMS);
|
|
||||||
/* FIXME handle failure */
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_data_exit(void)
|
|
||||||
{
|
|
||||||
g_free(base_store);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FP_FINGER_IS_VALID(finger) \
|
|
||||||
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
|
|
||||||
|
|
||||||
/* for debug messages only */
|
|
||||||
#ifdef ENABLE_DEBUG_LOGGING
|
|
||||||
static const char *finger_num_to_str(enum fp_finger finger)
|
|
||||||
{
|
|
||||||
const char *names[] = {
|
|
||||||
[LEFT_THUMB] = "left thumb",
|
|
||||||
[LEFT_INDEX] = "left index",
|
|
||||||
[LEFT_MIDDLE] = "left middle",
|
|
||||||
[LEFT_RING] = "left ring",
|
|
||||||
[LEFT_LITTLE] = "left little",
|
|
||||||
[RIGHT_THUMB] = "right thumb",
|
|
||||||
[RIGHT_INDEX] = "right index",
|
|
||||||
[RIGHT_MIDDLE] = "right middle",
|
|
||||||
[RIGHT_RING] = "right ring",
|
|
||||||
[RIGHT_LITTLE] = "right little",
|
|
||||||
};
|
|
||||||
if (!FP_FINGER_IS_VALID(finger))
|
|
||||||
return "UNKNOWN";
|
|
||||||
return names[finger];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
|
||||||
uint32_t devtype, enum fp_print_data_type type, size_t length)
|
|
||||||
{
|
|
||||||
struct fp_print_data *data = g_malloc0(sizeof(*data) + length);
|
|
||||||
fp_dbg("length=%zd driver=%02x devtype=%04x", length, driver_id, devtype);
|
|
||||||
data->driver_id = driver_id;
|
|
||||||
data->devtype = devtype;
|
|
||||||
data->type = type;
|
|
||||||
data->length = length;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length)
|
|
||||||
{
|
|
||||||
return print_data_new(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Convert a stored print into a unified representation inside a data buffer.
|
|
||||||
* You can then store this data buffer in any way that suits you, and load
|
|
||||||
* it back at some later time using fp_print_data_from_data().
|
|
||||||
* \param data the stored print
|
|
||||||
* \param ret output location for the data buffer. Must be freed with free()
|
|
||||||
* after use.
|
|
||||||
* \returns the size of the freshly allocated buffer, or 0 on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
|
||||||
unsigned char **ret)
|
|
||||||
{
|
|
||||||
struct fpi_print_data_fp1 *buf;
|
|
||||||
size_t buflen;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
buflen = sizeof(*buf) + data->length;
|
|
||||||
buf = malloc(buflen);
|
|
||||||
if (!buf)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*ret = (unsigned char *) buf;
|
|
||||||
buf->prefix[0] = 'F';
|
|
||||||
buf->prefix[1] = 'P';
|
|
||||||
buf->prefix[2] = '1';
|
|
||||||
buf->driver_id = GUINT16_TO_LE(data->driver_id);
|
|
||||||
buf->devtype = GUINT32_TO_LE(data->devtype);
|
|
||||||
buf->data_type = data->type;
|
|
||||||
memcpy(buf->data, data->data, data->length);
|
|
||||||
return buflen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Load a stored print from a data buffer. The contents of said buffer must
|
|
||||||
* be the untouched contents of a buffer previously supplied to you by the
|
|
||||||
* fp_print_data_get_data() function.
|
|
||||||
* \param buf the data buffer
|
|
||||||
* \param buflen the length of the buffer
|
|
||||||
* \returns the stored print represented by the data, or NULL on error. Must
|
|
||||||
* be freed with fp_print_data_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
struct fpi_print_data_fp1 *raw = (struct fpi_print_data_fp1 *) buf;
|
|
||||||
size_t print_data_len;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
|
|
||||||
fp_dbg("buffer size %zd", buflen);
|
|
||||||
if (buflen < sizeof(*raw))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (strncmp(raw->prefix, "FP1", 3) != 0) {
|
|
||||||
fp_dbg("bad header prefix");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_data_len = buflen - sizeof(*raw);
|
|
||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type, print_data_len);
|
|
||||||
memcpy(data->data, raw->data, print_data_len);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
|
|
||||||
{
|
|
||||||
char idstr[5];
|
|
||||||
char devtypestr[9];
|
|
||||||
|
|
||||||
g_snprintf(idstr, sizeof(idstr), "%04x", driver_id);
|
|
||||||
g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype);
|
|
||||||
|
|
||||||
return g_build_filename(base_store, idstr, devtypestr, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype,
|
|
||||||
enum fp_finger finger)
|
|
||||||
{
|
|
||||||
char *dirpath;
|
|
||||||
char *path;
|
|
||||||
char fingername[2];
|
|
||||||
|
|
||||||
g_snprintf(fingername, 2, "%x", finger);
|
|
||||||
|
|
||||||
dirpath = get_path_to_storedir(driver_id, devtype);
|
|
||||||
path = g_build_filename(dirpath, fingername, NULL);
|
|
||||||
g_free(dirpath);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
|
|
||||||
{
|
|
||||||
return __get_path_to_print(dev->drv->id, dev->devtype, finger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Saves a stored print to disk, assigned to a specific finger. Even though
|
|
||||||
* you are limited to storing only the 10 human fingers, this is a
|
|
||||||
* per-device-type limit. For example, you can store the users right index
|
|
||||||
* finger from a DigitalPersona scanner, and you can also save the right index
|
|
||||||
* finger from a UPEK scanner. When you later come to load the print, the right
|
|
||||||
* one will be automatically selected.
|
|
||||||
*
|
|
||||||
* This function will unconditionally overwrite a fingerprint previously
|
|
||||||
* saved for the same finger and device type. The print is saved in a hidden
|
|
||||||
* directory beneath the current user's home directory.
|
|
||||||
* \param data the stored print to save to disk
|
|
||||||
* \param finger the finger that this print corresponds to
|
|
||||||
* \returns 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
|
||||||
enum fp_finger finger)
|
|
||||||
{
|
|
||||||
GError *err = NULL;
|
|
||||||
char *path;
|
|
||||||
char *dirpath;
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t len;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!base_store)
|
|
||||||
storage_setup();
|
|
||||||
|
|
||||||
fp_dbg("save %s print from driver %04x", finger_num_to_str(finger),
|
|
||||||
data->driver_id);
|
|
||||||
len = fp_print_data_get_data(data, &buf);
|
|
||||||
if (!len)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
path = __get_path_to_print(data->driver_id, data->devtype, finger);
|
|
||||||
dirpath = g_path_get_dirname(path);
|
|
||||||
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("couldn't create storage directory");
|
|
||||||
g_free(path);
|
|
||||||
g_free(dirpath);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("saving to %s", path);
|
|
||||||
g_file_set_contents(path, buf, len, &err);
|
|
||||||
free(buf);
|
|
||||||
g_free(dirpath);
|
|
||||||
g_free(path);
|
|
||||||
if (err) {
|
|
||||||
r = err->code;
|
|
||||||
fp_err("save failed: %s", err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
/* FIXME interpret error codes */
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
|
||||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
|
||||||
enum fp_print_data_type type2)
|
|
||||||
{
|
|
||||||
if (driver_id1 != driver_id2) {
|
|
||||||
fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (devtype1 != devtype2) {
|
|
||||||
fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type1 != type2) {
|
|
||||||
fp_dbg("type mismatch: %d vs %d", type1, type2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_from_file(char *path, struct fp_print_data **data)
|
|
||||||
{
|
|
||||||
gsize length;
|
|
||||||
gchar *contents;
|
|
||||||
GError *err = NULL;
|
|
||||||
struct fp_print_data *fdata;
|
|
||||||
|
|
||||||
fp_dbg("from %s", path);
|
|
||||||
g_file_get_contents(path, &contents, &length, &err);
|
|
||||||
if (err) {
|
|
||||||
int r = err->code;
|
|
||||||
fp_err("%s load failed: %s", path, err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
/* FIXME interpret more error codes */
|
|
||||||
if (r == G_FILE_ERROR_NOENT)
|
|
||||||
return -ENOENT;
|
|
||||||
else
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
fdata = fp_print_data_from_data(contents, length);
|
|
||||||
g_free(contents);
|
|
||||||
if (!fdata)
|
|
||||||
return -EIO;
|
|
||||||
*data = fdata;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Loads a previously stored print from disk. The print must have been saved
|
|
||||||
* earlier using the fp_print_data_save() function.
|
|
||||||
*
|
|
||||||
* A return code of -ENOENT indicates that the fingerprint requested could not
|
|
||||||
* be found. Other error codes (both positive and negative) are possible for
|
|
||||||
* obscure error conditions (e.g. corruption).
|
|
||||||
*
|
|
||||||
* \param dev the device you are loading the print for
|
|
||||||
* \param finger the finger of the file you are loading
|
|
||||||
* \param data output location to put the corresponding stored print. Must be
|
|
||||||
* freed with fp_print_data_free() after use.
|
|
||||||
* \returns 0 on success, non-zero on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
|
||||||
enum fp_finger finger, struct fp_print_data **data)
|
|
||||||
{
|
|
||||||
gchar *path;
|
|
||||||
struct fp_print_data *fdata;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!base_store)
|
|
||||||
storage_setup();
|
|
||||||
|
|
||||||
path = get_path_to_print(dev, finger);
|
|
||||||
r = load_from_file(path, &fdata);
|
|
||||||
g_free(path);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!fp_dev_supports_print_data(dev, fdata)) {
|
|
||||||
fp_err("print data is not compatible!");
|
|
||||||
fp_print_data_free(fdata);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = fdata;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Removes a stored print from disk previously saved with fp_print_data_save().
|
|
||||||
* \param dev the device that the print belongs to
|
|
||||||
* \param finger the finger of the file you are deleting
|
|
||||||
* \returns 0 on success, negative on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
|
||||||
enum fp_finger finger)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
gchar *path = get_path_to_print(dev, finger);
|
|
||||||
|
|
||||||
fp_dbg("remove finger %d at %s", finger, path);
|
|
||||||
r = g_unlink(path);
|
|
||||||
g_free(path);
|
|
||||||
if (r < 0)
|
|
||||||
fp_dbg("unlink failed with error %d", r);
|
|
||||||
|
|
||||||
/* FIXME: cleanup empty directory */
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Attempts to load a stored print based on a \ref dscv_print
|
|
||||||
* "discovered print" record.
|
|
||||||
*
|
|
||||||
* A return code of -ENOENT indicates that the file referred to by the
|
|
||||||
* discovered print could not be found. Other error codes (both positive and
|
|
||||||
* negative) are possible for obscure error conditions (e.g. corruption).
|
|
||||||
*
|
|
||||||
* \param print the discovered print
|
|
||||||
* \param data output location to point to the corresponding stored print. Must
|
|
||||||
* be freed with fp_print_data_free() after use.
|
|
||||||
* \returns 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
|
||||||
struct fp_print_data **data)
|
|
||||||
{
|
|
||||||
return load_from_file(print->path, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Frees a stored print. Must be called when you are finished using the print.
|
|
||||||
* \param data the stored print to destroy. If NULL, function simply returns.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
g_free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Gets the \ref driver_id "driver ID" for a stored print. The driver ID
|
|
||||||
* indicates which driver the print originally came from. The print is
|
|
||||||
* only usable with a device controlled by that driver.
|
|
||||||
* \param data the stored print
|
|
||||||
* \returns the driver ID of the driver compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return data->driver_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup print_data
|
|
||||||
* Gets the \ref devtype "devtype" for a stored print. The devtype represents
|
|
||||||
* which type of device under the parent driver is compatible with the print.
|
|
||||||
* \param data the stored print
|
|
||||||
* \returns the devtype of the device range compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return data->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @defgroup dscv_print Print discovery
|
|
||||||
* The \ref print_data "stored print" documentation detailed a simple API
|
|
||||||
* for storing per-device prints for a single user, namely
|
|
||||||
* fp_print_data_save(). It also detailed a load function,
|
|
||||||
* fp_print_data_load(), but usage of this function is limited to scenarios
|
|
||||||
* where you know which device you would like to use, and you know which
|
|
||||||
* finger you are looking to verify.
|
|
||||||
*
|
|
||||||
* In other cases, it would be more useful to be able to enumerate all
|
|
||||||
* previously saved prints, potentially even before device discovery. These
|
|
||||||
* functions are designed to offer this functionality to you.
|
|
||||||
*
|
|
||||||
* Discovered prints are stored in a <tt>dscv_print</tt> structure, and you
|
|
||||||
* can use functions documented below to access some information about these
|
|
||||||
* prints. You can determine if a discovered print appears to be compatible
|
|
||||||
* with a device using functions such as fp_dscv_dev_supports_dscv_print() and
|
|
||||||
* fp_dev_supports_dscv_print().
|
|
||||||
*
|
|
||||||
* When you are ready to use the print, you can load it into memory in the form
|
|
||||||
* of a stored print by using the fp_print_data_from_dscv_print() function.
|
|
||||||
*
|
|
||||||
* You may have noticed the use of the word "appears" in the above paragraphs.
|
|
||||||
* libfprint performs print discovery simply by examining the file and
|
|
||||||
* directory structure of libfprint's private data store. It does not examine
|
|
||||||
* the actual prints themselves. Just because a print has been discovered
|
|
||||||
* and appears to be compatible with a certain device does not necessarily mean
|
|
||||||
* that it is usable; when you come to load or use it, under unusual
|
|
||||||
* circumstances it may turn out that the print is corrupt or not for the
|
|
||||||
* device that it appeared to be. Also, it is possible that the print may have
|
|
||||||
* been deleted by the time you come to load it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
|
|
||||||
uint32_t devtype, GSList *list)
|
|
||||||
{
|
|
||||||
GError *err = NULL;
|
|
||||||
const gchar *ent;
|
|
||||||
struct fp_dscv_print *print;
|
|
||||||
|
|
||||||
GDir *dir = g_dir_open(devpath, 0, &err);
|
|
||||||
if (!dir) {
|
|
||||||
fp_err("opendir %s failed: %s", devpath, err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = g_dir_read_name(dir))) {
|
|
||||||
/* ent is an 1 hex character fp_finger code */
|
|
||||||
guint64 val;
|
|
||||||
enum fp_finger finger;
|
|
||||||
gchar *endptr;
|
|
||||||
|
|
||||||
if (*ent == 0 || strlen(ent) != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
val = g_ascii_strtoull(ent, &endptr, 16);
|
|
||||||
if (endptr == ent || !FP_FINGER_IS_VALID(val)) {
|
|
||||||
fp_dbg("skipping print file %s", ent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
finger = (enum fp_finger) val;
|
|
||||||
print = g_malloc(sizeof(*print));
|
|
||||||
print->driver_id = driver_id;
|
|
||||||
print->devtype = devtype;
|
|
||||||
print->path = g_build_filename(devpath, ent, NULL);
|
|
||||||
print->finger = finger;
|
|
||||||
list = g_slist_prepend(list, print);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close(dir);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
|
|
||||||
GSList *list)
|
|
||||||
{
|
|
||||||
GError *err = NULL;
|
|
||||||
const gchar *ent;
|
|
||||||
|
|
||||||
GDir *dir = g_dir_open(drvpath, 0, &err);
|
|
||||||
if (!dir) {
|
|
||||||
fp_err("opendir %s failed: %s", drvpath, err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = g_dir_read_name(dir))) {
|
|
||||||
/* ent is an 8 hex character devtype */
|
|
||||||
guint64 val;
|
|
||||||
uint32_t devtype;
|
|
||||||
gchar *endptr;
|
|
||||||
gchar *path;
|
|
||||||
|
|
||||||
if (*ent == 0 || strlen(ent) != 8)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
val = g_ascii_strtoull(ent, &endptr, 16);
|
|
||||||
if (endptr == ent) {
|
|
||||||
fp_dbg("skipping devtype %s", ent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
devtype = (uint32_t) val;
|
|
||||||
path = g_build_filename(drvpath, ent, NULL);
|
|
||||||
list = scan_dev_store_dir(path, driver_id, devtype, list);
|
|
||||||
g_free(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close(dir);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Scans the users home directory and returns a list of prints that were
|
|
||||||
* previously saved using fp_print_data_save().
|
|
||||||
* \returns a NULL-terminated list of discovered prints, must be freed with
|
|
||||||
* fp_dscv_prints_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
|
||||||
{
|
|
||||||
GDir *dir;
|
|
||||||
const gchar *ent;
|
|
||||||
GError *err = NULL;
|
|
||||||
GSList *tmplist = NULL;
|
|
||||||
GSList *elem;
|
|
||||||
unsigned int tmplist_len;
|
|
||||||
struct fp_dscv_print **list;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (!base_store)
|
|
||||||
storage_setup();
|
|
||||||
|
|
||||||
dir = g_dir_open(base_store, 0, &err);
|
|
||||||
if (!dir) {
|
|
||||||
fp_err("opendir %s failed: %s", base_store, err->message);
|
|
||||||
g_error_free(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = g_dir_read_name(dir))) {
|
|
||||||
/* ent is a 4 hex digit driver_id */
|
|
||||||
gchar *endptr;
|
|
||||||
gchar *path;
|
|
||||||
guint64 val;
|
|
||||||
uint16_t driver_id;
|
|
||||||
|
|
||||||
if (*ent == 0 || strlen(ent) != 4)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
val = g_ascii_strtoull(ent, &endptr, 16);
|
|
||||||
if (endptr == ent) {
|
|
||||||
fp_dbg("skipping drv id %s", ent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
driver_id = (uint16_t) val;
|
|
||||||
path = g_build_filename(base_store, ent, NULL);
|
|
||||||
tmplist = scan_driver_store_dir(path, driver_id, tmplist);
|
|
||||||
g_free(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close(dir);
|
|
||||||
tmplist_len = g_slist_length(tmplist);
|
|
||||||
list = g_malloc(sizeof(*list) * (tmplist_len + 1));
|
|
||||||
elem = tmplist;
|
|
||||||
for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
|
|
||||||
list[i] = elem->data;
|
|
||||||
list[tmplist_len] = NULL; /* NULL-terminate */
|
|
||||||
|
|
||||||
g_slist_free(tmplist);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Frees a list of discovered prints. This function also frees the discovered
|
|
||||||
* prints themselves, so make sure you do not use any discovered prints
|
|
||||||
* after calling this function.
|
|
||||||
* \param prints the list of discovered prints. If NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct fp_dscv_print *print;
|
|
||||||
|
|
||||||
if (!prints)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; (print = prints[i]); i++) {
|
|
||||||
if (print)
|
|
||||||
g_free(print->path);
|
|
||||||
g_free(print);
|
|
||||||
}
|
|
||||||
g_free(prints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Gets the \ref driver_id "driver ID" for a discovered print. The driver ID
|
|
||||||
* indicates which driver the print originally came from. The print is only
|
|
||||||
* usable with a device controlled by that driver.
|
|
||||||
* \param print the discovered print
|
|
||||||
* \returns the driver ID of the driver compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->driver_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Gets the \ref devtype "devtype" for a discovered print. The devtype
|
|
||||||
* represents which type of device under the parent driver is compatible
|
|
||||||
* with the print.
|
|
||||||
* \param print the discovered print
|
|
||||||
* \returns the devtype of the device range compatible with the print
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Gets the finger code for a discovered print.
|
|
||||||
* \param print discovered print
|
|
||||||
* \returns a finger code from #fp_finger
|
|
||||||
*/
|
|
||||||
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->finger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
|
||||||
* Removes a discovered print from disk. After successful return of this
|
|
||||||
* function, functions such as fp_dscv_print_get_finger() will continue to
|
|
||||||
* operate as before, however calling fp_print_data_from_dscv_print() will
|
|
||||||
* fail for obvious reasons.
|
|
||||||
* \param print the discovered print to remove from disk
|
|
||||||
* \returns 0 on success, negative on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
fp_dbg("remove at %s", print->path);
|
|
||||||
r = g_unlink(print->path);
|
|
||||||
if (r < 0)
|
|
||||||
fp_dbg("unlink failed with error %d", r);
|
|
||||||
|
|
||||||
/* FIXME: cleanup empty directory */
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -19,99 +19,77 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes1660"
|
#define FP_COMPONENT "aes1660"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aesx660.h"
|
#include "aesx660.h"
|
||||||
#include "aes1660.h"
|
#include "aes1660.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define FRAME_WIDTH 128
|
#define FRAME_WIDTH 128
|
||||||
#define SCALE_FACTOR 2
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
struct _FpiDeviceAes1660
|
||||||
{
|
{
|
||||||
/* TODO check that device has endpoints we're using */
|
FpiDeviceAesX660 parent;
|
||||||
int r;
|
};
|
||||||
struct aesX660_dev *aesdev;
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI,
|
||||||
|
DEVICE_AES1660, FpiDeviceAesX660);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660);
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
if (r < 0) {
|
.frame_width = FRAME_WIDTH,
|
||||||
fp_err("could not claim interface 0");
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
return r;
|
.image_width = IMAGE_WIDTH,
|
||||||
}
|
.get_pixel = aes_get_pixel,
|
||||||
|
|
||||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
|
||||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
|
||||||
aesdev->h_scale_factor = SCALE_FACTOR;
|
|
||||||
aesdev->init_seqs[0] = aes1660_init_1;
|
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
|
||||||
aesdev->init_seqs[1] = aes1660_init_2;
|
|
||||||
aesdev->init_seqs_len[1] = array_n_elements(aes1660_init_2);
|
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
|
||||||
g_free(aesdev->buffer);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(dev->udev, 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1660 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1680 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1681 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1682 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1683 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1684 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1685 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1686 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1687 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1688 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x1689 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168a },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168b },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168c },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168d },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168e },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x168f },
|
|
||||||
{ 0, 0, 0, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes1660_driver = {
|
static const FpIdEntry id_table[] = {
|
||||||
.driver = {
|
{ .vid = 0x08ff, .pid = 0x1660, },
|
||||||
.id = AES1660_ID,
|
{ .vid = 0x08ff, .pid = 0x1680, },
|
||||||
.name = FP_COMPONENT,
|
{ .vid = 0x08ff, .pid = 0x1681, },
|
||||||
.full_name = "AuthenTec AES1660",
|
{ .vid = 0x08ff, .pid = 0x1682, },
|
||||||
.id_table = id_table,
|
{ .vid = 0x08ff, .pid = 0x1683, },
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{ .vid = 0x08ff, .pid = 0x1684, },
|
||||||
},
|
{ .vid = 0x08ff, .pid = 0x1685, },
|
||||||
.flags = 0,
|
{ .vid = 0x08ff, .pid = 0x1686, },
|
||||||
.img_height = -1,
|
{ .vid = 0x08ff, .pid = 0x1687, },
|
||||||
.img_width = FRAME_WIDTH * SCALE_FACTOR,
|
{ .vid = 0x08ff, .pid = 0x1688, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x1689, },
|
||||||
/* temporarily lowered until we sort out image processing code
|
{ .vid = 0x08ff, .pid = 0x168a, },
|
||||||
* binarized scan quality is good, minutiae detection is accurate,
|
{ .vid = 0x08ff, .pid = 0x168b, },
|
||||||
* it's just that we get fewer minutiae than other scanners (less scanning
|
{ .vid = 0x08ff, .pid = 0x168c, },
|
||||||
* area) */
|
{ .vid = 0x08ff, .pid = 0x168d, },
|
||||||
.bz3_threshold = 25,
|
{ .vid = 0x08ff, .pid = 0x168e, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x168f, },
|
||||||
.open = dev_init,
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
.close = dev_deinit,
|
|
||||||
.activate = aesX660_dev_activate,
|
|
||||||
.deactivate = aesX660_dev_deactivate,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes1660_init (FpiDeviceAes1660 *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = "aes1660";
|
||||||
|
dev_class->full_name = "AuthenTec AES1660";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
|
img_class->bz3_threshold = 20;
|
||||||
|
|
||||||
|
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
|
||||||
|
aes_class->init_seqs[0] = aes1660_init_1;
|
||||||
|
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes1660_init_1);
|
||||||
|
aes_class->init_seqs[1] = aes1660_init_2;
|
||||||
|
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes1660_init_2);
|
||||||
|
aes_class->start_imaging_cmd = (unsigned char *) aes1660_start_imaging_cmd;
|
||||||
|
aes_class->start_imaging_cmd_len = sizeof (aes1660_start_imaging_cmd);
|
||||||
|
aes_class->assembling_ctx = &assembling_ctx;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,158 +19,155 @@
|
|||||||
* 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,
|
||||||
AES2501_REG_CTRL2 = 0x81,
|
AES2501_REG_CTRL2 = 0x81,
|
||||||
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
|
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
|
||||||
AES2501_REG_DETCTRL = 0x83, /* detect control */
|
AES2501_REG_DETCTRL = 0x83, /* detect control */
|
||||||
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
|
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
|
||||||
AES2501_REG_MEASDRV = 0x89, /* measure drive */
|
AES2501_REG_MEASDRV = 0x89, /* measure drive */
|
||||||
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
|
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
|
||||||
AES2501_REG_DEMODPHASE1 = 0x8d,
|
AES2501_REG_DEMODPHASE1 = 0x8d,
|
||||||
AES2501_REG_DEMODPHASE2 = 0x8c,
|
AES2501_REG_DEMODPHASE2 = 0x8c,
|
||||||
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
|
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
|
||||||
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
|
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
|
||||||
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
|
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
|
||||||
AES2501_REG_STRTROW = 0x93, /* start row */
|
AES2501_REG_STRTROW = 0x93, /* start row */
|
||||||
AES2501_REG_ENDROW = 0x94, /* end row */
|
AES2501_REG_ENDROW = 0x94, /* end row */
|
||||||
AES2501_REG_STRTCOL = 0x95, /* start column */
|
AES2501_REG_STRTCOL = 0x95, /* start column */
|
||||||
AES2501_REG_ENDCOL = 0x96, /* end column */
|
AES2501_REG_ENDCOL = 0x96, /* end column */
|
||||||
AES2501_REG_DATFMT = 0x97, /* data format */
|
AES2501_REG_DATFMT = 0x97, /* data format */
|
||||||
AES2501_REG_IMAGCTRL = 0x98, /* image data */
|
AES2501_REG_IMAGCTRL = 0x98, /* image data */
|
||||||
AES2501_REG_STAT = 0x9a,
|
AES2501_REG_STAT = 0x9a,
|
||||||
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
|
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
|
||||||
AES2501_REG_CHWORD2 = 0x9c,
|
AES2501_REG_CHWORD2 = 0x9c,
|
||||||
AES2501_REG_CHWORD3 = 0x9d,
|
AES2501_REG_CHWORD3 = 0x9d,
|
||||||
AES2501_REG_CHWORD4 = 0x9e,
|
AES2501_REG_CHWORD4 = 0x9e,
|
||||||
AES2501_REG_CHWORD5 = 0x9f,
|
AES2501_REG_CHWORD5 = 0x9f,
|
||||||
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
|
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
|
||||||
AES2501_REG_AUTOCALOFFSET = 0xa8,
|
AES2501_REG_AUTOCALOFFSET = 0xa8,
|
||||||
AES2501_REG_TREGC = 0xac,
|
AES2501_REG_TREGC = 0xac,
|
||||||
AES2501_REG_TREGD = 0xad,
|
AES2501_REG_TREGD = 0xad,
|
||||||
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
|
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FIRST_AES2501_REG AES2501_REG_CTRL1
|
#define FIRST_AES2501_REG AES2501_REG_CTRL1
|
||||||
#define LAST_AES2501_REG AES2501_REG_CHWORD5
|
#define LAST_AES2501_REG AES2501_REG_CHWORD5
|
||||||
|
|
||||||
#define AES2501_CTRL1_MASTER_RESET (1<<0)
|
#define AES2501_CTRL1_MASTER_RESET (1 << 0)
|
||||||
#define AES2501_CTRL1_SCAN_RESET (1<<1) /* stop + restart scan sequencer */
|
#define AES2501_CTRL1_SCAN_RESET (1 << 1) /* stop + restart scan sequencer */
|
||||||
/* 1 = continuously updated, 0 = updated prior to starting a scan */
|
/* 1 = continuously updated, 0 = updated prior to starting a scan */
|
||||||
#define AES2501_CTRL1_REG_UPDATE (1<<2)
|
#define AES2501_CTRL1_REG_UPDATE (1 << 2)
|
||||||
|
|
||||||
/* 1 = continuous scans, 0 = single scans */
|
/* 1 = continuous scans, 0 = single scans */
|
||||||
#define AES2501_CTRL2_CONTINUOUS 0x01
|
#define AES2501_CTRL2_CONTINUOUS 0x01
|
||||||
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
|
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
|
||||||
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
|
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
|
||||||
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
|
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
|
||||||
#define AES2501_CTRL2_READ_ID 0x10
|
#define AES2501_CTRL2_READ_ID 0x10
|
||||||
|
|
||||||
enum aes2501_detection_rate {
|
enum aes2501_detection_rate {
|
||||||
/* rate of detection cycles: */
|
/* rate of detection cycles: */
|
||||||
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
|
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
|
||||||
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
|
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
|
||||||
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
|
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
|
||||||
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
|
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
|
||||||
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
|
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
|
||||||
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
|
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
|
||||||
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
|
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
|
||||||
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
|
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum aes2501_settling_delay {
|
enum aes2501_settling_delay {
|
||||||
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
|
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
|
||||||
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
|
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
|
||||||
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
|
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
|
||||||
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
|
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum aes2501_col_scan_rate {
|
enum aes2501_col_scan_rate {
|
||||||
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
|
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
|
||||||
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
|
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
|
||||||
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
|
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
|
||||||
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
|
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
|
||||||
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
|
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
|
||||||
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
|
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
|
||||||
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
|
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum aes2501_mesure_drive {
|
enum aes2501_mesure_drive {
|
||||||
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
|
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
|
||||||
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
|
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
|
||||||
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
|
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
|
||||||
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
|
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Select (1=square | 0=sine) wave drive during measure */
|
/* Select (1=square | 0=sine) wave drive during measure */
|
||||||
#define AES2501_MEASDRV_SQUARE 0x20
|
#define AES2501_MEASDRV_SQUARE 0x20
|
||||||
/* 0 = use mesure drive setting, 1 = when sine wave is selected */
|
/* 0 = use measure drive setting, 1 = when sine wave is selected */
|
||||||
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
|
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
|
||||||
|
|
||||||
enum aes2501_measure_freq {
|
enum aes2501_measure_freq {
|
||||||
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
|
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
|
||||||
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
|
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
|
||||||
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
|
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
|
||||||
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
|
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
|
||||||
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
|
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEMODPHASE_NONE 0x00
|
#define DEMODPHASE_NONE 0x00
|
||||||
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
|
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
|
||||||
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
|
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
|
||||||
|
|
||||||
#define AES2501_REG_DEMODPHASE1 0x8d
|
#define AES2501_REG_DEMODPHASE1 0x8d
|
||||||
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
|
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
|
||||||
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
|
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
|
||||||
|
|
||||||
enum aes2501_sensor_gain1 {
|
enum aes2501_sensor_gain1 {
|
||||||
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
|
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
|
||||||
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
|
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
|
||||||
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
|
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
|
||||||
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
|
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum aes2501_sensor_gain2 {
|
enum aes2501_sensor_gain2 {
|
||||||
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
|
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
|
||||||
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
|
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
|
||||||
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
|
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
|
||||||
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
|
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
|
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
|
||||||
#define AES2501_DATFMT_LOW_RES 0x20
|
#define AES2501_DATFMT_LOW_RES 0x20
|
||||||
#define AES2501_DATFMT_BIN_IMG 0x10
|
#define AES2501_DATFMT_BIN_IMG 0x10
|
||||||
|
|
||||||
/* don't send image or authentication messages when imaging */
|
/* don't send image or authentication messages when imaging */
|
||||||
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
|
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
|
||||||
/* send histogram when imaging */
|
/* send histogram when imaging */
|
||||||
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
|
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
|
||||||
/* send histogram at end of each row rather than each scan */
|
/* send histogram at end of each row rather than each scan */
|
||||||
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
|
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
|
||||||
/* send full image array rather than 64x64 center */
|
/* send full image array rather than 64x64 center */
|
||||||
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
|
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
|
||||||
/* return registers before data (rather than after) */
|
/* return registers before data (rather than after) */
|
||||||
#define AES2501_IMAGCTRL_REG_FIRST 0x10
|
#define AES2501_IMAGCTRL_REG_FIRST 0x10
|
||||||
/* return test registers with register dump */
|
/* return test registers with register dump */
|
||||||
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
|
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
|
||||||
|
|
||||||
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
|
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
|
||||||
|
|
||||||
/* Enable the reading of the register in TREGD */
|
/* Enable the reading of the register in TREGD */
|
||||||
#define AES2501_TREGC_ENABLE 0x01
|
#define AES2501_TREGC_ENABLE 0x01
|
||||||
|
|
||||||
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
|
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
|
||||||
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
|
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
|
||||||
|
|
||||||
#define AES2501_ADREFHI_MIN_VALUE 0x28
|
#define AES2501_ADREFHI_MIN_VALUE 0x28
|
||||||
#define AES2501_ADREFHI_MAX_VALUE 0x58
|
#define AES2501_ADREFHI_MAX_VALUE 0x58
|
||||||
|
|
||||||
#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 */
|
|
||||||
|
|||||||
@@ -17,98 +17,95 @@
|
|||||||
* 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 */
|
||||||
|
|
||||||
#define AES2550_REG80_MASTER_RESET (1 << 0)
|
#define AES2550_REG80_MASTER_RESET (1 << 0)
|
||||||
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
|
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
|
||||||
#define AES2550_REG80_LPO_START (1 << 2)
|
#define AES2550_REG80_LPO_START (1 << 2)
|
||||||
#define AES2550_REG80_HGC_ENABLE (1 << 3)
|
#define AES2550_REG80_HGC_ENABLE (1 << 3)
|
||||||
#define AES2550_REG80_SENSOR_MODE_OFS (4)
|
#define AES2550_REG80_SENSOR_MODE_OFS (4)
|
||||||
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
|
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
|
||||||
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
|
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
|
||||||
|
|
||||||
#define AES2550_REG81_CONT_SCAN (1 << 0)
|
#define AES2550_REG81_CONT_SCAN (1 << 0)
|
||||||
#define AES2550_REG81_READ_REG (1 << 1)
|
#define AES2550_REG81_READ_REG (1 << 1)
|
||||||
#define AES2550_REG81_NSHOT (1 << 2)
|
#define AES2550_REG81_NSHOT (1 << 2)
|
||||||
#define AES2550_REG81_RUN_FD (1 << 3)
|
#define AES2550_REG81_RUN_FD (1 << 3)
|
||||||
#define AES2550_REG81_READ_ID (1 << 4)
|
#define AES2550_REG81_READ_ID (1 << 4)
|
||||||
#define AES2550_REG81_RUN_CAL (1 << 5)
|
#define AES2550_REG81_RUN_CAL (1 << 5)
|
||||||
#define AES2550_REG81_RUN_TIMER (1 << 6)
|
#define AES2550_REG81_RUN_TIMER (1 << 6)
|
||||||
#define AES2550_REG81_RUN_BIST (1 << 7)
|
#define AES2550_REG81_RUN_BIST (1 << 7)
|
||||||
|
|
||||||
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
|
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
|
||||||
|
|
||||||
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
|
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
|
||||||
|
|
||||||
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
|
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
|
||||||
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
|
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
|
||||||
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
|
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
|
||||||
#define AES2550_REG8F_HISTO64 (1 << 4)
|
#define AES2550_REG8F_HISTO64 (1 << 4)
|
||||||
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
|
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
|
||||||
|
|
||||||
#define AES2550_REG95_COL_SCANNED_OFS (0)
|
#define AES2550_REG95_COL_SCANNED_OFS (0)
|
||||||
#define AES2550_REG95_EPIX_AVG_OFS (4)
|
#define AES2550_REG95_EPIX_AVG_OFS (4)
|
||||||
|
|
||||||
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
|
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
|
||||||
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
|
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
|
||||||
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
|
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
|
||||||
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
|
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
|
||||||
|
|
||||||
#define AES2550_REGAD_LPFD_AVG_OFS (0)
|
#define AES2550_REGAD_LPFD_AVG_OFS (0)
|
||||||
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
|
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
|
||||||
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
|
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
|
||||||
|
|
||||||
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
|
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
|
||||||
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
|
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
|
||||||
#define AES2550_REGB1_ANALOG_PD (1 << 3)
|
#define AES2550_REGB1_ANALOG_PD (1 << 3)
|
||||||
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
|
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
|
||||||
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
|
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
|
||||||
#define AES2550_REGB1_RESET_UHSM (1 << 6)
|
#define AES2550_REGB1_RESET_UHSM (1 << 6)
|
||||||
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
|
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
|
||||||
|
|
||||||
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
|
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
|
||||||
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
|
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
|
||||||
|
|
||||||
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
|
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
|
||||||
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
|
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
|
||||||
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
|
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
|
||||||
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
|
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
|
||||||
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
|
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
|
||||||
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
|
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
|
||||||
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
|
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
|
||||||
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
|
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
|
||||||
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
|
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
|
||||||
|
|
||||||
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
|
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
|
||||||
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
|
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
|
||||||
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
|
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
|
||||||
|
|
||||||
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
|
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
|
||||||
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
|
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
|
||||||
|
|
||||||
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
|
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
|
||||||
|
|
||||||
/* Commands */
|
/* Commands */
|
||||||
|
|
||||||
enum aes2550_cmds {
|
enum aes2550_cmds {
|
||||||
AES2550_CMD_SET_IDLE_MODE = 0x00,
|
AES2550_CMD_SET_IDLE_MODE = 0x00,
|
||||||
AES2550_CMD_RUN_FD = 0x01,
|
AES2550_CMD_RUN_FD = 0x01,
|
||||||
AES2550_CMD_GET_ENROLL_IMG = 0x02,
|
AES2550_CMD_GET_ENROLL_IMG = 0x02,
|
||||||
AES2550_CMD_CALIBRATE = 0x06,
|
AES2550_CMD_CALIBRATE = 0x06,
|
||||||
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
|
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
|
||||||
AES2550_CMD_HEARTBEAT = 0x70,
|
AES2550_CMD_HEARTBEAT = 0x70,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Messages */
|
/* Messages */
|
||||||
|
|
||||||
#define AES2550_STRIP_SIZE (0x31e + 3)
|
#define AES2550_STRIP_SIZE (0x31e + 3)
|
||||||
#define AES2550_HEARTBEAT_SIZE (4 + 3)
|
#define AES2550_HEARTBEAT_SIZE (4 + 3)
|
||||||
#define AES2550_EDATA_MAGIC 0xe0
|
#define AES2550_EDATA_MAGIC 0xe0
|
||||||
#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
|
|
||||||
|
|||||||
@@ -19,94 +19,79 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes2660"
|
#define FP_COMPONENT "aes2660"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aesx660.h"
|
#include "aesx660.h"
|
||||||
#include "aes2660.h"
|
#include "aes2660.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
struct _FpiDeviceAes2660
|
||||||
{
|
{
|
||||||
/* TODO check that device has endpoints we're using */
|
FpiDeviceAesX660 parent;
|
||||||
int r;
|
};
|
||||||
struct aesX660_dev *aesdev;
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI,
|
||||||
|
DEVICE_AES2660, FpiDeviceAesX660);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660);
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
if (r < 0) {
|
.frame_width = FRAME_WIDTH,
|
||||||
fp_err("could not claim interface 0");
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
return r;
|
.image_width = IMAGE_WIDTH,
|
||||||
}
|
.get_pixel = aes_get_pixel,
|
||||||
|
|
||||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
|
||||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
|
||||||
/* No scaling for AES2660 */
|
|
||||||
aesdev->h_scale_factor = 1;
|
|
||||||
aesdev->init_seqs[0] = aes2660_init_1;
|
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
|
||||||
aesdev->init_seqs[1] = aes2660_init_2;
|
|
||||||
aesdev->init_seqs_len[1] = array_n_elements(aes2660_init_2);
|
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
|
||||||
g_free(aesdev->buffer);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(dev->udev, 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2660 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2680 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2681 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2682 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2683 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2684 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2685 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2686 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2687 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2688 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2689 },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268a },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268b },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268c },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268d },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268e },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x268f },
|
|
||||||
{ .vendor = 0x08ff, .product = 0x2691 },
|
|
||||||
{ 0, 0, 0, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes2660_driver = {
|
static const FpIdEntry id_table[] = {
|
||||||
.driver = {
|
{ .vid = 0x08ff, .pid = 0x2660, },
|
||||||
.id = AES2660_ID,
|
{ .vid = 0x08ff, .pid = 0x2680, },
|
||||||
.name = FP_COMPONENT,
|
{ .vid = 0x08ff, .pid = 0x2681, },
|
||||||
.full_name = "AuthenTec AES2660",
|
{ .vid = 0x08ff, .pid = 0x2682, },
|
||||||
.id_table = id_table,
|
{ .vid = 0x08ff, .pid = 0x2683, },
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{ .vid = 0x08ff, .pid = 0x2684, },
|
||||||
},
|
{ .vid = 0x08ff, .pid = 0x2685, },
|
||||||
.flags = 0,
|
{ .vid = 0x08ff, .pid = 0x2686, },
|
||||||
.img_height = -1,
|
{ .vid = 0x08ff, .pid = 0x2687, },
|
||||||
.img_width = FRAME_WIDTH,
|
{ .vid = 0x08ff, .pid = 0x2688, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x2689, },
|
||||||
.open = dev_init,
|
{ .vid = 0x08ff, .pid = 0x268a, },
|
||||||
.close = dev_deinit,
|
{ .vid = 0x08ff, .pid = 0x268b, },
|
||||||
.activate = aesX660_dev_activate,
|
{ .vid = 0x08ff, .pid = 0x268c, },
|
||||||
.deactivate = aesX660_dev_deactivate,
|
{ .vid = 0x08ff, .pid = 0x268d, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x268e, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x268f, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x2691, },
|
||||||
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes2660_init (FpiDeviceAes2660 *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = "aes2660";
|
||||||
|
dev_class->full_name = "AuthenTec AES2660";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
|
img_class->bz3_threshold = 20;
|
||||||
|
|
||||||
|
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
|
||||||
|
aes_class->init_seqs[0] = aes2660_init_1;
|
||||||
|
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes2660_init_1);
|
||||||
|
aes_class->init_seqs[1] = aes2660_init_2;
|
||||||
|
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes2660_init_2);
|
||||||
|
aes_class->start_imaging_cmd = (unsigned char *) aes2660_start_imaging_cmd;
|
||||||
|
aes_class->start_imaging_cmd_len = sizeof (aes2660_start_imaging_cmd);
|
||||||
|
aes_class->assembling_ctx = &assembling_ctx;
|
||||||
|
}
|
||||||
|
|||||||
162
libfprint/drivers/aes3500.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* AuthenTec AES3500 driver for libfprint
|
||||||
|
*
|
||||||
|
* AES3500 is a press-typed sensor, which captures image in 128x128
|
||||||
|
* pixels.
|
||||||
|
*
|
||||||
|
* Thanks Rafael Toledo for the Windows driver and the help.
|
||||||
|
*
|
||||||
|
* This work is derived from Daniel Drake's AES4000 driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011-2013 Juvenn Woo <machese@gmail.com>
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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 "aes3500"
|
||||||
|
|
||||||
|
#include "aes3k.h"
|
||||||
|
|
||||||
|
#define DATA_BUFLEN 0x2089
|
||||||
|
|
||||||
|
/* image size = FRAME_WIDTH x FRAME_WIDTH */
|
||||||
|
#define FRAME_WIDTH 128
|
||||||
|
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||||
|
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||||
|
#define ENLARGE_FACTOR 2
|
||||||
|
|
||||||
|
|
||||||
|
static struct aes_regwrite init_reqs[] = {
|
||||||
|
/* master reset */
|
||||||
|
{ 0x80, 0x01 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
/* scan reset */
|
||||||
|
{ 0x80, 0x02 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
/* disable register buffering */
|
||||||
|
{ 0x80, 0x04 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
/* windows driver reads registers now (81 02) */
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
|
||||||
|
/* set excitation bias current: 2mhz drive ring frequency,
|
||||||
|
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||||
|
{ 0x82, 0x04 },
|
||||||
|
|
||||||
|
/* continuously sample drive ring for finger detection,
|
||||||
|
* 62.50ms debounce delay */
|
||||||
|
{ 0x83, 0x13 },
|
||||||
|
|
||||||
|
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||||
|
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||||
|
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||||
|
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||||
|
{ 0x88, 0x02 }, /* set column scan period */
|
||||||
|
{ 0x89, 0x02 }, /* set measure drive */
|
||||||
|
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||||
|
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||||
|
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||||
|
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||||
|
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||||
|
{ 0x8f, 0x07 }, /* set image parameters */
|
||||||
|
{ 0x90, 0x00 }, /* carrier offset null */
|
||||||
|
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||||
|
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||||
|
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||||
|
{ 0x94, 0x07 }, /* set end row */
|
||||||
|
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||||
|
{ 0x96, 0x1f }, /* set end column */
|
||||||
|
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||||
|
{ 0x98, 0x28 }, /* image data control */
|
||||||
|
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||||
|
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||||
|
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||||
|
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||||
|
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||||
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct aes_regwrite capture_reqs[] = {
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x81, 0x04 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _FpiDeviceAes3500
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k parent;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
|
||||||
|
DEVICE_AES3500, FpiDeviceAes3k);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
|
||||||
|
|
||||||
|
|
||||||
|
static const FpIdEntry id_table[] = {
|
||||||
|
{ .vid = 0x08ff, .pid = 0x5731 },
|
||||||
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = "aes3500";
|
||||||
|
dev_class->full_name = "AuthenTec AES3500";
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
|
||||||
|
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||||
|
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||||
|
|
||||||
|
aes_class->data_buflen = DATA_BUFLEN;
|
||||||
|
aes_class->frame_width = FRAME_WIDTH;
|
||||||
|
aes_class->frame_size = FRAME_SIZE;
|
||||||
|
aes_class->frame_number = FRAME_NUMBER;
|
||||||
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
|
aes_class->init_reqs = init_reqs;
|
||||||
|
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||||
|
aes_class->capture_reqs = capture_reqs;
|
||||||
|
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
||||||
|
}
|
||||||
272
libfprint/drivers/aes3k.c
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* AuthenTec AES3500/AES4000 common routines
|
||||||
|
*
|
||||||
|
* The AES3500 and AES4000 sensors are press-typed, and could capture
|
||||||
|
* fingerprint images in 128x128 and 96x96 pixels respectively. They
|
||||||
|
* share a same communication interface: a number of frames are
|
||||||
|
* transferred and captured, from which a final image could be
|
||||||
|
* assembled. Each frame has fixed height of 16 pixels.
|
||||||
|
*
|
||||||
|
* As the imaging area is a bit small, only a part of finger could be
|
||||||
|
* captured, the detected minutiae are not so many that the NBIS
|
||||||
|
* matching works not so good. The verification rate is very low at the
|
||||||
|
* moment.
|
||||||
|
*
|
||||||
|
* This work is derived from Daniel Drake's AES4000 driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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 "aes3k"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
|
#include "aes3k.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* This is used both as a flag that we are in a capture operation
|
||||||
|
* and for cancellation.
|
||||||
|
*/
|
||||||
|
GCancellable *img_capture_cancel;
|
||||||
|
} FpiDeviceAes3kPrivate;
|
||||||
|
|
||||||
|
#define CTRL_TIMEOUT 1000
|
||||||
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
|
||||||
|
static void do_capture (FpImageDevice *dev);
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_assemble_image (unsigned char *input, size_t width, size_t height,
|
||||||
|
unsigned char *output)
|
||||||
|
{
|
||||||
|
size_t row, column;
|
||||||
|
|
||||||
|
for (column = 0; column < width; column++)
|
||||||
|
{
|
||||||
|
for (row = 0; row < height; row += 2)
|
||||||
|
{
|
||||||
|
output[width * row + column] = (*input & 0x0f) * 17;
|
||||||
|
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||||
|
input++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
unsigned char *ptr = transfer->buffer;
|
||||||
|
FpImage *tmp;
|
||||||
|
FpImage *img;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Image capture operation is finished (error/completed) */
|
||||||
|
g_clear_object (&priv->img_capture_cancel);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (g_error_matches (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
/* Cancellation implies we are deactivating. */
|
||||||
|
g_error_free (error);
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
|
|
||||||
|
tmp = fp_image_new (cls->frame_width, cls->frame_width);
|
||||||
|
tmp->width = cls->frame_width;
|
||||||
|
tmp->height = cls->frame_width;
|
||||||
|
tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||||
|
for (i = 0; i < cls->frame_number; i++)
|
||||||
|
{
|
||||||
|
fp_dbg ("frame header byte %02x", *ptr);
|
||||||
|
ptr++;
|
||||||
|
aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT));
|
||||||
|
ptr += cls->frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||||
|
* to process reliably */
|
||||||
|
img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor);
|
||||||
|
g_object_unref (tmp);
|
||||||
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
|
||||||
|
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||||
|
* it really has. */
|
||||||
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
|
|
||||||
|
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_capture (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
g_autoptr(FpiUsbTransfer) img_trf = NULL;
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
|
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
|
||||||
|
img_trf->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
|
||||||
|
priv->img_capture_cancel,
|
||||||
|
img_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
g_clear_object (&priv->img_capture_cancel);
|
||||||
|
fpi_image_device_session_error (dev, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: we never cancel a pending capture. So we are likely leaving the
|
||||||
|
* hardware in a bad state should we abort the capture operation and the
|
||||||
|
* user does not touch the device.
|
||||||
|
* But, we don't know how we might cancel, so just leave it as is. */
|
||||||
|
do_capture (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_capture_start (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
|
aes_write_regv (dev, cls->capture_reqs, cls->capture_reqs_len, capture_reqs_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||||
|
{
|
||||||
|
fpi_image_device_activate_complete (dev, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_activate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
|
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_deactivate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
|
/* If a capture is running, then deactivation finishes from the cancellation handler */
|
||||||
|
if (priv->img_capture_cancel)
|
||||||
|
g_cancellable_cancel (priv->img_capture_cancel);
|
||||||
|
else
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
|
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
|
{
|
||||||
|
g_assert (!priv->img_capture_cancel);
|
||||||
|
priv->img_capture_cancel = g_cancellable_new ();
|
||||||
|
|
||||||
|
do_capture_start (dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_init (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
||||||
|
{
|
||||||
|
fpi_image_device_open_complete (dev, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_image_device_open_complete (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||||
|
|
||||||
|
img_class->img_open = aes3k_dev_init;
|
||||||
|
img_class->img_close = aes3k_dev_deinit;
|
||||||
|
img_class->activate = aes3k_dev_activate;
|
||||||
|
img_class->change_state = aes3k_dev_change_state;
|
||||||
|
img_class->deactivate = aes3k_dev_deactivate;
|
||||||
|
|
||||||
|
/* Extremely low due to low image quality. */
|
||||||
|
img_class->bz3_threshold = 9;
|
||||||
|
|
||||||
|
/* Everything else is set by the subclasses. */
|
||||||
|
}
|
||||||
62
libfprint/drivers/aes3k.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* AuthenTec AES3500/AES4000 common routines
|
||||||
|
*
|
||||||
|
* The AES3500 and AES4000 sensors are press-typed, and could capture
|
||||||
|
* fingerprint images in 128x128 and 96x96 pixels respectively. They
|
||||||
|
* share a same communication interface: a number of frames are
|
||||||
|
* transferred and captured, from which a final image could be
|
||||||
|
* assembled. Each frame has fixed height of 16 pixels.
|
||||||
|
*
|
||||||
|
* As the imaging area is a bit small, only a part of finger could be
|
||||||
|
* captured, the detected minutiae are not so many that the NBIS
|
||||||
|
* matching works not so good. The verification rate is very low at the
|
||||||
|
* moment.
|
||||||
|
*
|
||||||
|
* This work is derived from Daniel Drake's AES4000 driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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-image-device.h"
|
||||||
|
#include "aeslib.h"
|
||||||
|
|
||||||
|
#define AES3K_FRAME_HEIGHT 16
|
||||||
|
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI,
|
||||||
|
DEVICE_AES3K, FpImageDevice)
|
||||||
|
|
||||||
|
#define FPI_TYPE_DEVICE_AES3K (fpi_device_aes3k_get_type ())
|
||||||
|
|
||||||
|
struct _FpiDeviceAes3kClass
|
||||||
|
{
|
||||||
|
FpImageDeviceClass parent;
|
||||||
|
|
||||||
|
gsize frame_width; /* image size = frame_width x frame_width */
|
||||||
|
gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
|
||||||
|
gsize frame_number; /* number of frames */
|
||||||
|
gsize enlarge_factor;
|
||||||
|
|
||||||
|
gsize data_buflen; /* buffer length of usb bulk transfer */
|
||||||
|
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||||
|
gsize init_reqs_len;
|
||||||
|
struct aes_regwrite *capture_reqs; /* capture values sent to device */
|
||||||
|
gsize capture_reqs_len;
|
||||||
|
};
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* AuthenTec AES4000 driver for libfprint
|
* AuthenTec AES4000 driver for libfprint
|
||||||
|
*
|
||||||
|
* AES4000 is a press-typed sensor, which captures image in 96x96
|
||||||
|
* pixels.
|
||||||
|
*
|
||||||
|
* This work is derived from Daniel Drake's AES4000 driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@@ -19,254 +26,134 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes4000"
|
#define FP_COMPONENT "aes4000"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "aes3k.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#define DATA_BUFLEN 0x1259
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
/* image size = FRAME_WIDTH x FRAME_WIDTH */
|
||||||
#include <fp_internal.h>
|
#define FRAME_WIDTH 96
|
||||||
|
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
|
||||||
#include "driver_ids.h"
|
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
|
||||||
|
|
||||||
#define CTRL_TIMEOUT 1000
|
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
|
||||||
#define DATA_BUFLEN 0x1259
|
|
||||||
#define NR_SUBARRAYS 6
|
|
||||||
#define SUBARRAY_LEN 768
|
|
||||||
|
|
||||||
#define IMG_HEIGHT 96
|
|
||||||
#define IMG_WIDTH 96
|
|
||||||
#define ENLARGE_FACTOR 3
|
#define ENLARGE_FACTOR 3
|
||||||
|
|
||||||
struct aes4k_dev {
|
|
||||||
struct libusb_transfer *img_trf;
|
static struct aes_regwrite init_reqs[] = {
|
||||||
|
/* master reset */
|
||||||
|
{ 0x80, 0x01 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
/* scan reset */
|
||||||
|
{ 0x80, 0x02 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
/* disable register buffering */
|
||||||
|
{ 0x80, 0x04 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
{ 0, 0 },
|
||||||
|
/* windows driver reads registers now (81 02) */
|
||||||
|
{ 0x80, 0x00 },
|
||||||
|
{ 0x81, 0x00 },
|
||||||
|
|
||||||
|
/* set excitation bias current: 2mhz drive ring frequency,
|
||||||
|
* 4V drive ring voltage, 16.5mA excitation bias */
|
||||||
|
{ 0x82, 0x04 },
|
||||||
|
|
||||||
|
/* continuously sample drive ring for finger detection,
|
||||||
|
* 62.50ms debounce delay */
|
||||||
|
{ 0x83, 0x13 },
|
||||||
|
|
||||||
|
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
||||||
|
{ 0x85, 0x3d }, /* set calibration capacitance */
|
||||||
|
{ 0x86, 0x03 }, /* detect drive voltage */
|
||||||
|
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
||||||
|
{ 0x88, 0x02 }, /* set column scan period */
|
||||||
|
{ 0x89, 0x02 }, /* set measure drive */
|
||||||
|
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
||||||
|
{ 0x8b, 0x33 }, /* set matrix pattern */
|
||||||
|
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
||||||
|
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
||||||
|
{ 0x8e, 0x23 }, /* set sensor gain */
|
||||||
|
{ 0x8f, 0x07 }, /* set image parameters */
|
||||||
|
{ 0x90, 0x00 }, /* carrier offset null */
|
||||||
|
{ 0x91, 0x1c }, /* set A/D reference high */
|
||||||
|
{ 0x92, 0x08 }, /* set A/D reference low */
|
||||||
|
{ 0x93, 0x00 }, /* set start row to 0 */
|
||||||
|
{ 0x94, 0x05 }, /* set end row to 5 */
|
||||||
|
{ 0x95, 0x00 }, /* set start column to 0 */
|
||||||
|
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
|
||||||
|
{ 0x97, 0x04 }, /* data format and thresholds */
|
||||||
|
{ 0x98, 0x28 }, /* image data control */
|
||||||
|
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
||||||
|
{ 0x9a, 0x0b }, /* set initial scan state */
|
||||||
|
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
||||||
|
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
||||||
|
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
||||||
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
|
{ 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct aes_regwrite init_reqs[] = {
|
static struct aes_regwrite capture_reqs[] = {
|
||||||
/* master reset */
|
{ 0x80, 0x00 },
|
||||||
{ 0x80, 0x01 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
{ 0x80, 0x00 },
|
{ 0x81, 0x04 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
{ 0x81, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
|
||||||
{ 0x80, 0x00 },
|
|
||||||
{ 0, 0 },
|
|
||||||
|
|
||||||
/* scan reset */
|
|
||||||
{ 0x80, 0x02 },
|
|
||||||
{ 0, 0 },
|
|
||||||
{ 0x80, 0x00 },
|
|
||||||
{ 0, 0 },
|
|
||||||
|
|
||||||
/* disable register buffering */
|
|
||||||
{ 0x80, 0x04 },
|
|
||||||
{ 0, 0 },
|
|
||||||
{ 0x80, 0x00 },
|
|
||||||
{ 0, 0 },
|
|
||||||
|
|
||||||
{ 0x81, 0x00 },
|
|
||||||
{ 0, 0 },
|
|
||||||
/* windows driver reads registers now (81 02) */
|
|
||||||
{ 0x80, 0x00 },
|
|
||||||
{ 0x81, 0x00 },
|
|
||||||
|
|
||||||
/* set excitation bias current: 2mhz drive ring frequency,
|
|
||||||
* 4V drive ring voltage, 16.5mA excitation bias */
|
|
||||||
{ 0x82, 0x04 },
|
|
||||||
|
|
||||||
/* continuously sample drive ring for finger detection,
|
|
||||||
* 62.50ms debounce delay */
|
|
||||||
{ 0x83, 0x13 },
|
|
||||||
|
|
||||||
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
|
|
||||||
{ 0x85, 0x3d }, /* set calibration capacitance */
|
|
||||||
{ 0x86, 0x03 }, /* detect drive voltage */
|
|
||||||
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
|
|
||||||
{ 0x88, 0x02 }, /* set column scan period */
|
|
||||||
{ 0x89, 0x02 }, /* set measure drive */
|
|
||||||
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
|
|
||||||
{ 0x8b, 0x33 }, /* set matrix pattern */
|
|
||||||
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
|
|
||||||
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
|
|
||||||
{ 0x8e, 0x23 }, /* set sensor gain */
|
|
||||||
{ 0x8f, 0x07 }, /* set image parameters */
|
|
||||||
{ 0x90, 0x00 }, /* carrier offset null */
|
|
||||||
{ 0x91, 0x1c }, /* set A/D reference high */
|
|
||||||
{ 0x92, 0x08 }, /* set A/D reference low */
|
|
||||||
{ 0x93, 0x00 }, /* set start row to 0 */
|
|
||||||
{ 0x94, 0x05 }, /* set end row to 5 */
|
|
||||||
{ 0x95, 0x00 }, /* set start column to 0 */
|
|
||||||
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
|
|
||||||
{ 0x97, 0x04 }, /* data format and thresholds */
|
|
||||||
{ 0x98, 0x28 }, /* image data control */
|
|
||||||
{ 0x99, 0x00 }, /* disable general purpose outputs */
|
|
||||||
{ 0x9a, 0x0b }, /* set initial scan state */
|
|
||||||
{ 0x9b, 0x00 }, /* clear challenge word bits */
|
|
||||||
{ 0x9c, 0x00 }, /* clear challenge word bits */
|
|
||||||
{ 0x9d, 0x09 }, /* set some challenge word bits */
|
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
|
||||||
{ 0, 0 },
|
|
||||||
|
|
||||||
{ 0x80, 0x00 },
|
|
||||||
{ 0x81, 0x00 },
|
|
||||||
{ 0, 0 },
|
|
||||||
{ 0x81, 0x04 },
|
|
||||||
{ 0, 0 },
|
|
||||||
{ 0x81, 0x00 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void do_capture(struct fp_img_dev *dev);
|
struct _FpiDeviceAes4000
|
||||||
|
|
||||||
static void img_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpiDeviceAes3k parent;
|
||||||
struct aes4k_dev *aesdev = dev->priv;
|
};
|
||||||
unsigned char *ptr = transfer->buffer;
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
|
||||||
struct fp_img *tmp;
|
DEVICE_AES4000, FpiDeviceAes3k);
|
||||||
struct fp_img *img;
|
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
|
||||||
int i;
|
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
|
||||||
goto err;
|
|
||||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
|
||||||
goto err;
|
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
static const FpIdEntry id_table[] = {
|
||||||
|
{ .vid = 0x08ff, .pid = 0x5501 },
|
||||||
tmp = fpi_img_new(IMG_WIDTH * IMG_HEIGHT);
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
tmp->width = IMG_WIDTH;
|
|
||||||
tmp->height = IMG_HEIGHT;
|
|
||||||
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
|
||||||
for (i = 0; i < NR_SUBARRAYS; i++) {
|
|
||||||
fp_dbg("subarray header byte %02x", *ptr);
|
|
||||||
ptr++;
|
|
||||||
aes_assemble_image(ptr, 96, 16, tmp->data + (i * 96 * 16));
|
|
||||||
ptr += SUBARRAY_LEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
|
||||||
* to process reliably */
|
|
||||||
img = fpi_im_resize(tmp, ENLARGE_FACTOR, ENLARGE_FACTOR);
|
|
||||||
fp_img_free(tmp);
|
|
||||||
fpi_imgdev_image_captured(dev, img);
|
|
||||||
|
|
||||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
|
||||||
* it really has, then restart the capture */
|
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
|
||||||
|
|
||||||
do_capture(dev);
|
|
||||||
|
|
||||||
err:
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
aesdev->img_trf = NULL;
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_capture(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aes4k_dev *aesdev = dev->priv;
|
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
aesdev->img_trf = libusb_alloc_transfer(0);
|
|
||||||
if (!aesdev->img_trf) {
|
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(DATA_BUFLEN);
|
|
||||||
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
|
|
||||||
DATA_BUFLEN, img_cb, dev, 0);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(aesdev->img_trf);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(aesdev->img_trf);
|
|
||||||
aesdev->img_trf = NULL;
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
|
||||||
{
|
|
||||||
fpi_imgdev_activate_complete(dev, result);
|
|
||||||
if (result == 0)
|
|
||||||
do_capture(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|
||||||
{
|
|
||||||
aes_write_regv(dev, init_reqs, G_N_ELEMENTS(init_reqs), init_reqs_cb, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aes4k_dev *aesdev = dev->priv;
|
|
||||||
|
|
||||||
/* FIXME: should wait for cancellation to complete before returning
|
|
||||||
* from deactivation, otherwise app may legally exit before we've
|
|
||||||
* cleaned up */
|
|
||||||
if (aesdev->img_trf)
|
|
||||||
libusb_cancel_transfer(aesdev->img_trf);
|
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
|
||||||
if (r < 0)
|
|
||||||
fp_err("could not claim interface 0");
|
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct aes4k_dev));
|
|
||||||
|
|
||||||
if (r == 0)
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
g_free(dev->priv);
|
|
||||||
libusb_release_interface(dev->udev, 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
|
||||||
{ .vendor = 0x08ff, .product = 0x5501 },
|
|
||||||
{ 0, 0, 0, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes4000_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_aes4000_init (FpiDeviceAes4000 *self)
|
||||||
.id = AES4000_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES4000",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
|
||||||
},
|
|
||||||
.flags = 0,
|
|
||||||
.img_height = IMG_HEIGHT * ENLARGE_FACTOR,
|
|
||||||
.img_width = IMG_WIDTH * ENLARGE_FACTOR,
|
|
||||||
|
|
||||||
/* temporarily lowered until image quality improves */
|
static void
|
||||||
.bz3_threshold = 9,
|
fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
||||||
|
{
|
||||||
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
|
||||||
|
|
||||||
.open = dev_init,
|
dev_class->id = "aes4000";
|
||||||
.close = dev_deinit,
|
dev_class->full_name = "AuthenTec AES4000";
|
||||||
.activate = dev_activate,
|
dev_class->id_table = id_table;
|
||||||
.deactivate = dev_deactivate,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||||
|
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
||||||
|
|
||||||
|
aes_class->data_buflen = DATA_BUFLEN;
|
||||||
|
aes_class->frame_width = FRAME_WIDTH;
|
||||||
|
aes_class->frame_size = FRAME_SIZE;
|
||||||
|
aes_class->frame_number = FRAME_NUMBER;
|
||||||
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
|
aes_class->init_reqs = init_reqs;
|
||||||
|
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
||||||
|
aes_class->capture_reqs = capture_reqs;
|
||||||
|
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
||||||
|
}
|
||||||
|
|||||||
169
libfprint/drivers/aeslib.c
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Shared functions between libfprint Authentec drivers
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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 "aeslib"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "aeslib.h"
|
||||||
|
|
||||||
|
#define MAX_REGWRITES_PER_REQUEST 16
|
||||||
|
|
||||||
|
#define BULK_TIMEOUT 4000
|
||||||
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
|
||||||
|
struct write_regv_data
|
||||||
|
{
|
||||||
|
unsigned int num_regs;
|
||||||
|
const struct aes_regwrite *regs;
|
||||||
|
unsigned int offset;
|
||||||
|
aes_write_regv_cb callback;
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void continue_write_regv (FpImageDevice *dev,
|
||||||
|
struct write_regv_data *wdata);
|
||||||
|
|
||||||
|
/* libusb bulk callback for regv write completion transfer. continues the
|
||||||
|
* transaction */
|
||||||
|
static void
|
||||||
|
write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
struct write_regv_data *wdata = user_data;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data);
|
||||||
|
g_free (wdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue_write_regv (FP_IMAGE_DEVICE (device), wdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
||||||
|
static void
|
||||||
|
do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound)
|
||||||
|
{
|
||||||
|
unsigned int offset = wdata->offset;
|
||||||
|
unsigned int num = upper_bound - offset + 1;
|
||||||
|
size_t alloc_size = num * 2;
|
||||||
|
unsigned int i;
|
||||||
|
size_t data_offset = 0;
|
||||||
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size);
|
||||||
|
|
||||||
|
for (i = offset; i < offset + num; i++)
|
||||||
|
{
|
||||||
|
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
||||||
|
transfer->buffer[data_offset++] = regwrite->reg;
|
||||||
|
transfer->buffer[data_offset++] = regwrite->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
write_regv_trf_complete, wdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write the next batch of registers to be written, or if there are no more,
|
||||||
|
* indicate completion to the caller */
|
||||||
|
static void
|
||||||
|
continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
|
||||||
|
{
|
||||||
|
unsigned int offset = wdata->offset;
|
||||||
|
unsigned int regs_remaining;
|
||||||
|
unsigned int limit;
|
||||||
|
unsigned int upper_bound;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* skip all zeros and ensure there is still work to do */
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (offset >= wdata->num_regs)
|
||||||
|
{
|
||||||
|
fp_dbg ("all registers written");
|
||||||
|
wdata->callback (dev, 0, wdata->user_data);
|
||||||
|
g_free (wdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (wdata->regs[offset].reg)
|
||||||
|
break;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdata->offset = offset;
|
||||||
|
regs_remaining = wdata->num_regs - offset;
|
||||||
|
limit = MIN (regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
||||||
|
upper_bound = offset + limit - 1;
|
||||||
|
|
||||||
|
/* determine if we can write the entire of the regs at once, or if there
|
||||||
|
* is a zero dividing things up */
|
||||||
|
for (i = offset; i <= upper_bound; i++)
|
||||||
|
if (!wdata->regs[i].reg)
|
||||||
|
{
|
||||||
|
upper_bound = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_write_regv (dev, wdata, upper_bound);
|
||||||
|
|
||||||
|
wdata->offset = upper_bound + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write a load of registers to the device, combining multiple writes in a
|
||||||
|
* single URB up to a limit. insert writes to non-existent register 0 to force
|
||||||
|
* specific groups of writes to be separated by different URBs. */
|
||||||
|
void
|
||||||
|
aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs,
|
||||||
|
unsigned int num_regs, aes_write_regv_cb callback,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct write_regv_data *wdata;
|
||||||
|
|
||||||
|
fp_dbg ("write %d regs", num_regs);
|
||||||
|
wdata = g_malloc (sizeof (*wdata));
|
||||||
|
wdata->num_regs = num_regs;
|
||||||
|
wdata->regs = regs;
|
||||||
|
wdata->offset = 0;
|
||||||
|
wdata->callback = callback;
|
||||||
|
wdata->user_data = user_data;
|
||||||
|
continue_write_regv (dev, wdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
struct fpi_frame *frame,
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y)
|
||||||
|
{
|
||||||
|
unsigned char ret;
|
||||||
|
|
||||||
|
ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)];
|
||||||
|
ret = y % 2 ? ret >> 4 : ret & 0xf;
|
||||||
|
ret *= 17;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
46
libfprint/drivers/aeslib.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Shared functions between libfprint Authentec drivers
|
||||||
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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 <fprint.h>
|
||||||
|
|
||||||
|
struct aes_regwrite
|
||||||
|
{
|
||||||
|
unsigned char reg;
|
||||||
|
unsigned char value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fpi_frame;
|
||||||
|
struct fpi_frame_asmbl_ctx;
|
||||||
|
|
||||||
|
typedef void (*aes_write_regv_cb)(FpImageDevice *dev,
|
||||||
|
GError *error,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
void aes_write_regv (FpImageDevice *dev,
|
||||||
|
const struct aes_regwrite *regs,
|
||||||
|
unsigned int num_regs,
|
||||||
|
aes_write_regv_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
struct fpi_frame *frame,
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y);
|
||||||
@@ -17,13 +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 __AESX660_H
|
#pragma once
|
||||||
#define __AESX660_H
|
|
||||||
|
|
||||||
#define AESX660_HEADER_SIZE 3
|
#define AESX660_HEADER_SIZE 3
|
||||||
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
|
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
|
||||||
#define AESX660_RESPONSE_SIZE_LSB_OFFSET 0x01
|
#define AESX660_RESPONSE_SIZE_LSB_OFFSET 0x01
|
||||||
#define AESX660_RESPONSE_SIZE_MSB_OFFSEt 0x02
|
#define AESX660_RESPONSE_SIZE_MSB_OFFSET 0x02
|
||||||
|
|
||||||
#define AESX660_CALIBRATE_RESPONSE 0x06
|
#define AESX660_CALIBRATE_RESPONSE 0x06
|
||||||
#define AESX660_FINGER_DET_RESPONSE 0x40
|
#define AESX660_FINGER_DET_RESPONSE 0x40
|
||||||
@@ -35,83 +34,78 @@
|
|||||||
#define AESX660_LAST_FRAME_OFFSET 0x04
|
#define AESX660_LAST_FRAME_OFFSET 0x04
|
||||||
#define AESX660_LAST_FRAME_BIT 0x01
|
#define AESX660_LAST_FRAME_BIT 0x01
|
||||||
|
|
||||||
|
#define AESX660_FRAME_DELTA_X_OFFSET 16
|
||||||
|
#define AESX660_FRAME_DELTA_Y_OFFSET 17
|
||||||
|
|
||||||
#define AESX660_IMAGE_OFFSET 43
|
#define AESX660_IMAGE_OFFSET 43
|
||||||
#define AESX660_BULK_TRANSFER_SIZE 4096
|
#define AESX660_BULK_TRANSFER_SIZE 4096
|
||||||
|
|
||||||
struct aesX660_dev {
|
#define AESX660_FRAME_HEIGHT 8
|
||||||
GSList *strips;
|
|
||||||
size_t strips_len;
|
|
||||||
gboolean deactivating;
|
|
||||||
struct aesX660_cmd *init_seq;
|
|
||||||
size_t init_seq_len;
|
|
||||||
unsigned int init_cmd_idx;
|
|
||||||
unsigned int init_seq_idx;
|
|
||||||
struct libusb_transfer *fd_data_transfer;
|
|
||||||
unsigned char *buffer;
|
|
||||||
size_t buffer_size;
|
|
||||||
size_t buffer_max;
|
|
||||||
|
|
||||||
/* Device-specific stuff */
|
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI,
|
||||||
int h_scale_factor;
|
DEVICE_AES_X660, FpImageDevice)
|
||||||
struct aesX660_cmd *init_seqs[2];
|
|
||||||
size_t init_seqs_len[2];
|
#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ())
|
||||||
unsigned char *start_imaging_cmd;
|
|
||||||
size_t start_imaging_cmd_len;
|
struct _FpiDeviceAesX660Class
|
||||||
unsigned int frame_width;
|
{
|
||||||
|
FpImageDeviceClass parent;
|
||||||
|
|
||||||
|
struct aesX660_cmd *init_seqs[2];
|
||||||
|
gsize init_seqs_len[2];
|
||||||
|
guint8 *start_imaging_cmd;
|
||||||
|
gsize start_imaging_cmd_len;
|
||||||
|
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aesX660_cmd {
|
struct aesX660_cmd
|
||||||
const unsigned char *cmd;
|
{
|
||||||
size_t len;
|
const guint8 *cmd;
|
||||||
|
gsize len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 0x77 cmd seems to control LED, this sequence
|
/* 0x77 cmd seems to control LED, this sequence
|
||||||
* makes LED blink
|
* makes LED blink
|
||||||
*/
|
*/
|
||||||
static const unsigned char led_blink_cmd[] = {
|
static const guint8 led_blink_cmd[] = {
|
||||||
0x77, 0x18, 0x00,
|
0x77, 0x18, 0x00,
|
||||||
0x00, 0x3f, 0x00, 0xff, 0x00,
|
0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
||||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
|
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
|
||||||
0x01, 0x00, 0x7f
|
0x01, 0x00, 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This sequence makes LED light solid
|
/* This sequence makes LED light solid
|
||||||
*/
|
*/
|
||||||
static const unsigned char led_solid_cmd[] = {
|
static const guint8 led_solid_cmd[] = {
|
||||||
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
||||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x7f
|
0x00, 0x00, 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char wait_for_finger_cmd[] = {
|
static const guint8 wait_for_finger_cmd[] = {
|
||||||
0x20,
|
0x20,
|
||||||
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 0x40 cmd response
|
/* 0x40 cmd response
|
||||||
*
|
*
|
||||||
static const unsigned char pkt1371[] = {
|
static const guint8 pkt1371[] = {
|
||||||
0x40, 0x01, 0x00, 0x01
|
0x40, 0x01, 0x00, 0x01
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const unsigned char set_idle_cmd[] = {
|
static const guint8 set_idle_cmd[] = {
|
||||||
0x0d, /* Reset or "set idle"? */
|
0x0d, /* Reset or "set idle"? */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char read_id_cmd[] = {
|
static const guint8 read_id_cmd[] = {
|
||||||
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
|
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
|
||||||
0x07, /* Read ID? */
|
0x07, /* Read ID? */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char calibrate_cmd[] = {
|
static const guint8 calibrate_cmd[] = {
|
||||||
0x44, 0x02, 0x00, 0x04, 0x00,
|
0x44, 0x02, 0x00, 0x04, 0x00,
|
||||||
0x06,
|
0x06,
|
||||||
};
|
};
|
||||||
|
|
||||||
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
|
||||||
void aesX660_dev_deactivate(struct fp_img_dev *dev);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
1415
libfprint/drivers/egis0570.c
Normal file
592
libfprint/drivers/egis0570.h
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
// };
|
||||||
|
|
||||||
|
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, 0x25, 0x00 },
|
||||||
|
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00 },
|
||||||
|
{ 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
|
||||||
|
|
||||||
|
|
||||||
|
// Calibration
|
||||||
|
|
||||||
|
enum driver_version {
|
||||||
|
PACKET_CALIBRATION,
|
||||||
|
PACKET_VERSION_1,
|
||||||
|
NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PRESISTENT_DATA_LENGTH 9
|
||||||
|
#define EGIS0570_CAL_IMG_TOT 22 //124
|
||||||
|
#define EGIS0570_CAL_INPSIZE 6528
|
||||||
|
#define EGIS0570_CAL_BS_ELM 7
|
||||||
|
|
||||||
|
|
||||||
|
#define IMG_COL_IGNORE 23
|
||||||
|
#define TARGET_UPPER 80
|
||||||
|
#define TARGET_LOWER 70
|
||||||
|
// #define SIDE_DIFF (-10)
|
||||||
|
#define SIDE_DIFF (+5)
|
||||||
|
|
||||||
|
/* static pkts */
|
||||||
|
static guint8 EGIS0570_CAL_CONFIGURATION_MODE_PKT[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x1f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x05, 0x08},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_PKT_ZERO_RANGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x10},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x04, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x05, 0x08},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x06, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x07, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x08, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0a, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0b, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0c, 0xff},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_CAPTURING_AREA[][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}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_SENSOR_AND_EMITTER[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x15},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x08}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_WHITE_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x3f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BLACK_WHITE_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x20},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0x33}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BLACK_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x03},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0xff},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0xff}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BLACK_WHITE_CLEAR[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x00},
|
||||||
|
{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, 0x01, 0x09, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_MIDDLE_BLACK_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x7f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x7f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0x33}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_AFTER_IMAGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_REPEAT[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BORDER_WHITE_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x3f},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_FIRST_BS_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_BEFORE_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x1c},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x1c},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x31},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x40}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_NO_IMAGE_SETTING_0[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x05},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x08, 0x1c}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0b, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0c, 0xff},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0xff},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x1d},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x04, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_NO_IMAGE_PRE_FIRST[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_NO_IMAGE_REQUEST[][EGIS0570_PKTSIZE] =
|
||||||
|
{
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00},
|
||||||
|
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define EGIS0570_CAL_STATIC_LIST_SIZEOF (sizeof ((EGIS0570_CAL_STATIC_LIST)) / sizeof ((EGIS0570_CAL_STATIC_LIST[0])))
|
||||||
|
|
||||||
|
static guint8 * EGIS0570_CAL_STATIC_LIST[] = {
|
||||||
|
*EGIS0570_CAL_CONFIGURATION_MODE_PKT,
|
||||||
|
*EGIS0570_CAL_PKT_ZERO_RANGE,
|
||||||
|
*EGIS0570_CAL_CAPTURING_AREA,
|
||||||
|
*EGIS0570_CAL_SENSOR_AND_EMITTER,
|
||||||
|
*EGIS0570_CAL_WHITE_SETTING,
|
||||||
|
*EGIS0570_CAL_BLACK_WHITE_GET_IMAGE,
|
||||||
|
*EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||||
|
*EGIS0570_CAL_BLACK_SETTING,
|
||||||
|
*EGIS0570_CAL_BLACK_WHITE_CLEAR,
|
||||||
|
*EGIS0570_CAL_MIDDLE_BLACK_SETTING,
|
||||||
|
*EGIS0570_CAL_GET_IMAGE,
|
||||||
|
*EGIS0570_CAL_AFTER_IMAGE,
|
||||||
|
*EGIS0570_CAL_REPEAT,
|
||||||
|
*EGIS0570_CAL_BORDER_WHITE_SETTING,
|
||||||
|
*EGIS0570_CAL_FIRST_BS_SETTING,
|
||||||
|
*EGIS0570_CAL_BEFORE_GET_IMAGE,
|
||||||
|
*EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA,
|
||||||
|
*EGIS0570_CAL_NO_IMAGE_SETTING_0,
|
||||||
|
*EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING,
|
||||||
|
*EGIS0570_CAL_NO_IMAGE_PRE_FIRST,
|
||||||
|
*EGIS0570_CAL_NO_IMAGE_REQUEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define EGIS0570_HELPER_PKT_SIZEOF(x) (sizeof (x) / sizeof (x[0]))
|
||||||
|
|
||||||
|
static guint8 EGIS0570_CAL_STATIC_LIST_SIZE[] = {
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_CONFIGURATION_MODE_PKT),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_PKT_ZERO_RANGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_CAPTURING_AREA),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_SENSOR_AND_EMITTER),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_WHITE_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_GET_IMAGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_CLEAR),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_MIDDLE_BLACK_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_GET_IMAGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_AFTER_IMAGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_REPEAT),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BORDER_WHITE_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_FIRST_BS_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BEFORE_GET_IMAGE),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_SETTING_0),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_PRE_FIRST),
|
||||||
|
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_REQUEST),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Calibration logic */
|
||||||
|
enum cal_proc_en {
|
||||||
|
CAL_CONF_PKT,
|
||||||
|
CAL_PKT_ZERO_RNG,
|
||||||
|
CAL_CAPT_AREA,
|
||||||
|
CAL_SENS_AND_EMIT,
|
||||||
|
CAL_RNG_20_58,
|
||||||
|
CAL_RNG_60_D0,
|
||||||
|
CAL_WHITE_SET,
|
||||||
|
CAL_BLACK_WHITE_GET_IMG,
|
||||||
|
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||||
|
CAL_BLACK_SET,
|
||||||
|
CAL_CHECK_BLACK_WHITE,
|
||||||
|
CAL_5_ROWS_ZEROS,
|
||||||
|
CAL_BLACK_WHITE_CLEAR,
|
||||||
|
CAL_RNG_60_D1,
|
||||||
|
CAL_MID_BLACK_SET,
|
||||||
|
CAL_GET_IMG,
|
||||||
|
CAL_AFTER_IMG,
|
||||||
|
CAL_GET_9,
|
||||||
|
CAL_BORDER_WHITE_SET,
|
||||||
|
CAL_FIRST_BS_SET,
|
||||||
|
CAL_BS_CHK_SET,
|
||||||
|
CAL_PKT_02,
|
||||||
|
CAL_BEFORE_IMG,
|
||||||
|
CAL_BS_JUMP,
|
||||||
|
CAL_BS_END,
|
||||||
|
CAL_PKT_15_0,
|
||||||
|
CAL_PKT_16_3C,
|
||||||
|
CAL_CHK_NEW_CONF,
|
||||||
|
CAL_GET_21,
|
||||||
|
CAL_NO_IMG_CAP_AREA,
|
||||||
|
CAL_NO_IMG_SET_0,
|
||||||
|
CAL_NO_IMG_03_1C,
|
||||||
|
CAL_NO_CHK_03_80,
|
||||||
|
CAL_NO_SET_03_80,
|
||||||
|
CAL_NO_IMG_14_BS_SET,
|
||||||
|
CAL_NO_IMG_14_BS_CHK_SET,
|
||||||
|
CAL_NO_IMG_PRE_FIRST,
|
||||||
|
CAL_NO_IMG_GET_8,
|
||||||
|
CAL_NO_IMG_14_BS_JUMP,
|
||||||
|
CAL_NO_IMG_14_BS_END,
|
||||||
|
CAL_NO_IMG_16_BS_SET,
|
||||||
|
CAL_NO_IMG_16_BS_CHK_SET_15,
|
||||||
|
CAL_NO_IMG_16_BS_SET_16,
|
||||||
|
CAL_NO_IMG_16_BS_JUMP,
|
||||||
|
CAL_NO_IMG_16_BS_END,
|
||||||
|
|
||||||
|
|
||||||
|
CAL_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define EGIS0570_CAL_PROC_SIZEOF (sizeof ((calibration_procedure)) / sizeof ((calibration_procedure[0])))
|
||||||
|
|
||||||
|
static guint8 calibration_procedure[] = {
|
||||||
|
// conf
|
||||||
|
CAL_CONF_PKT,
|
||||||
|
// sensor check
|
||||||
|
CAL_PKT_ZERO_RNG,
|
||||||
|
CAL_CAPT_AREA,
|
||||||
|
CAL_SENS_AND_EMIT,
|
||||||
|
CAL_RNG_20_58,
|
||||||
|
CAL_RNG_60_D0,
|
||||||
|
CAL_WHITE_SET,
|
||||||
|
CAL_BLACK_WHITE_GET_IMG,
|
||||||
|
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||||
|
CAL_BLACK_SET,
|
||||||
|
CAL_BLACK_WHITE_GET_IMG,
|
||||||
|
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||||
|
CAL_CHECK_BLACK_WHITE,
|
||||||
|
// not binary 16
|
||||||
|
CAL_CAPT_AREA,
|
||||||
|
CAL_5_ROWS_ZEROS,
|
||||||
|
CAL_BLACK_WHITE_CLEAR,
|
||||||
|
CAL_RNG_20_58,
|
||||||
|
CAL_RNG_60_D1,
|
||||||
|
CAL_MID_BLACK_SET,
|
||||||
|
CAL_GET_IMG,
|
||||||
|
CAL_AFTER_IMG,
|
||||||
|
CAL_GET_9,
|
||||||
|
CAL_BORDER_WHITE_SET,
|
||||||
|
CAL_GET_IMG,
|
||||||
|
CAL_AFTER_IMG,
|
||||||
|
CAL_GET_9,
|
||||||
|
// binary
|
||||||
|
CAL_FIRST_BS_SET,
|
||||||
|
CAL_BS_CHK_SET, // 0
|
||||||
|
CAL_PKT_02, // 1
|
||||||
|
CAL_BEFORE_IMG, // 2
|
||||||
|
CAL_GET_IMG, // 3
|
||||||
|
CAL_AFTER_IMG, // 4
|
||||||
|
CAL_GET_9, // 5
|
||||||
|
CAL_BS_JUMP, // 6
|
||||||
|
CAL_BS_END, // 7
|
||||||
|
// check pictures.
|
||||||
|
CAL_PKT_15_0,
|
||||||
|
CAL_PKT_16_3C,
|
||||||
|
CAL_CHK_NEW_CONF,
|
||||||
|
CAL_PKT_02,
|
||||||
|
CAL_BEFORE_IMG,
|
||||||
|
CAL_GET_IMG,
|
||||||
|
CAL_AFTER_IMG,
|
||||||
|
CAL_GET_21,
|
||||||
|
// no image 14
|
||||||
|
CAL_NO_IMG_CAP_AREA,
|
||||||
|
CAL_NO_IMG_SET_0,
|
||||||
|
CAL_NO_IMG_03_1C,
|
||||||
|
CAL_NO_CHK_03_80,
|
||||||
|
CAL_NO_SET_03_80,
|
||||||
|
CAL_NO_IMG_14_BS_SET,
|
||||||
|
CAL_NO_IMG_14_BS_CHK_SET, // 0
|
||||||
|
CAL_NO_IMG_PRE_FIRST, // 1
|
||||||
|
CAL_NO_IMG_GET_8, // 2
|
||||||
|
CAL_NO_IMG_14_BS_JUMP, // 3
|
||||||
|
CAL_NO_IMG_14_BS_END, // 4
|
||||||
|
// no image 16
|
||||||
|
CAL_NO_IMG_16_BS_SET,
|
||||||
|
CAL_NO_IMG_16_BS_CHK_SET_15, // 0
|
||||||
|
CAL_NO_IMG_16_BS_SET_16, // 1
|
||||||
|
CAL_NO_IMG_PRE_FIRST, // 2
|
||||||
|
CAL_NO_IMG_GET_8, // 3
|
||||||
|
CAL_NO_IMG_16_BS_JUMP, // 4
|
||||||
|
CAL_NO_IMG_16_BS_END, // 5
|
||||||
|
// end
|
||||||
|
CAL_CONF_PKT,
|
||||||
|
CAL_CONF_PKT,
|
||||||
|
|
||||||
|
CAL_END,
|
||||||
|
};
|
||||||
1629
libfprint/drivers/egismoc/egismoc.c
Normal file
223
libfprint/drivers/egismoc/egismoc.h
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
|
||||||
|
* Originally authored 2023 by Joshua Grisham <josh@joshuagrisham.com>
|
||||||
|
*
|
||||||
|
* Portions of code and logic inspired from the elanmoc libfprint driver
|
||||||
|
* which is copyright (C) 2021 Elan Microelectronics Inc (see elanmoc.c)
|
||||||
|
*
|
||||||
|
* Based on original reverse-engineering work by Joshua Grisham. The protocol has
|
||||||
|
* been reverse-engineered from captures of the official Windows driver, and by
|
||||||
|
* testing commands on the sensor with a multiplatform Python prototype driver:
|
||||||
|
* https://github.com/joshuagrisham/galaxy-book2-pro-linux/tree/main/fingerprint/
|
||||||
|
*
|
||||||
|
* 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 (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpDevice)
|
||||||
|
|
||||||
|
#define EGISMOC_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
|
||||||
|
|
||||||
|
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
|
||||||
|
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
|
||||||
|
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
|
||||||
|
|
||||||
|
#define EGISMOC_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
#define EGISMOC_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
|
||||||
|
#define EGISMOC_EP_CMD_INTERRUPT_IN 0x83
|
||||||
|
|
||||||
|
#define EGISMOC_USB_CONTROL_TIMEOUT 5000
|
||||||
|
#define EGISMOC_USB_SEND_TIMEOUT 5000
|
||||||
|
#define EGISMOC_USB_RECV_TIMEOUT 5000
|
||||||
|
#define EGISMOC_USB_INTERRUPT_TIMEOUT 60000
|
||||||
|
|
||||||
|
#define EGISMOC_USB_IN_RECV_LENGTH 4096
|
||||||
|
#define EGISMOC_USB_INTERRUPT_IN_RECV_LENGTH 64
|
||||||
|
|
||||||
|
#define EGISMOC_MAX_ENROLL_STAGES_DEFAULT 10
|
||||||
|
#define EGISMOC_MAX_ENROLL_NUM 10
|
||||||
|
#define EGISMOC_FINGERPRINT_DATA_SIZE 32
|
||||||
|
#define EGISMOC_LIST_RESPONSE_PREFIX_SIZE 14
|
||||||
|
#define EGISMOC_LIST_RESPONSE_SUFFIX_SIZE 2
|
||||||
|
|
||||||
|
/* standard prefixes for all read/writes */
|
||||||
|
|
||||||
|
static guchar egismoc_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
|
||||||
|
static gsize egismoc_write_prefix_len = sizeof (egismoc_write_prefix) / sizeof (egismoc_write_prefix[0]);
|
||||||
|
|
||||||
|
static guchar egismoc_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
|
||||||
|
static gsize egismoc_read_prefix_len = sizeof (egismoc_read_prefix) / sizeof (egismoc_read_prefix[0]);
|
||||||
|
|
||||||
|
|
||||||
|
/* hard-coded command payloads */
|
||||||
|
|
||||||
|
static guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
|
||||||
|
static gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_version[0]);
|
||||||
|
static guchar rsp_fw_version_suffix[] = {0x90, 0x00};
|
||||||
|
static gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
|
||||||
|
|
||||||
|
static guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
|
||||||
|
static gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
|
||||||
|
static gsize cmd_sensor_reset_len = sizeof (cmd_sensor_reset) / sizeof (cmd_sensor_reset[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
|
||||||
|
static gsize cmd_sensor_check_len = sizeof (cmd_sensor_check) / sizeof (cmd_sensor_check[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
|
||||||
|
static gsize cmd_sensor_identify_len = sizeof (cmd_sensor_identify) / sizeof (cmd_sensor_identify[0]);
|
||||||
|
static guchar rsp_identify_match_suffix[] = {0x90, 0x00};
|
||||||
|
static gsize rsp_identify_match_suffix_len = sizeof (rsp_identify_match_suffix) / sizeof (rsp_identify_match_suffix[0]);
|
||||||
|
static guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
|
||||||
|
static gsize rsp_identify_notmatch_suffix_len = sizeof (rsp_identify_notmatch_suffix) / sizeof (rsp_identify_notmatch_suffix[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_enroll[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x00};
|
||||||
|
static gsize cmd_sensor_enroll_len = sizeof (cmd_sensor_enroll) / sizeof (cmd_sensor_enroll[0]);
|
||||||
|
|
||||||
|
static guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
|
||||||
|
static gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
|
||||||
|
static gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
|
||||||
|
|
||||||
|
static guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
|
||||||
|
static gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
|
||||||
|
static guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||||
|
static gsize rsp_read_success_prefix_len = sizeof (rsp_read_success_prefix) / sizeof (rsp_read_success_prefix[0]);
|
||||||
|
static guchar rsp_read_success_suffix[] = {0x90, 0x00};
|
||||||
|
static gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
|
||||||
|
static guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||||
|
static gsize rsp_read_offcenter_prefix_len = sizeof (rsp_read_offcenter_prefix) / sizeof (rsp_read_offcenter_prefix[0]);
|
||||||
|
static guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
|
||||||
|
static gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
|
||||||
|
static guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
|
||||||
|
static gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof (rsp_read_dirty_prefix[0]);
|
||||||
|
|
||||||
|
static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
|
||||||
|
static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
|
||||||
|
|
||||||
|
|
||||||
|
/* commands which exist on the device but are currently not used */
|
||||||
|
/*
|
||||||
|
static guchar cmd_sensor_cancel[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x04, 0x00};
|
||||||
|
static gsize cmd_sensor_cancel_len = sizeof(cmd_sensor_cancel) / sizeof(cmd_sensor_cancel[0]);
|
||||||
|
|
||||||
|
static guchar cmd_sensor_verify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x01, 0x00};
|
||||||
|
static gsize cmd_sensor_verify_len = sizeof(cmd_sensor_verify) / sizeof(cmd_sensor_verify[0]);
|
||||||
|
|
||||||
|
static guchar cmd_read_verify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x02, 0x00};
|
||||||
|
static gsize cmd_read_verify_len = sizeof(cmd_read_verify) / sizeof(cmd_read_verify[0]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* prefixes/suffixes and other things for dynamically created command payloads */
|
||||||
|
|
||||||
|
#define EGISMOC_CHECK_BYTES_LENGTH 2
|
||||||
|
#define EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
|
||||||
|
#define EGISMOC_CMD_CHECK_SEPARATOR_LENGTH 32
|
||||||
|
|
||||||
|
static guchar cmd_new_print_prefix[] = {0x00, 0x00, 0x00, 0x27, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x20};
|
||||||
|
static gsize cmd_new_print_prefix_len = sizeof (cmd_new_print_prefix) / sizeof (cmd_new_print_prefix[0]);
|
||||||
|
|
||||||
|
static guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
|
||||||
|
static gsize cmd_delete_prefix_len = sizeof (cmd_delete_prefix) / sizeof (cmd_delete_prefix[0]);
|
||||||
|
static guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
|
||||||
|
static gsize rsp_delete_success_prefix_len = sizeof (rsp_delete_success_prefix) / sizeof (rsp_delete_success_prefix[0]);
|
||||||
|
|
||||||
|
static guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
|
||||||
|
static gsize cmd_check_prefix_type1_len = sizeof (cmd_check_prefix_type1) / sizeof (cmd_check_prefix_type1[0]);
|
||||||
|
static guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
|
||||||
|
static gsize cmd_check_prefix_type2_len = sizeof (cmd_check_prefix_type2) / sizeof (cmd_check_prefix_type2[0]);
|
||||||
|
static guchar cmd_check_suffix[] = {0x00, 0x40};
|
||||||
|
static gsize cmd_check_suffix_len = sizeof (cmd_check_suffix) / sizeof (cmd_check_suffix[0]);
|
||||||
|
static guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
|
||||||
|
static gsize rsp_check_not_yet_enrolled_suffix_len = sizeof (rsp_check_not_yet_enrolled_suffix) / sizeof (rsp_check_not_yet_enrolled_suffix[0]);
|
||||||
|
|
||||||
|
|
||||||
|
/* SSM task states and various status enums */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_SEND,
|
||||||
|
CMD_GET,
|
||||||
|
CMD_STATES,
|
||||||
|
} CommandStates;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DEV_INIT_CONTROL1,
|
||||||
|
DEV_INIT_CONTROL2,
|
||||||
|
DEV_INIT_CONTROL3,
|
||||||
|
DEV_INIT_CONTROL4,
|
||||||
|
DEV_INIT_CONTROL5,
|
||||||
|
DEV_GET_FW_VERSION,
|
||||||
|
DEV_INIT_STATES,
|
||||||
|
} DeviceInitStates;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IDENTIFY_GET_ENROLLED_IDS,
|
||||||
|
IDENTIFY_CHECK_ENROLLED_NUM,
|
||||||
|
IDENTIFY_SENSOR_RESET,
|
||||||
|
IDENTIFY_SENSOR_IDENTIFY,
|
||||||
|
IDENTIFY_WAIT_FINGER,
|
||||||
|
IDENTIFY_SENSOR_CHECK,
|
||||||
|
IDENTIFY_CHECK,
|
||||||
|
IDENTIFY_COMPLETE_SENSOR_RESET,
|
||||||
|
IDENTIFY_COMPLETE,
|
||||||
|
IDENTIFY_STATES,
|
||||||
|
} IdentifyStates;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ENROLL_GET_ENROLLED_IDS,
|
||||||
|
ENROLL_CHECK_ENROLLED_NUM,
|
||||||
|
ENROLL_SENSOR_RESET,
|
||||||
|
ENROLL_SENSOR_ENROLL,
|
||||||
|
ENROLL_WAIT_FINGER,
|
||||||
|
ENROLL_SENSOR_CHECK,
|
||||||
|
ENROLL_CHECK,
|
||||||
|
ENROLL_START,
|
||||||
|
ENROLL_CAPTURE_SENSOR_RESET,
|
||||||
|
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
|
||||||
|
ENROLL_CAPTURE_WAIT_FINGER,
|
||||||
|
ENROLL_CAPTURE_READ_RESPONSE,
|
||||||
|
ENROLL_COMMIT_START,
|
||||||
|
ENROLL_COMMIT,
|
||||||
|
ENROLL_COMMIT_SENSOR_RESET,
|
||||||
|
ENROLL_COMPLETE,
|
||||||
|
ENROLL_STATES,
|
||||||
|
} EnrollStates;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ENROLL_STATUS_DEVICE_FULL,
|
||||||
|
ENROLL_STATUS_DUPLICATE,
|
||||||
|
ENROLL_STATUS_PARTIAL_OK,
|
||||||
|
ENROLL_STATUS_RETRY,
|
||||||
|
ENROLL_STATUS_COMPLETE,
|
||||||
|
} EnrollStatus;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LIST_GET_ENROLLED_IDS,
|
||||||
|
LIST_RETURN_ENROLLED_PRINTS,
|
||||||
|
LIST_STATES,
|
||||||
|
} ListStates;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DELETE_GET_ENROLLED_IDS,
|
||||||
|
DELETE_DELETE,
|
||||||
|
DELETE_STATES,
|
||||||
|
} DeleteStates;
|
||||||
1010
libfprint/drivers/elan.c
Normal file
235
libfprint/drivers/elan.h
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* Elan driver for libfprint
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Igor Filatov <ia.filatov@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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#define ELAN_VEND_ID 0x04f3
|
||||||
|
|
||||||
|
/* a default device type */
|
||||||
|
#define ELAN_ALL_DEV 0
|
||||||
|
|
||||||
|
/* devices with quirks */
|
||||||
|
#define ELAN_0907 (1 << 0)
|
||||||
|
#define ELAN_0C03 (1 << 1)
|
||||||
|
#define ELAN_0C42 (1 << 2)
|
||||||
|
|
||||||
|
/* devices which don't require frame rotation before assembling */
|
||||||
|
#define ELAN_NOT_ROTATED ELAN_0C03
|
||||||
|
|
||||||
|
/* min FW version that supports calibration */
|
||||||
|
#define ELAN_MIN_CALIBRATION_FW 0x0138
|
||||||
|
|
||||||
|
/* max difference between background image mean and calibration mean
|
||||||
|
* (the response value of get_calib_mean_cmd)*/
|
||||||
|
#define ELAN_CALIBRATION_MAX_DELTA 500
|
||||||
|
|
||||||
|
/* times to retry reading calibration status during one session
|
||||||
|
* generally prevents calibration from looping indefinitely */
|
||||||
|
#define ELAN_CALIBRATION_ATTEMPTS 10
|
||||||
|
|
||||||
|
/* min and max frames in a capture */
|
||||||
|
#define ELAN_MIN_FRAMES 7
|
||||||
|
#define ELAN_MAX_FRAMES 30
|
||||||
|
|
||||||
|
/* crop frames to this height to improve stitching */
|
||||||
|
#define ELAN_MAX_FRAME_HEIGHT 50
|
||||||
|
|
||||||
|
/* number of frames to drop at the end of capture because frames captured
|
||||||
|
* while the finger is being lifted can be bad */
|
||||||
|
#define ELAN_SKIP_LAST_FRAMES 2
|
||||||
|
|
||||||
|
#define ELAN_CMD_LEN 0x2
|
||||||
|
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
|
||||||
|
#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN)
|
||||||
|
|
||||||
|
/* used as response length to tell the driver to skip reading response */
|
||||||
|
#define ELAN_CMD_SKIP_READ 0
|
||||||
|
|
||||||
|
/* usual command timeout and timeout for when we need to check if the finger is
|
||||||
|
* still on the device */
|
||||||
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
||||||
|
FpImageDevice);
|
||||||
|
|
||||||
|
struct elan_cmd
|
||||||
|
{
|
||||||
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
|
int response_len;
|
||||||
|
int response_in;
|
||||||
|
unsigned short devices;
|
||||||
|
gboolean never_cancel;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_sensor_dim_cmd = {
|
||||||
|
.cmd = {0x00, 0x0c},
|
||||||
|
.response_len = 0x4,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_fw_ver_cmd = {
|
||||||
|
.cmd = {0x40, 0x19},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* unknown, returns 0x0 0x1 on 0907 */
|
||||||
|
static const struct elan_cmd activate_cmd_1 = {
|
||||||
|
.cmd = {0x40, 0x2a},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_0907,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_image_cmd = {
|
||||||
|
.cmd = {0x00, 0x09},
|
||||||
|
/* raw frame sizes are calculated from image dimensions reported by the
|
||||||
|
* device */
|
||||||
|
.response_len = -1,
|
||||||
|
.response_in = ELAN_EP_IMG_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd read_sensor_status_cmd = {
|
||||||
|
.cmd = {0x40, 0x13},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_calib_status_cmd = {
|
||||||
|
.cmd = {0x40, 0x23},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_calib_mean_cmd = {
|
||||||
|
.cmd = {0x40, 0x24},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd led_on_cmd = {
|
||||||
|
.cmd = {0x40, 0x31},
|
||||||
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* wait for finger
|
||||||
|
* subsequent read will not complete until finger is placed on the reader */
|
||||||
|
static const struct elan_cmd pre_scan_cmd = {
|
||||||
|
.cmd = {0x40, 0x3f},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* led off, stop waiting for finger */
|
||||||
|
static const struct elan_cmd stop_cmd = {
|
||||||
|
.cmd = {0x00, 0x0b},
|
||||||
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
.never_cancel = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const FpIdEntry elan_id_table[] = {
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c30, .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 = 0x0c33, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c4b, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
|
||||||
|
{.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},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void elan_cmd_done (FpiSsm *ssm);
|
||||||
|
static void elan_cmd_read (FpiSsm *ssm,
|
||||||
|
FpDevice *dev);
|
||||||
|
|
||||||
|
static void elan_calibrate (FpiDeviceElan *self);
|
||||||
|
static void elan_capture (FpiDeviceElan *self);
|
||||||
|
|
||||||
|
static void dev_change_state (FpImageDevice *dev,
|
||||||
|
FpiImageDeviceState state);
|
||||||
1180
libfprint/drivers/elanmoc/elanmoc.c
Normal file
196
libfprint/drivers/elanmoc/elanmoc.h
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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 max_moc_enroll_time;
|
||||||
|
int cancel_result;
|
||||||
|
int cmd_retry_cnt;
|
||||||
|
int list_index;
|
||||||
|
GPtrArray *list_result;
|
||||||
|
};
|
||||||